aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcmdhd
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/net/wireless/bcmdhd
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/net/wireless/bcmdhd')
-rw-r--r--drivers/net/wireless/bcmdhd/Kconfig79
-rw-r--r--drivers/net/wireless/bcmdhd/Makefile54
-rw-r--r--drivers/net/wireless/bcmdhd/aiutils.c675
-rw-r--r--drivers/net/wireless/bcmdhd/bcmevent.c125
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh.c690
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_linux.c741
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c1331
-rw-r--r--drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c350
-rw-r--r--drivers/net/wireless/bcmdhd/bcmutils.c1967
-rw-r--r--drivers/net/wireless/bcmdhd/bcmwifi.c274
-rw-r--r--drivers/net/wireless/bcmdhd/dhd.h733
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_bta.c335
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_bta.h39
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_bus.h99
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_cdc.c2530
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_common.c2306
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_custom_gpio.c293
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_dbg.h105
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux.c5080
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux_mon.c393
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_linux_sched.c39
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_proto.h105
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_sdio.c6289
-rw-r--r--drivers/net/wireless/bcmdhd/dhd_wlfc.h266
-rw-r--r--drivers/net/wireless/bcmdhd/dngl_stats.h43
-rw-r--r--drivers/net/wireless/bcmdhd/dngl_wlhdr.h40
-rw-r--r--drivers/net/wireless/bcmdhd/hndpmu.c222
-rw-r--r--drivers/net/wireless/bcmdhd/include/Makefile53
-rw-r--r--drivers/net/wireless/bcmdhd/include/aidmp.h377
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmcdc.h121
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmdefs.h196
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmdevs.h182
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmendian.h279
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmpcispi.h181
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmperf.h36
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdbus.h120
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdh.h211
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h122
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdpcm.h274
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdspi.h135
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmsdstd.h267
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmspi.h40
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmutils.h708
-rw-r--r--drivers/net/wireless/bcmdhd/include/bcmwifi.h165
-rw-r--r--drivers/net/wireless/bcmdhd/include/dhdioctl.h129
-rw-r--r--drivers/net/wireless/bcmdhd/include/epivers.h49
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndpmu.h34
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h88
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndrte_cons.h68
-rw-r--r--drivers/net/wireless/bcmdhd/include/hndsoc.h207
-rw-r--r--drivers/net/wireless/bcmdhd/include/htsf.h74
-rw-r--r--drivers/net/wireless/bcmdhd/include/linux_osl.h431
-rw-r--r--drivers/net/wireless/bcmdhd/include/linuxver.h593
-rw-r--r--drivers/net/wireless/bcmdhd/include/miniopt.h77
-rw-r--r--drivers/net/wireless/bcmdhd/include/msgtrace.h74
-rw-r--r--drivers/net/wireless/bcmdhd/include/osl.h66
-rw-r--r--drivers/net/wireless/bcmdhd/include/packed_section_end.h54
-rw-r--r--drivers/net/wireless/bcmdhd/include/packed_section_start.h61
-rw-r--r--drivers/net/wireless/bcmdhd/include/pcicfg.h52
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.11.h1731
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h45
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.11e.h131
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/802.1d.h49
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmeth.h83
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmevent.h312
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bcmip.h154
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h442
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/eapol.h173
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/ethernet.h162
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/p2p.h512
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/sdspi.h76
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/vlan.h70
-rw-r--r--drivers/net/wireless/bcmdhd/include/proto/wpa.h160
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbchipc.h1615
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbconfig.h276
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbhnddma.h327
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbpcmcia.h109
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbsdio.h166
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h293
-rw-r--r--drivers/net/wireless/bcmdhd/include/sbsocram.h186
-rw-r--r--drivers/net/wireless/bcmdhd/include/sdio.h611
-rw-r--r--drivers/net/wireless/bcmdhd/include/sdioh.h412
-rw-r--r--drivers/net/wireless/bcmdhd/include/sdiovar.h58
-rw-r--r--drivers/net/wireless/bcmdhd/include/siutils.h247
-rw-r--r--drivers/net/wireless/bcmdhd/include/trxhdr.h52
-rw-r--r--drivers/net/wireless/bcmdhd/include/typedefs.h309
-rw-r--r--drivers/net/wireless/bcmdhd/include/wlfc_proto.h198
-rw-r--r--drivers/net/wireless/bcmdhd/include/wlioctl.h2757
-rw-r--r--drivers/net/wireless/bcmdhd/linux_osl.c919
-rw-r--r--drivers/net/wireless/bcmdhd/sbutils.c992
-rw-r--r--drivers/net/wireless/bcmdhd/siutils.c1720
-rw-r--r--drivers/net/wireless/bcmdhd/siutils_priv.h235
-rw-r--r--drivers/net/wireless/bcmdhd/uamp_api.h176
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.c840
-rw-r--r--drivers/net/wireless/bcmdhd/wl_android.h57
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.c7330
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfg80211.h558
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.c1469
-rw-r--r--drivers/net/wireless/bcmdhd/wl_cfgp2p.h247
-rw-r--r--drivers/net/wireless/bcmdhd/wl_dbg.h49
-rw-r--r--drivers/net/wireless/bcmdhd/wl_iw.c8766
-rw-r--r--drivers/net/wireless/bcmdhd/wl_iw.h306
-rw-r--r--drivers/net/wireless/bcmdhd/wldev_common.c341
-rw-r--r--drivers/net/wireless/bcmdhd/wldev_common.h110
104 files changed, 66558 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig
new file mode 100644
index 00000000000..4c3461a67f4
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/Kconfig
@@ -0,0 +1,79 @@
1config BCMDHD
2 tristate "Broadcom 4329/30 wireless cards support"
3 depends on MMC
4 ---help---
5 This module adds support for wireless adapters based on
6 Broadcom 4329/30 chipset.
7
8 This driver uses the kernel's wireless extensions subsystem.
9
10 If you choose to build a module, it'll be called dhd. Say M if
11 unsure.
12
13config BCMDHD_FW_DIR
14 depends on BCMDHD
15 string "Firmware path"
16 default "/system/vendor/firmware"
17 ---help---
18 Path to the firmware file.
19
20config BCMDHD_NVRAM_DIR
21 depends on BCMDHD
22 string "NVRAM path"
23 default "/system/etc"
24 ---help---
25 Path to the calibration file.
26
27choice
28 prompt "Select API"
29 depends on BCMDHD
30 default BCMDHD_NOAPI
31
32config BCMDHD_WEXT
33 bool "Enable WEXT support"
34 select WIRELESS_EXT
35 select WEXT_PRIV
36 help
37 Enables WEXT support
38
39config BCMDHD_CFG80211
40 bool "Enable CFG80211 support"
41 depends on CFG80211
42 help
43 Enables CFG80211 support
44
45config BCMDHD_NOAPI
46 bool "No wireless API"
47 help
48 No wireless API is needed
49
50endchoice
51
52config BCMDHD_WIFI_CONTROL_FUNC
53 bool "Use bcmdhd_wlan device"
54 depends on BCMDHD
55 default n
56 ---help---
57 Use this option to get various parameters from architecture specific
58 bcmdhd_wlan platform device. Say n if unsure.
59
60config BCMDHD_HW_OOB
61 bool "Use out of band interrupt"
62 depends on BCMDHD
63 default n
64 ---help---
65 Use out of band interrupt for card interrupt and wake on wireless.
66
67config BCMDHD_CSCAN_ENABLE
68 bool "Enable Combo Scan"
69 depends on BCMDHD
70 default n
71 ---help---
72 Enable Combo Scan
73
74config BCMDHD_INSMOD_NO_FW_LOAD
75 bool "Enable delayed firmware load"
76 depends on BCMDHD
77 default n
78 ---help---
79 Enable delayes firmware
diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile
new file mode 100644
index 00000000000..918e59fb495
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/Makefile
@@ -0,0 +1,54 @@
1# bcmdhd
2DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \
3 -DBCMDONGLEHOST -DUNRELEASEDCHIP -DBCMDMA32 -DWLBTAMP -DBCMFILEIMAGE \
4 -DDHDTHREAD -DDHD_GPL -DDHD_SCHED -DDHD_DEBUG -DSDTEST -DBDC -DTOE \
5 -DDHD_BCMEVENTS -DSHOW_EVENTS -DDONGLEOVERLAYS -DBCMDBG \
6 -DCUSTOMER_HW2 \
7 -DMMC_SDIO_ABORT -DBCMSDIO -DBCMLXSDMMC -DBCMPLATFORM_BUS -DWLP2P \
8 -DNEW_COMPAT_WIRELESS -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \
9 -DKEEP_ALIVE -DPKT_FILTER_SUPPORT \
10 -DEMBEDDED_PLATFORM \
11 -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include
12
13ifeq ($(CONFIG_BCMDHD_WIFI_CONTROL_FUNC),y)
14DHDCFLAGS += -DCONFIG_WIFI_CONTROL_FUNC
15else
16DHDCFLAGS += -DCUSTOM_OOB_GPIO_NUM=2
17endif
18
19ifeq ($(CONFIG_BCMDHD_HW_OOB),y)
20DHDCFLAGS += -DHW_OOB -DOOB_INTR_ONLY
21else
22DHDCFLAGS += -DSDIO_ISR_THREAD
23endif
24
25ifeq ($(CONFIG_BCMDHD_CSCAN_ENABLE),y)
26DHDCFLAGS += -DCSCAN -DPNO_SUPPORT
27endif
28
29ifeq ($(CONFIG_BCMDHD_INSMOD_NO_FW_LOAD),y)
30DHDCFLAGS += -DENABLE_INSMOD_NO_FW_LOAD
31endif
32
33DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \
34 dhd_linux_sched.o bcmwifi.o dhd_sdio.o bcmevent.o dhd_bta.o hndpmu.o \
35 bcmsdh.o dhd_cdc.o bcmsdh_linux.o dhd_common.o linux_osl.o \
36 bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o
37
38obj-$(CONFIG_BCMDHD) += bcmdhd.o
39bcmdhd-objs += $(DHDOFILES)
40
41ifeq ($(CONFIG_BCMDHD_WEXT),y)
42bcmdhd-objs += wl_iw.o
43DHDCFLAGS += -DSOFTAP
44endif
45
46ifeq ($(CONFIG_BCMDHD_CFG80211),y)
47bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o dhd_linux_mon.o
48DHDCFLAGS += -DWL_CFG80211
49endif
50
51EXTRA_CFLAGS = $(DHDCFLAGS)
52ifeq ($(CONFIG_BCMDHD),m)
53EXTRA_LDFLAGS += --strip-debug
54endif
diff --git a/drivers/net/wireless/bcmdhd/aiutils.c b/drivers/net/wireless/bcmdhd/aiutils.c
new file mode 100644
index 00000000000..059df890792
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/aiutils.c
@@ -0,0 +1,675 @@
1/*
2 * Misc utility routines for accessing chip-specific features
3 * of the SiliconBackplane-based Broadcom chips.
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: aiutils.c,v 1.26.2.1 2010-03-09 18:41:21 Exp $
26 */
27
28
29#include <typedefs.h>
30#include <bcmdefs.h>
31#include <osl.h>
32#include <bcmutils.h>
33#include <siutils.h>
34#include <hndsoc.h>
35#include <sbchipc.h>
36#include <pcicfg.h>
37
38#include "siutils_priv.h"
39
40
41
42
43
44static uint32
45get_erom_ent(si_t *sih, uint32 **eromptr, uint32 mask, uint32 match)
46{
47 uint32 ent;
48 uint inv = 0, nom = 0;
49
50 while (TRUE) {
51 ent = R_REG(si_osh(sih), *eromptr);
52 (*eromptr)++;
53
54 if (mask == 0)
55 break;
56
57 if ((ent & ER_VALID) == 0) {
58 inv++;
59 continue;
60 }
61
62 if (ent == (ER_END | ER_VALID))
63 break;
64
65 if ((ent & mask) == match)
66 break;
67
68 nom++;
69 }
70
71 SI_VMSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent));
72 if (inv + nom) {
73 SI_VMSG((" after %d invalid and %d non-matching entries\n", inv, nom));
74 }
75 return ent;
76}
77
78static uint32
79get_asd(si_t *sih, uint32 **eromptr, uint sp, uint ad, uint st, uint32 *addrl, uint32 *addrh,
80 uint32 *sizel, uint32 *sizeh)
81{
82 uint32 asd, sz, szd;
83
84 asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID);
85 if (((asd & ER_TAG1) != ER_ADD) ||
86 (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) ||
87 ((asd & AD_ST_MASK) != st)) {
88
89 (*eromptr)--;
90 return 0;
91 }
92 *addrl = asd & AD_ADDR_MASK;
93 if (asd & AD_AG32)
94 *addrh = get_erom_ent(sih, eromptr, 0, 0);
95 else
96 *addrh = 0;
97 *sizeh = 0;
98 sz = asd & AD_SZ_MASK;
99 if (sz == AD_SZ_SZD) {
100 szd = get_erom_ent(sih, eromptr, 0, 0);
101 *sizel = szd & SD_SZ_MASK;
102 if (szd & SD_SG32)
103 *sizeh = get_erom_ent(sih, eromptr, 0, 0);
104 } else
105 *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT);
106
107 SI_VMSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n",
108 sp, ad, st, *sizeh, *sizel, *addrh, *addrl));
109
110 return asd;
111}
112
113static void
114ai_hwfixup(si_info_t *sii)
115{
116}
117
118
119void
120ai_scan(si_t *sih, void *regs, uint devid)
121{
122 si_info_t *sii = SI_INFO(sih);
123 chipcregs_t *cc = (chipcregs_t *)regs;
124 uint32 erombase, *eromptr, *eromlim;
125
126 erombase = R_REG(sii->osh, &cc->eromptr);
127
128 switch (BUSTYPE(sih->bustype)) {
129 case SI_BUS:
130 eromptr = (uint32 *)REG_MAP(erombase, SI_CORE_SIZE);
131 break;
132
133 case PCI_BUS:
134
135 sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE);
136
137
138 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase);
139 eromptr = regs;
140 break;
141
142 case SPI_BUS:
143 case SDIO_BUS:
144 eromptr = (uint32 *)(uintptr)erombase;
145 break;
146
147 case PCMCIA_BUS:
148 default:
149 SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype));
150 ASSERT(0);
151 return;
152 }
153 eromlim = eromptr + (ER_REMAPCONTROL / sizeof(uint32));
154
155 SI_VMSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%p, eromlim = 0x%p\n",
156 regs, erombase, eromptr, eromlim));
157 while (eromptr < eromlim) {
158 uint32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp;
159 uint32 mpd, asd, addrl, addrh, sizel, sizeh;
160 uint32 *base;
161 uint i, j, idx;
162 bool br;
163
164 br = FALSE;
165
166
167 cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI);
168 if (cia == (ER_END | ER_VALID)) {
169 SI_VMSG(("Found END of erom after %d cores\n", sii->numcores));
170 ai_hwfixup(sii);
171 return;
172 }
173 base = eromptr - 1;
174 cib = get_erom_ent(sih, &eromptr, 0, 0);
175
176 if ((cib & ER_TAG) != ER_CI) {
177 SI_ERROR(("CIA not followed by CIB\n"));
178 goto error;
179 }
180
181 cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT;
182 mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT;
183 crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
184 nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT;
185 nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT;
186 nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT;
187 nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT;
188
189 SI_VMSG(("Found component 0x%04x/0x%04x rev %d at erom addr 0x%p, with nmw = %d, "
190 "nsw = %d, nmp = %d & nsp = %d\n",
191 mfg, cid, crev, base, nmw, nsw, nmp, nsp));
192
193 if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0))
194 continue;
195 if ((nmw + nsw == 0)) {
196
197 if (cid == OOB_ROUTER_CORE_ID) {
198 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE,
199 &addrl, &addrh, &sizel, &sizeh);
200 if (asd != 0) {
201 sii->oob_router = addrl;
202 }
203 }
204 continue;
205 }
206
207 idx = sii->numcores;
208
209 sii->cia[idx] = cia;
210 sii->cib[idx] = cib;
211 sii->coreid[idx] = cid;
212
213 for (i = 0; i < nmp; i++) {
214 mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID);
215 if ((mpd & ER_TAG) != ER_MP) {
216 SI_ERROR(("Not enough MP entries for component 0x%x\n", cid));
217 goto error;
218 }
219 SI_VMSG((" Master port %d, mp: %d id: %d\n", i,
220 (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT,
221 (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT));
222 }
223
224
225 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh);
226 if (asd == 0) {
227
228 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh,
229 &sizel, &sizeh);
230 if (asd != 0)
231 br = TRUE;
232 else
233 if ((addrh != 0) || (sizeh != 0) || (sizel != SI_CORE_SIZE)) {
234 SI_ERROR(("First Slave ASD for core 0x%04x malformed "
235 "(0x%08x)\n", cid, asd));
236 goto error;
237 }
238 }
239 sii->coresba[idx] = addrl;
240 sii->coresba_size[idx] = sizel;
241
242 j = 1;
243 do {
244 asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh,
245 &sizel, &sizeh);
246 if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) {
247 sii->coresba2[idx] = addrl;
248 sii->coresba2_size[idx] = sizel;
249 }
250 j++;
251 } while (asd != 0);
252
253
254 for (i = 1; i < nsp; i++) {
255 j = 0;
256 do {
257 asd = get_asd(sih, &eromptr, i, j++, AD_ST_SLAVE, &addrl, &addrh,
258 &sizel, &sizeh);
259 } while (asd != 0);
260 if (j == 0) {
261 SI_ERROR((" SP %d has no address descriptors\n", i));
262 goto error;
263 }
264 }
265
266
267 for (i = 0; i < nmw; i++) {
268 asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh,
269 &sizel, &sizeh);
270 if (asd == 0) {
271 SI_ERROR(("Missing descriptor for MW %d\n", i));
272 goto error;
273 }
274 if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
275 SI_ERROR(("Master wrapper %d is not 4KB\n", i));
276 goto error;
277 }
278 if (i == 0)
279 sii->wrapba[idx] = addrl;
280 }
281
282
283 for (i = 0; i < nsw; i++) {
284 uint fwp = (nsp == 1) ? 0 : 1;
285 asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh,
286 &sizel, &sizeh);
287 if (asd == 0) {
288 SI_ERROR(("Missing descriptor for SW %d\n", i));
289 goto error;
290 }
291 if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
292 SI_ERROR(("Slave wrapper %d is not 4KB\n", i));
293 goto error;
294 }
295 if ((nmw == 0) && (i == 0))
296 sii->wrapba[idx] = addrl;
297 }
298
299
300 if (br)
301 continue;
302
303
304 sii->numcores++;
305 }
306
307 SI_ERROR(("Reached end of erom without finding END"));
308
309error:
310 sii->numcores = 0;
311 return;
312}
313
314
315void *
316ai_setcoreidx(si_t *sih, uint coreidx)
317{
318 si_info_t *sii = SI_INFO(sih);
319 uint32 addr = sii->coresba[coreidx];
320 uint32 wrap = sii->wrapba[coreidx];
321 void *regs;
322
323 if (coreidx >= sii->numcores)
324 return (NULL);
325
326
327 ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg));
328
329 switch (BUSTYPE(sih->bustype)) {
330 case SI_BUS:
331
332 if (!sii->regs[coreidx]) {
333 sii->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE);
334 ASSERT(GOODREGS(sii->regs[coreidx]));
335 }
336 sii->curmap = regs = sii->regs[coreidx];
337 if (!sii->wrappers[coreidx]) {
338 sii->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE);
339 ASSERT(GOODREGS(sii->wrappers[coreidx]));
340 }
341 sii->curwrap = sii->wrappers[coreidx];
342 break;
343
344
345 case SPI_BUS:
346 case SDIO_BUS:
347 sii->curmap = regs = (void *)((uintptr)addr);
348 sii->curwrap = (void *)((uintptr)wrap);
349 break;
350
351 case PCMCIA_BUS:
352 default:
353 ASSERT(0);
354 regs = NULL;
355 break;
356 }
357
358 sii->curmap = regs;
359 sii->curidx = coreidx;
360
361 return regs;
362}
363
364
365int
366ai_numaddrspaces(si_t *sih)
367{
368 return 2;
369}
370
371
372uint32
373ai_addrspace(si_t *sih, uint asidx)
374{
375 si_info_t *sii;
376 uint cidx;
377
378 sii = SI_INFO(sih);
379 cidx = sii->curidx;
380
381 if (asidx == 0)
382 return sii->coresba[cidx];
383 else if (asidx == 1)
384 return sii->coresba2[cidx];
385 else {
386 SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n",
387 __FUNCTION__, asidx));
388 return 0;
389 }
390}
391
392
393uint32
394ai_addrspacesize(si_t *sih, uint asidx)
395{
396 si_info_t *sii;
397 uint cidx;
398
399 sii = SI_INFO(sih);
400 cidx = sii->curidx;
401
402 if (asidx == 0)
403 return sii->coresba_size[cidx];
404 else if (asidx == 1)
405 return sii->coresba2_size[cidx];
406 else {
407 SI_ERROR(("%s: Need to parse the erom again to find addr space %d\n",
408 __FUNCTION__, asidx));
409 return 0;
410 }
411}
412
413uint
414ai_flag(si_t *sih)
415{
416 si_info_t *sii;
417 aidmp_t *ai;
418
419 sii = SI_INFO(sih);
420 ai = sii->curwrap;
421
422 return (R_REG(sii->osh, &ai->oobselouta30) & 0x1f);
423}
424
425void
426ai_setint(si_t *sih, int siflag)
427{
428}
429
430uint
431ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val)
432{
433 si_info_t *sii = SI_INFO(sih);
434 uint32 *map = (uint32 *) sii->curwrap;
435
436 if (mask || val) {
437 uint32 w = R_REG(sii->osh, map+(offset/4));
438 w &= ~mask;
439 w |= val;
440 W_REG(sii->osh, map+(offset/4), val);
441 }
442
443 return (R_REG(sii->osh, map+(offset/4)));
444}
445
446uint
447ai_corevendor(si_t *sih)
448{
449 si_info_t *sii;
450 uint32 cia;
451
452 sii = SI_INFO(sih);
453 cia = sii->cia[sii->curidx];
454 return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT);
455}
456
457uint
458ai_corerev(si_t *sih)
459{
460 si_info_t *sii;
461 uint32 cib;
462
463 sii = SI_INFO(sih);
464 cib = sii->cib[sii->curidx];
465 return ((cib & CIB_REV_MASK) >> CIB_REV_SHIFT);
466}
467
468bool
469ai_iscoreup(si_t *sih)
470{
471 si_info_t *sii;
472 aidmp_t *ai;
473
474 sii = SI_INFO(sih);
475 ai = sii->curwrap;
476
477 return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) &&
478 ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0));
479}
480
481
482uint
483ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
484{
485 uint origidx = 0;
486 uint32 *r = NULL;
487 uint w;
488 uint intr_val = 0;
489 bool fast = FALSE;
490 si_info_t *sii;
491
492 sii = SI_INFO(sih);
493
494 ASSERT(GOODIDX(coreidx));
495 ASSERT(regoff < SI_CORE_SIZE);
496 ASSERT((val & ~mask) == 0);
497
498 if (coreidx >= SI_MAXCORES)
499 return 0;
500
501 if (BUSTYPE(sih->bustype) == SI_BUS) {
502
503 fast = TRUE;
504
505 if (!sii->regs[coreidx]) {
506 sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx],
507 SI_CORE_SIZE);
508 ASSERT(GOODREGS(sii->regs[coreidx]));
509 }
510 r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff);
511 } else if (BUSTYPE(sih->bustype) == PCI_BUS) {
512
513
514 if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
515
516
517 fast = TRUE;
518 r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff);
519 } else if (sii->pub.buscoreidx == coreidx) {
520
521 fast = TRUE;
522 if (SI_FAST(sii))
523 r = (uint32 *)((char *)sii->curmap +
524 PCI_16KB0_PCIREGS_OFFSET + regoff);
525 else
526 r = (uint32 *)((char *)sii->curmap +
527 ((regoff >= SBCONFIGOFF) ?
528 PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
529 regoff);
530 }
531 }
532
533 if (!fast) {
534 INTR_OFF(sii, intr_val);
535
536
537 origidx = si_coreidx(&sii->pub);
538
539
540 r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff);
541 }
542 ASSERT(r != NULL);
543
544
545 if (mask || val) {
546 w = (R_REG(sii->osh, r) & ~mask) | val;
547 W_REG(sii->osh, r, w);
548 }
549
550
551 w = R_REG(sii->osh, r);
552
553 if (!fast) {
554
555 if (origidx != coreidx)
556 ai_setcoreidx(&sii->pub, origidx);
557
558 INTR_RESTORE(sii, intr_val);
559 }
560
561 return (w);
562}
563
564void
565ai_core_disable(si_t *sih, uint32 bits)
566{
567 si_info_t *sii;
568 volatile uint32 dummy;
569 aidmp_t *ai;
570
571 sii = SI_INFO(sih);
572
573 ASSERT(GOODREGS(sii->curwrap));
574 ai = sii->curwrap;
575
576
577 if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET)
578 return;
579
580 W_REG(sii->osh, &ai->ioctrl, bits);
581 dummy = R_REG(sii->osh, &ai->ioctrl);
582 OSL_DELAY(10);
583
584 W_REG(sii->osh, &ai->resetctrl, AIRC_RESET);
585 OSL_DELAY(1);
586}
587
588
589void
590ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
591{
592 si_info_t *sii;
593 aidmp_t *ai;
594 volatile uint32 dummy;
595
596 sii = SI_INFO(sih);
597 ASSERT(GOODREGS(sii->curwrap));
598 ai = sii->curwrap;
599
600
601 ai_core_disable(sih, (bits | resetbits));
602
603
604 W_REG(sii->osh, &ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN));
605 dummy = R_REG(sii->osh, &ai->ioctrl);
606 W_REG(sii->osh, &ai->resetctrl, 0);
607 OSL_DELAY(1);
608
609 W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN));
610 dummy = R_REG(sii->osh, &ai->ioctrl);
611 OSL_DELAY(1);
612}
613
614
615void
616ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
617{
618 si_info_t *sii;
619 aidmp_t *ai;
620 uint32 w;
621
622 sii = SI_INFO(sih);
623 ASSERT(GOODREGS(sii->curwrap));
624 ai = sii->curwrap;
625
626 ASSERT((val & ~mask) == 0);
627
628 if (mask || val) {
629 w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val);
630 W_REG(sii->osh, &ai->ioctrl, w);
631 }
632}
633
634uint32
635ai_core_cflags(si_t *sih, uint32 mask, uint32 val)
636{
637 si_info_t *sii;
638 aidmp_t *ai;
639 uint32 w;
640
641 sii = SI_INFO(sih);
642 ASSERT(GOODREGS(sii->curwrap));
643 ai = sii->curwrap;
644
645 ASSERT((val & ~mask) == 0);
646
647 if (mask || val) {
648 w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val);
649 W_REG(sii->osh, &ai->ioctrl, w);
650 }
651
652 return R_REG(sii->osh, &ai->ioctrl);
653}
654
655uint32
656ai_core_sflags(si_t *sih, uint32 mask, uint32 val)
657{
658 si_info_t *sii;
659 aidmp_t *ai;
660 uint32 w;
661
662 sii = SI_INFO(sih);
663 ASSERT(GOODREGS(sii->curwrap));
664 ai = sii->curwrap;
665
666 ASSERT((val & ~mask) == 0);
667 ASSERT((mask & ~SISF_CORE_BITS) == 0);
668
669 if (mask || val) {
670 w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val);
671 W_REG(sii->osh, &ai->iostatus, w);
672 }
673
674 return R_REG(sii->osh, &ai->iostatus);
675}
diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c
new file mode 100644
index 00000000000..24581ddd353
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmevent.c
@@ -0,0 +1,125 @@
1/*
2 * bcmevent read-only data shared by kernel or app layers
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 * $Id: bcmevent.c,v 1.8.2.7 2011-02-01 06:23:39 Exp $
24 */
25
26#include <typedefs.h>
27#include <bcmutils.h>
28#include <proto/ethernet.h>
29#include <proto/bcmeth.h>
30#include <proto/bcmevent.h>
31
32#if WLC_E_LAST != 85
33#error "You need to add an entry to bcmevent_names[] for the new event"
34#endif
35
36const bcmevent_name_t bcmevent_names[] = {
37 { WLC_E_SET_SSID, "SET_SSID" },
38 { WLC_E_JOIN, "JOIN" },
39 { WLC_E_START, "START" },
40 { WLC_E_AUTH, "AUTH" },
41 { WLC_E_AUTH_IND, "AUTH_IND" },
42 { WLC_E_DEAUTH, "DEAUTH" },
43 { WLC_E_DEAUTH_IND, "DEAUTH_IND" },
44 { WLC_E_ASSOC, "ASSOC" },
45 { WLC_E_ASSOC_IND, "ASSOC_IND" },
46 { WLC_E_REASSOC, "REASSOC" },
47 { WLC_E_REASSOC_IND, "REASSOC_IND" },
48 { WLC_E_DISASSOC, "DISASSOC" },
49 { WLC_E_DISASSOC_IND, "DISASSOC_IND" },
50 { WLC_E_QUIET_START, "START_QUIET" },
51 { WLC_E_QUIET_END, "END_QUIET" },
52 { WLC_E_BEACON_RX, "BEACON_RX" },
53 { WLC_E_LINK, "LINK" },
54 { WLC_E_MIC_ERROR, "MIC_ERROR" },
55 { WLC_E_NDIS_LINK, "NDIS_LINK" },
56 { WLC_E_ROAM, "ROAM" },
57 { WLC_E_TXFAIL, "TXFAIL" },
58 { WLC_E_PMKID_CACHE, "PMKID_CACHE" },
59 { WLC_E_RETROGRADE_TSF, "RETROGRADE_TSF" },
60 { WLC_E_PRUNE, "PRUNE" },
61 { WLC_E_AUTOAUTH, "AUTOAUTH" },
62 { WLC_E_EAPOL_MSG, "EAPOL_MSG" },
63 { WLC_E_SCAN_COMPLETE, "SCAN_COMPLETE" },
64 { WLC_E_ADDTS_IND, "ADDTS_IND" },
65 { WLC_E_DELTS_IND, "DELTS_IND" },
66 { WLC_E_BCNSENT_IND, "BCNSENT_IND" },
67 { WLC_E_BCNRX_MSG, "BCNRX_MSG" },
68 { WLC_E_BCNLOST_MSG, "BCNLOST_IND" },
69 { WLC_E_ROAM_PREP, "ROAM_PREP" },
70 { WLC_E_PFN_NET_FOUND, "PFNFOUND_IND" },
71 { WLC_E_PFN_NET_LOST, "PFNLOST_IND" },
72#if defined(IBSS_PEER_DISCOVERY_EVENT)
73 { WLC_E_IBSS_ASSOC, "IBSS_ASSOC" },
74#endif /* defined(IBSS_PEER_DISCOVERY_EVENT) */
75 { WLC_E_RADIO, "RADIO" },
76 { WLC_E_PSM_WATCHDOG, "PSM_WATCHDOG" },
77 { WLC_E_PROBREQ_MSG, "PROBE_REQ_MSG" },
78 { WLC_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND" },
79 { WLC_E_PSK_SUP, "PSK_SUP" },
80 { WLC_E_COUNTRY_CODE_CHANGED, "CNTRYCODE_IND" },
81 { WLC_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME" },
82 { WLC_E_ICV_ERROR, "ICV_ERROR" },
83 { WLC_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR" },
84 { WLC_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR" },
85 { WLC_E_TRACE, "TRACE" },
86 { WLC_E_BTA_HCI_EVENT, "BTA_HCI_EVENT" },
87 { WLC_E_IF, "IF" },
88#ifdef WLP2P
89 { WLC_E_P2P_DISC_LISTEN_COMPLETE, "WLC_E_P2P_DISC_LISTEN_COMPLETE" },
90#endif
91 { WLC_E_RSSI, "RSSI" },
92 { WLC_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE" },
93 { WLC_E_EXTLOG_MSG, "EXTERNAL LOG MESSAGE" },
94#ifdef WIFI_ACT_FRAME
95 { WLC_E_ACTION_FRAME, "ACTION_FRAME" },
96 { WLC_E_ACTION_FRAME_RX, "ACTION_FRAME_RX" },
97 { WLC_E_ACTION_FRAME_COMPLETE, "ACTION_FRAME_COMPLETE" },
98#endif
99 { WLC_E_ESCAN_RESULT, "WLC_E_ESCAN_RESULT" },
100 { WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "WLC_E_AF_OFF_CHAN_COMPLETE" },
101#ifdef WLP2P
102 { WLC_E_PROBRESP_MSG, "PROBE_RESP_MSG" },
103 { WLC_E_P2P_PROBREQ_MSG, "P2P PROBE_REQ_MSG" },
104#endif
105#ifdef PROP_TXSTATUS
106 { WLC_E_FIFO_CREDIT_MAP, "FIFO_CREDIT_MAP" },
107#endif
108 { WLC_E_WAKE_EVENT, "WAKE_EVENT" },
109 { WLC_E_DCS_REQUEST, "DCS_REQUEST" },
110 { WLC_E_RM_COMPLETE, "RM_COMPLETE" },
111#ifdef WLMEDIA_HTSF
112 { WLC_E_HTSFSYNC, "HTSF_SYNC_EVENT" },
113#endif
114 { WLC_E_OVERLAY_REQ, "OVERLAY_REQ_EVENT" },
115 { WLC_E_CSA_COMPLETE_IND, "WLC_E_CSA_COMPLETE_IND" },
116 { WLC_E_EXCESS_PM_WAKE_EVENT, "EXCESS_PM_WAKE_EVENT" },
117 { WLC_E_PFN_SCAN_NONE, "PFN_SCAN_NONE" },
118 { WLC_E_PFN_SCAN_ALLGONE, "PFN_SCAN_ALLGONE" },
119#ifdef SOFTAP
120 { WLC_E_GTK_PLUMBED, "GTK_PLUMBED" }
121#endif
122};
123
124
125const int bcmevent_names_size = ARRAYSIZE(bcmevent_names);
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh.c b/drivers/net/wireless/bcmdhd/bcmsdh.c
new file mode 100644
index 00000000000..918c8e648f1
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmsdh.c
@@ -0,0 +1,690 @@
1/*
2 * BCMSDH interface glue
3 * implement bcmsdh API for SDIOH driver
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: bcmsdh.c 275784 2011-08-04 22:41:49Z $
26 */
27
28/**
29 * @file bcmsdh.c
30 */
31
32/* ****************** BCMSDH Interface Functions *************************** */
33
34#include <typedefs.h>
35#include <bcmdevs.h>
36#include <bcmendian.h>
37#include <bcmutils.h>
38#include <hndsoc.h>
39#include <siutils.h>
40#include <osl.h>
41
42#include <bcmsdh.h> /* BRCM API for SDIO clients (such as wl, dhd) */
43#include <bcmsdbus.h> /* common SDIO/controller interface */
44#include <sbsdio.h> /* SDIO device core hardware definitions. */
45
46#include <sdio.h> /* SDIO Device and Protocol Specs */
47
48#define SDIOH_API_ACCESS_RETRY_LIMIT 2
49const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL;
50
51/**
52 * BCMSDH API context
53 */
54struct bcmsdh_info
55{
56 bool init_success; /* underlying driver successfully attached */
57 void *sdioh; /* handler for sdioh */
58 uint32 vendevid; /* Target Vendor and Device ID on SD bus */
59 osl_t *osh;
60 bool regfail; /* Save status of last reg_read/reg_write call */
61 uint32 sbwad; /* Save backplane window address */
62};
63/* local copy of bcm sd handler */
64bcmsdh_info_t * l_bcmsdh = NULL;
65
66#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
67extern int
68sdioh_enable_hw_oob_intr(void *sdioh, bool enable);
69
70void
71bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable)
72{
73 sdioh_enable_hw_oob_intr(sdh->sdioh, enable);
74}
75#endif
76
77/* Attach BCMSDH layer to SDIO Host Controller Driver
78 *
79 * @param osh OSL Handle.
80 * @param cfghdl Configuration Handle.
81 * @param regsva Virtual address of controller registers.
82 * @param irq Interrupt number of SDIO controller.
83 *
84 * @return bcmsdh_info_t Handle to BCMSDH context.
85 */
86bcmsdh_info_t *
87bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq)
88{
89 bcmsdh_info_t *bcmsdh;
90
91 if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) {
92 BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
93 return NULL;
94 }
95 bzero((char *)bcmsdh, sizeof(bcmsdh_info_t));
96
97 /* save the handler locally */
98 l_bcmsdh = bcmsdh;
99
100 if (!(bcmsdh->sdioh = sdioh_attach(osh, cfghdl, irq))) {
101 bcmsdh_detach(osh, bcmsdh);
102 return NULL;
103 }
104
105 bcmsdh->osh = osh;
106 bcmsdh->init_success = TRUE;
107
108 *regsva = (uint32 *)SI_ENUM_BASE;
109
110 /* Report the BAR, to fix if needed */
111 bcmsdh->sbwad = SI_ENUM_BASE;
112 return bcmsdh;
113}
114
115int
116bcmsdh_detach(osl_t *osh, void *sdh)
117{
118 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
119
120 if (bcmsdh != NULL) {
121 if (bcmsdh->sdioh) {
122 sdioh_detach(osh, bcmsdh->sdioh);
123 bcmsdh->sdioh = NULL;
124 }
125 MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t));
126 }
127
128 l_bcmsdh = NULL;
129 return 0;
130}
131
132int
133bcmsdh_iovar_op(void *sdh, const char *name,
134 void *params, int plen, void *arg, int len, bool set)
135{
136 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
137 return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set);
138}
139
140bool
141bcmsdh_intr_query(void *sdh)
142{
143 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
144 SDIOH_API_RC status;
145 bool on;
146
147 ASSERT(bcmsdh);
148 status = sdioh_interrupt_query(bcmsdh->sdioh, &on);
149 if (SDIOH_API_SUCCESS(status))
150 return FALSE;
151 else
152 return on;
153}
154
155int
156bcmsdh_intr_enable(void *sdh)
157{
158 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
159 SDIOH_API_RC status;
160 ASSERT(bcmsdh);
161
162 status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE);
163 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
164}
165
166int
167bcmsdh_intr_disable(void *sdh)
168{
169 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
170 SDIOH_API_RC status;
171 ASSERT(bcmsdh);
172
173 status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE);
174 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
175}
176
177int
178bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
179{
180 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
181 SDIOH_API_RC status;
182 ASSERT(bcmsdh);
183
184 status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh);
185 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
186}
187
188int
189bcmsdh_intr_dereg(void *sdh)
190{
191 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
192 SDIOH_API_RC status;
193 ASSERT(bcmsdh);
194
195 status = sdioh_interrupt_deregister(bcmsdh->sdioh);
196 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
197}
198
199#if defined(DHD_DEBUG)
200bool
201bcmsdh_intr_pending(void *sdh)
202{
203 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
204
205 ASSERT(sdh);
206 return sdioh_interrupt_pending(bcmsdh->sdioh);
207}
208#endif
209
210
211int
212bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
213{
214 ASSERT(sdh);
215
216 /* don't support yet */
217 return BCME_UNSUPPORTED;
218}
219
220/**
221 * Read from SDIO Configuration Space
222 * @param sdh SDIO Host context.
223 * @param func_num Function number to read from.
224 * @param addr Address to read from.
225 * @param err Error return.
226 * @return value read from SDIO configuration space.
227 */
228uint8
229bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err)
230{
231 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
232 SDIOH_API_RC status;
233#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
234 int32 retry = 0;
235#endif
236 uint8 data = 0;
237
238 if (!bcmsdh)
239 bcmsdh = l_bcmsdh;
240
241 ASSERT(bcmsdh->init_success);
242
243#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
244 do {
245 if (retry) /* wait for 1 ms till bus get settled down */
246 OSL_DELAY(1000);
247#endif
248 status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data);
249#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
250 } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
251#endif
252 if (err)
253 *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
254
255 BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__,
256 fnc_num, addr, data));
257
258 return data;
259}
260
261void
262bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err)
263{
264 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
265 SDIOH_API_RC status;
266#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
267 int32 retry = 0;
268#endif
269
270 if (!bcmsdh)
271 bcmsdh = l_bcmsdh;
272
273 ASSERT(bcmsdh->init_success);
274
275#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
276 do {
277 if (retry) /* wait for 1 ms till bus get settled down */
278 OSL_DELAY(1000);
279#endif
280 status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data);
281#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
282 } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
283#endif
284 if (err)
285 *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR;
286
287 BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__,
288 fnc_num, addr, data));
289}
290
291uint32
292bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err)
293{
294 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
295 SDIOH_API_RC status;
296 uint32 data = 0;
297
298 if (!bcmsdh)
299 bcmsdh = l_bcmsdh;
300
301 ASSERT(bcmsdh->init_success);
302
303 status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num,
304 addr, &data, 4);
305
306 if (err)
307 *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
308
309 BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__,
310 fnc_num, addr, data));
311
312 return data;
313}
314
315void
316bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err)
317{
318 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
319 SDIOH_API_RC status;
320
321 if (!bcmsdh)
322 bcmsdh = l_bcmsdh;
323
324 ASSERT(bcmsdh->init_success);
325
326 status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num,
327 addr, &data, 4);
328
329 if (err)
330 *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
331
332 BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num,
333 addr, data));
334}
335
336
337int
338bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length)
339{
340 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
341 SDIOH_API_RC status;
342
343 uint8 *tmp_buf, *tmp_ptr;
344 uint8 *ptr;
345 bool ascii = func & ~0xf;
346 func &= 0x7;
347
348 if (!bcmsdh)
349 bcmsdh = l_bcmsdh;
350
351 ASSERT(bcmsdh->init_success);
352 ASSERT(cis);
353 ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT);
354
355 status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length);
356
357 if (ascii) {
358 /* Move binary bits to tmp and format them into the provided buffer. */
359 if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) {
360 BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__));
361 return BCME_NOMEM;
362 }
363 bcopy(cis, tmp_buf, length);
364 for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) {
365 ptr += sprintf((char*)ptr, "%.2x ", *tmp_ptr & 0xff);
366 if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0)
367 ptr += sprintf((char *)ptr, "\n");
368 }
369 MFREE(bcmsdh->osh, tmp_buf, length);
370 }
371
372 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
373}
374
375
376int
377bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set)
378{
379 int err = 0;
380 uint bar0 = address & ~SBSDIO_SB_OFT_ADDR_MASK;
381 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
382
383 if (bar0 != bcmsdh->sbwad || force_set) {
384 bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
385 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
386 if (!err)
387 bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
388 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
389 if (!err)
390 bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
391 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
392
393 if (!err)
394 bcmsdh->sbwad = bar0;
395 else
396 /* invalidate cached window var */
397 bcmsdh->sbwad = 0;
398
399 }
400
401 return err;
402}
403
404uint32
405bcmsdh_reg_read(void *sdh, uint32 addr, uint size)
406{
407 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
408 SDIOH_API_RC status;
409 uint32 word = 0;
410
411 BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __FUNCTION__, addr));
412
413 if (!bcmsdh)
414 bcmsdh = l_bcmsdh;
415
416 ASSERT(bcmsdh->init_success);
417
418 if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE))
419 return 0xFFFFFFFF;
420
421 addr &= SBSDIO_SB_OFT_ADDR_MASK;
422 if (size == 4)
423 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
424
425 status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL,
426 SDIOH_READ, SDIO_FUNC_1, addr, &word, size);
427
428 bcmsdh->regfail = !(SDIOH_API_SUCCESS(status));
429
430 BCMSDH_INFO(("uint32data = 0x%x\n", word));
431
432 /* if ok, return appropriately masked word */
433 if (SDIOH_API_SUCCESS(status)) {
434 switch (size) {
435 case sizeof(uint8):
436 return (word & 0xff);
437 case sizeof(uint16):
438 return (word & 0xffff);
439 case sizeof(uint32):
440 return word;
441 default:
442 bcmsdh->regfail = TRUE;
443
444 }
445 }
446
447 /* otherwise, bad sdio access or invalid size */
448 BCMSDH_ERROR(("%s: error reading addr 0x%04x size %d\n", __FUNCTION__, addr, size));
449 return 0xFFFFFFFF;
450}
451
452uint32
453bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data)
454{
455 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
456 SDIOH_API_RC status;
457 int err = 0;
458
459 BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
460 __FUNCTION__, addr, size*8, data));
461
462 if (!bcmsdh)
463 bcmsdh = l_bcmsdh;
464
465 ASSERT(bcmsdh->init_success);
466
467 if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
468 return err;
469
470 addr &= SBSDIO_SB_OFT_ADDR_MASK;
471 if (size == 4)
472 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
473 status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1,
474 addr, &data, size);
475 bcmsdh->regfail = !(SDIOH_API_SUCCESS(status));
476
477 if (SDIOH_API_SUCCESS(status))
478 return 0;
479
480 BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n",
481 __FUNCTION__, data, addr, size));
482 return 0xFFFFFFFF;
483}
484
485bool
486bcmsdh_regfail(void *sdh)
487{
488 return ((bcmsdh_info_t *)sdh)->regfail;
489}
490
491int
492bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags,
493 uint8 *buf, uint nbytes, void *pkt,
494 bcmsdh_cmplt_fn_t complete_fn, void *handle)
495{
496 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
497 SDIOH_API_RC status;
498 uint incr_fix;
499 uint width;
500 int err = 0;
501
502 ASSERT(bcmsdh);
503 ASSERT(bcmsdh->init_success);
504
505 BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
506 __FUNCTION__, fn, addr, nbytes));
507
508 /* Async not implemented yet */
509 ASSERT(!(flags & SDIO_REQ_ASYNC));
510 if (flags & SDIO_REQ_ASYNC)
511 return BCME_UNSUPPORTED;
512
513 if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
514 return err;
515
516 addr &= SBSDIO_SB_OFT_ADDR_MASK;
517
518 incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
519 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
520 if (width == 4)
521 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
522
523 status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
524 SDIOH_READ, fn, addr, width, nbytes, buf, pkt);
525
526 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
527}
528
529int
530bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags,
531 uint8 *buf, uint nbytes, void *pkt,
532 bcmsdh_cmplt_fn_t complete_fn, void *handle)
533{
534 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
535 SDIOH_API_RC status;
536 uint incr_fix;
537 uint width;
538 int err = 0;
539
540 ASSERT(bcmsdh);
541 ASSERT(bcmsdh->init_success);
542
543 BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
544 __FUNCTION__, fn, addr, nbytes));
545
546 /* Async not implemented yet */
547 ASSERT(!(flags & SDIO_REQ_ASYNC));
548 if (flags & SDIO_REQ_ASYNC)
549 return BCME_UNSUPPORTED;
550
551 if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
552 return err;
553
554 addr &= SBSDIO_SB_OFT_ADDR_MASK;
555
556 incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
557 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
558 if (width == 4)
559 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
560
561 status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
562 SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt);
563
564 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
565}
566
567int
568bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes)
569{
570 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
571 SDIOH_API_RC status;
572
573 ASSERT(bcmsdh);
574 ASSERT(bcmsdh->init_success);
575 ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0);
576
577 addr &= SBSDIO_SB_OFT_ADDR_MASK;
578 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
579
580 status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC,
581 (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1,
582 addr, 4, nbytes, buf, NULL);
583
584 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
585}
586
587int
588bcmsdh_abort(void *sdh, uint fn)
589{
590 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
591
592 return sdioh_abort(bcmsdh->sdioh, fn);
593}
594
595int
596bcmsdh_start(void *sdh, int stage)
597{
598 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
599
600 return sdioh_start(bcmsdh->sdioh, stage);
601}
602
603int
604bcmsdh_stop(void *sdh)
605{
606 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
607
608 return sdioh_stop(bcmsdh->sdioh);
609}
610
611int
612bcmsdh_waitlockfree(void *sdh)
613{
614 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
615 if (!bcmsdh)
616 bcmsdh = l_bcmsdh;
617
618 return sdioh_waitlockfree(bcmsdh->sdioh);
619}
620
621
622int
623bcmsdh_query_device(void *sdh)
624{
625 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
626 bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0;
627 return (bcmsdh->vendevid);
628}
629
630uint
631bcmsdh_query_iofnum(void *sdh)
632{
633 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
634
635 if (!bcmsdh)
636 bcmsdh = l_bcmsdh;
637
638 return (sdioh_query_iofnum(bcmsdh->sdioh));
639}
640
641int
642bcmsdh_reset(bcmsdh_info_t *sdh)
643{
644 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
645
646 return sdioh_sdio_reset(bcmsdh->sdioh);
647}
648
649void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh)
650{
651 ASSERT(sdh);
652 return sdh->sdioh;
653}
654
655/* Function to pass device-status bits to DHD. */
656uint32
657bcmsdh_get_dstatus(void *sdh)
658{
659 return 0;
660}
661uint32
662bcmsdh_cur_sbwad(void *sdh)
663{
664 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
665
666 if (!bcmsdh)
667 bcmsdh = l_bcmsdh;
668
669 return (bcmsdh->sbwad);
670}
671
672void
673bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev)
674{
675 return;
676}
677
678
679int
680bcmsdh_sleep(void *sdh, bool enab)
681{
682#ifdef SDIOH_SLEEP_ENABLED
683 bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
684 sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
685
686 return sdioh_sleep(sd, enab);
687#else
688 return BCME_UNSUPPORTED;
689#endif
690}
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
new file mode 100644
index 00000000000..d467e4b5630
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c
@@ -0,0 +1,741 @@
1/*
2 * SDIO access interface for drivers - linux specific (pci only)
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmsdh_linux.c,v 1.72.6.5 2010-12-23 01:13:15 Exp $
25 */
26
27/**
28 * @file bcmsdh_linux.c
29 */
30
31#define __UNDEF_NO_VERSION__
32
33#include <typedefs.h>
34#include <linuxver.h>
35
36#include <linux/pci.h>
37#include <linux/completion.h>
38#include <linux/mmc/sdio_func.h>
39
40#include <osl.h>
41#include <pcicfg.h>
42#include <bcmdefs.h>
43#include <bcmdevs.h>
44
45#if defined(OOB_INTR_ONLY)
46#include <linux/irq.h>
47extern void dhdsdio_isr(void * args);
48#include <bcmutils.h>
49#include <dngl_stats.h>
50#include <dhd.h>
51#endif /* defined(OOB_INTR_ONLY) */
52
53/**
54 * SDIO Host Controller info
55 */
56typedef struct bcmsdh_hc bcmsdh_hc_t;
57
58struct bcmsdh_hc {
59 bcmsdh_hc_t *next;
60#ifdef BCMPLATFORM_BUS
61 struct device *dev; /* platform device handle */
62#else
63 struct pci_dev *dev; /* pci device handle */
64#endif /* BCMPLATFORM_BUS */
65 osl_t *osh;
66 void *regs; /* SDIO Host Controller address */
67 bcmsdh_info_t *sdh; /* SDIO Host Controller handle */
68 void *ch;
69 unsigned int oob_irq;
70 unsigned long oob_flags; /* OOB Host specifiction as edge and etc */
71 bool oob_irq_registered;
72 bool oob_irq_enable_flag;
73#if defined(OOB_INTR_ONLY)
74 spinlock_t irq_lock;
75#endif
76};
77static bcmsdh_hc_t *sdhcinfo = NULL;
78
79/* driver info, initialized when bcmsdh_register is called */
80static bcmsdh_driver_t drvinfo = {NULL, NULL};
81
82/* debugging macros */
83#define SDLX_MSG(x)
84
85/**
86 * Checks to see if vendor and device IDs match a supported SDIO Host Controller.
87 */
88bool
89bcmsdh_chipmatch(uint16 vendor, uint16 device)
90{
91 /* Add other vendors and devices as required */
92
93#ifdef BCMSDIOH_STD
94 /* Check for Arasan host controller */
95 if (vendor == VENDOR_SI_IMAGE) {
96 return (TRUE);
97 }
98 /* Check for BRCM 27XX Standard host controller */
99 if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) {
100 return (TRUE);
101 }
102 /* Check for BRCM Standard host controller */
103 if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
104 return (TRUE);
105 }
106 /* Check for TI PCIxx21 Standard host controller */
107 if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) {
108 return (TRUE);
109 }
110 if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) {
111 return (TRUE);
112 }
113 /* Ricoh R5C822 Standard SDIO Host */
114 if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) {
115 return (TRUE);
116 }
117 /* JMicron Standard SDIO Host */
118 if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) {
119 return (TRUE);
120 }
121
122#endif /* BCMSDIOH_STD */
123#ifdef BCMSDIOH_SPI
124 /* This is the PciSpiHost. */
125 if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
126 printf("Found PCI SPI Host Controller\n");
127 return (TRUE);
128 }
129
130#endif /* BCMSDIOH_SPI */
131
132 return (FALSE);
133}
134
135#if defined(BCMPLATFORM_BUS)
136#if defined(BCMLXSDMMC)
137/* forward declarations */
138int bcmsdh_probe_bcmdhd(struct device *dev);
139int bcmsdh_remove_bcmdhd(struct device *dev);
140
141EXPORT_SYMBOL(bcmsdh_probe_bcmdhd);
142EXPORT_SYMBOL(bcmsdh_remove_bcmdhd);
143
144#else
145/* forward declarations */
146static int __devinit bcmsdh_probe_bcmdhd(struct device *dev);
147static int __devexit bcmsdh_remove_bcmdhd(struct device *dev);
148#endif /* BCMLXSDMMC */
149
150#ifndef BCMLXSDMMC
151static struct device_driver bcmsdh_driver = {
152 .name = "pxa2xx-mci",
153 .bus = &platform_bus_type,
154 .probe = bcmsdh_probe_bcmdhd,
155 .remove = bcmsdh_remove_bcmdhd,
156 .suspend = NULL,
157 .resume = NULL,
158 };
159#endif /* BCMLXSDMMC */
160
161#ifndef BCMLXSDMMC
162static
163#endif /* BCMLXSDMMC */
164int bcmsdh_probe_bcmdhd(struct device *dev)
165{
166 osl_t *osh = NULL;
167 bcmsdh_hc_t *sdhc = NULL;
168 ulong regs = 0;
169 bcmsdh_info_t *sdh = NULL;
170 struct sdio_func *func = container_of(dev, struct sdio_func, dev);
171#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
172 struct platform_device *pdev;
173 struct resource *r;
174#endif /* BCMLXSDMMC */
175 int irq = 0;
176 uint32 vendevid;
177 unsigned long irq_flags = 0;
178
179#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
180 pdev = to_platform_device(dev);
181 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
182 irq = platform_get_irq(pdev, 0);
183 if (!r || irq == NO_IRQ)
184 return -ENXIO;
185#endif /* BCMLXSDMMC */
186
187#if defined(OOB_INTR_ONLY)
188#ifdef HW_OOB
189 irq_flags =
190 IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE;
191#else
192 irq_flags = IRQF_TRIGGER_FALLING;
193#endif /* HW_OOB */
194
195 /* Get customer specific OOB IRQ parametres: IRQ number as IRQ type */
196 irq = dhd_customer_oob_irq_map(&irq_flags);
197 if (irq < 0) {
198 SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__));
199 return 1;
200 }
201#endif /* defined(OOB_INTR_ONLY) */
202 /* allocate SDIO Host Controller state info */
203 if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) {
204 SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
205 goto err;
206 }
207 if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
208 SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
209 __FUNCTION__,
210 MALLOCED(osh)));
211 goto err;
212 }
213 bzero(sdhc, sizeof(bcmsdh_hc_t));
214 sdhc->osh = osh;
215
216 sdhc->dev = (void *)dev;
217
218#ifdef BCMLXSDMMC
219 if (!(sdh = bcmsdh_attach(osh, (void *)0,
220 (void **)&regs, irq))) {
221 SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
222 goto err;
223 }
224#else
225 if (!(sdh = bcmsdh_attach(osh, (void *)r->start,
226 (void **)&regs, irq))) {
227 SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
228 goto err;
229 }
230#endif /* BCMLXSDMMC */
231 sdhc->sdh = sdh;
232 sdhc->oob_irq = irq;
233 sdhc->oob_flags = irq_flags;
234 sdhc->oob_irq_registered = FALSE; /* to make sure.. */
235 sdhc->oob_irq_enable_flag = FALSE;
236#if defined(OOB_INTR_ONLY)
237 spin_lock_init(&sdhc->irq_lock);
238#endif
239
240 /* chain SDIO Host Controller info together */
241 sdhc->next = sdhcinfo;
242 sdhcinfo = sdhc;
243 /* Read the vendor/device ID from the CIS */
244 vendevid = bcmsdh_query_device(sdh);
245
246
247 /* try to attach to the target device */
248 if (!(sdhc->ch = drvinfo.attach((vendevid >> 16),
249 func->device, 0, 0, 0, 0,
250 (void *)regs, NULL, sdh, dev))) {
251 SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
252 goto err;
253 }
254
255 return 0;
256
257 /* error handling */
258err:
259 if (sdhc) {
260 if (sdhc->sdh)
261 bcmsdh_detach(sdhc->osh, sdhc->sdh);
262 MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
263 }
264 if (osh)
265 osl_detach(osh);
266 return -ENODEV;
267}
268
269#ifndef BCMLXSDMMC
270static
271#endif /* BCMLXSDMMC */
272int bcmsdh_remove_bcmdhd(struct device *dev)
273{
274 bcmsdh_hc_t *sdhc, *prev;
275 osl_t *osh;
276
277 sdhc = sdhcinfo;
278 drvinfo.detach(sdhc->ch);
279 bcmsdh_detach(sdhc->osh, sdhc->sdh);
280 /* find the SDIO Host Controller state for this pdev and take it out from the list */
281 for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
282 if (sdhc->dev == (void *)dev) {
283 if (prev)
284 prev->next = sdhc->next;
285 else
286 sdhcinfo = NULL;
287 break;
288 }
289 prev = sdhc;
290 }
291 if (!sdhc) {
292 SDLX_MSG(("%s: failed\n", __FUNCTION__));
293 return 0;
294 }
295
296
297 /* release SDIO Host Controller info */
298 osh = sdhc->osh;
299 MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
300 osl_detach(osh);
301
302#if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY)
303 dev_set_drvdata(dev, NULL);
304#endif /* !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY) */
305
306 return 0;
307}
308
309#else /* BCMPLATFORM_BUS */
310
311#if !defined(BCMLXSDMMC)
312/* forward declarations for PCI probe and remove functions. */
313static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
314static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev);
315
316/**
317 * pci id table
318 */
319static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = {
320 { vendor: PCI_ANY_ID,
321 device: PCI_ANY_ID,
322 subvendor: PCI_ANY_ID,
323 subdevice: PCI_ANY_ID,
324 class: 0,
325 class_mask: 0,
326 driver_data: 0,
327 },
328 { 0, }
329};
330MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid);
331
332/**
333 * SDIO Host Controller pci driver info
334 */
335static struct pci_driver bcmsdh_pci_driver = {
336 node: {},
337 name: "bcmsdh",
338 id_table: bcmsdh_pci_devid,
339 probe: bcmsdh_pci_probe,
340 remove: bcmsdh_pci_remove,
341#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
342 save_state: NULL,
343#endif
344 suspend: NULL,
345 resume: NULL,
346 };
347
348
349extern uint sd_pci_slot; /* Force detection to a particular PCI */
350 /* slot only . Allows for having multiple */
351 /* WL devices at once in a PC */
352 /* Only one instance of dhd will be */
353 /* usable at a time */
354 /* Upper word is bus number, */
355 /* lower word is slot number */
356 /* Default value of 0xffffffff turns this */
357 /* off */
358module_param(sd_pci_slot, uint, 0);
359
360
361/**
362 * Detect supported SDIO Host Controller and attach if found.
363 *
364 * Determine if the device described by pdev is a supported SDIO Host
365 * Controller. If so, attach to it and attach to the target device.
366 */
367static int __devinit
368bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
369{
370 osl_t *osh = NULL;
371 bcmsdh_hc_t *sdhc = NULL;
372 ulong regs;
373 bcmsdh_info_t *sdh = NULL;
374 int rc;
375
376 if (sd_pci_slot != 0xFFFFffff) {
377 if (pdev->bus->number != (sd_pci_slot>>16) ||
378 PCI_SLOT(pdev->devfn) != (sd_pci_slot&0xffff)) {
379 SDLX_MSG(("%s: %s: bus %X, slot %X, vend %X, dev %X\n",
380 __FUNCTION__,
381 bcmsdh_chipmatch(pdev->vendor, pdev->device)
382 ?"Found compatible SDIOHC"
383 :"Probing unknown device",
384 pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor,
385 pdev->device));
386 return -ENODEV;
387 }
388 SDLX_MSG(("%s: %s: bus %X, slot %X, vendor %X, device %X (good PCI location)\n",
389 __FUNCTION__,
390 bcmsdh_chipmatch(pdev->vendor, pdev->device)
391 ?"Using compatible SDIOHC"
392 :"WARNING, forced use of unkown device",
393 pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor, pdev->device));
394 }
395
396 if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) ||
397 (pdev->device == PCIXX21_FLASHMEDIA0_ID))) {
398 uint32 config_reg;
399
400 SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n", __FUNCTION__));
401 if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
402 SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
403 goto err;
404 }
405
406 config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4);
407
408 /*
409 * Set MMC_SD_DIS bit in FlashMedia Controller.
410 * Disbling the SD/MMC Controller in the FlashMedia Controller
411 * allows the Standard SD Host Controller to take over control
412 * of the SD Slot.
413 */
414 config_reg |= 0x02;
415 OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg);
416 osl_detach(osh);
417 }
418 /* match this pci device with what we support */
419 /* we can't solely rely on this to believe it is our SDIO Host Controller! */
420 if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) {
421 return -ENODEV;
422 }
423
424 /* this is a pci device we might support */
425 SDLX_MSG(("%s: Found possible SDIO Host Controller: bus %d slot %d func %d irq %d\n",
426 __FUNCTION__,
427 pdev->bus->number, PCI_SLOT(pdev->devfn),
428 PCI_FUNC(pdev->devfn), pdev->irq));
429
430 /* use bcmsdh_query_device() to get the vendor ID of the target device so
431 * it will eventually appear in the Broadcom string on the console
432 */
433
434 /* allocate SDIO Host Controller state info */
435 if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
436 SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
437 goto err;
438 }
439 if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
440 SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
441 __FUNCTION__,
442 MALLOCED(osh)));
443 goto err;
444 }
445 bzero(sdhc, sizeof(bcmsdh_hc_t));
446 sdhc->osh = osh;
447
448 sdhc->dev = pdev;
449
450 /* map to address where host can access */
451 pci_set_master(pdev);
452 rc = pci_enable_device(pdev);
453 if (rc) {
454 SDLX_MSG(("%s: Cannot enable PCI device\n", __FUNCTION__));
455 goto err;
456 }
457 if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0),
458 (void **)&regs, pdev->irq))) {
459 SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
460 goto err;
461 }
462
463 sdhc->sdh = sdh;
464
465 /* try to attach to the target device */
466 if (!(sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */
467 bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0,
468 (void *)regs, NULL, sdh, pdev->dev))) {
469 SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
470 goto err;
471 }
472
473 /* chain SDIO Host Controller info together */
474 sdhc->next = sdhcinfo;
475 sdhcinfo = sdhc;
476
477 return 0;
478
479 /* error handling */
480err:
481 if (sdhc) {
482 if (sdhc->sdh)
483 bcmsdh_detach(sdhc->osh, sdhc->sdh);
484 MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
485 }
486 if (osh)
487 osl_detach(osh);
488 return -ENODEV;
489}
490
491
492/**
493 * Detach from target devices and SDIO Host Controller
494 */
495static void __devexit
496bcmsdh_pci_remove(struct pci_dev *pdev)
497{
498 bcmsdh_hc_t *sdhc, *prev;
499 osl_t *osh;
500
501 /* find the SDIO Host Controller state for this pdev and take it out from the list */
502 for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
503 if (sdhc->dev == pdev) {
504 if (prev)
505 prev->next = sdhc->next;
506 else
507 sdhcinfo = NULL;
508 break;
509 }
510 prev = sdhc;
511 }
512 if (!sdhc)
513 return;
514
515 drvinfo.detach(sdhc->ch);
516
517 bcmsdh_detach(sdhc->osh, sdhc->sdh);
518
519 /* release SDIO Host Controller info */
520 osh = sdhc->osh;
521 MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
522 osl_detach(osh);
523}
524#endif /* BCMLXSDMMC */
525#endif /* BCMPLATFORM_BUS */
526
527extern int sdio_function_init(void);
528
529int
530bcmsdh_register(bcmsdh_driver_t *driver)
531{
532 int error = 0;
533
534 drvinfo = *driver;
535
536#if defined(BCMPLATFORM_BUS)
537#if defined(BCMLXSDMMC)
538 SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
539 error = sdio_function_init();
540#else
541 SDLX_MSG(("Intel PXA270 SDIO Driver\n"));
542 error = driver_register(&bcmsdh_driver);
543#endif /* defined(BCMLXSDMMC) */
544 return error;
545#endif /* defined(BCMPLATFORM_BUS) */
546
547#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
548#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
549 if (!(error = pci_module_init(&bcmsdh_pci_driver)))
550 return 0;
551#else
552 if (!(error = pci_register_driver(&bcmsdh_pci_driver)))
553 return 0;
554#endif
555
556 SDLX_MSG(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error));
557#endif /* BCMPLATFORM_BUS */
558
559 return error;
560}
561
562extern void sdio_function_cleanup(void);
563
564void
565bcmsdh_unregister(void)
566{
567#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
568 if (bcmsdh_pci_driver.node.next)
569#endif
570
571#if defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
572 driver_unregister(&bcmsdh_driver);
573#endif
574#if defined(BCMLXSDMMC)
575 sdio_function_cleanup();
576#endif /* BCMLXSDMMC */
577#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
578 pci_unregister_driver(&bcmsdh_pci_driver);
579#endif /* BCMPLATFORM_BUS */
580}
581
582#if defined(OOB_INTR_ONLY)
583void bcmsdh_oob_intr_set(bool enable)
584{
585 static bool curstate = 1;
586 unsigned long flags;
587
588 spin_lock_irqsave(&sdhcinfo->irq_lock, flags);
589 if (curstate != enable) {
590 if (enable)
591 enable_irq(sdhcinfo->oob_irq);
592 else
593 disable_irq_nosync(sdhcinfo->oob_irq);
594 curstate = enable;
595 }
596 spin_unlock_irqrestore(&sdhcinfo->irq_lock, flags);
597}
598
599static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
600{
601 dhd_pub_t *dhdp;
602
603 dhdp = (dhd_pub_t *)dev_get_drvdata(sdhcinfo->dev);
604
605 bcmsdh_oob_intr_set(0);
606
607 if (dhdp == NULL) {
608 SDLX_MSG(("Out of band GPIO interrupt fired way too early\n"));
609 return IRQ_HANDLED;
610 }
611
612 dhdsdio_isr((void *)dhdp->bus);
613
614 return IRQ_HANDLED;
615}
616
617void *bcmsdh_get_drvdata(void)
618{
619 if (!sdhcinfo)
620 return NULL;
621 return dev_get_drvdata(sdhcinfo->dev);
622}
623
624int bcmsdh_register_oob_intr(void * dhdp)
625{
626 int error = 0;
627
628 SDLX_MSG(("%s Enter \n", __FUNCTION__));
629
630 /* IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; */
631
632 dev_set_drvdata(sdhcinfo->dev, dhdp);
633
634 if (!sdhcinfo->oob_irq_registered) {
635 SDLX_MSG(("%s IRQ=%d Type=%X \n", __FUNCTION__,
636 (int)sdhcinfo->oob_irq, (int)sdhcinfo->oob_flags));
637 /* Refer to customer Host IRQ docs about proper irqflags definition */
638 error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags,
639 "bcmsdh_sdmmc", NULL);
640 if (error)
641 return -ENODEV;
642
643 enable_irq_wake(sdhcinfo->oob_irq);
644 sdhcinfo->oob_irq_registered = TRUE;
645 sdhcinfo->oob_irq_enable_flag = TRUE;
646 }
647
648 return 0;
649}
650
651void bcmsdh_set_irq(int flag)
652{
653 if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) {
654 SDLX_MSG(("%s Flag = %d", __FUNCTION__, flag));
655 sdhcinfo->oob_irq_enable_flag = flag;
656 if (flag) {
657 enable_irq(sdhcinfo->oob_irq);
658 enable_irq_wake(sdhcinfo->oob_irq);
659 } else {
660 disable_irq_wake(sdhcinfo->oob_irq);
661 disable_irq(sdhcinfo->oob_irq);
662 }
663 }
664}
665
666void bcmsdh_unregister_oob_intr(void)
667{
668 SDLX_MSG(("%s: Enter\n", __FUNCTION__));
669
670 if (sdhcinfo->oob_irq_registered == TRUE) {
671 bcmsdh_set_irq(FALSE);
672 free_irq(sdhcinfo->oob_irq, NULL);
673 sdhcinfo->oob_irq_registered = FALSE;
674 }
675}
676#endif /* defined(OOB_INTR_ONLY) */
677/* Module parameters specific to each host-controller driver */
678
679extern uint sd_msglevel; /* Debug message level */
680module_param(sd_msglevel, uint, 0);
681
682extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */
683module_param(sd_power, uint, 0);
684
685extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */
686module_param(sd_clock, uint, 0);
687
688extern uint sd_divisor; /* Divisor (-1 means external clock) */
689module_param(sd_divisor, uint, 0);
690
691extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */
692module_param(sd_sdmode, uint, 0);
693
694extern uint sd_hiok; /* Ok to use hi-speed mode */
695module_param(sd_hiok, uint, 0);
696
697extern uint sd_f2_blocksize;
698module_param(sd_f2_blocksize, int, 0);
699
700
701#ifdef BCMSDH_MODULE
702EXPORT_SYMBOL(bcmsdh_attach);
703EXPORT_SYMBOL(bcmsdh_detach);
704EXPORT_SYMBOL(bcmsdh_intr_query);
705EXPORT_SYMBOL(bcmsdh_intr_enable);
706EXPORT_SYMBOL(bcmsdh_intr_disable);
707EXPORT_SYMBOL(bcmsdh_intr_reg);
708EXPORT_SYMBOL(bcmsdh_intr_dereg);
709
710#if defined(DHD_DEBUG)
711EXPORT_SYMBOL(bcmsdh_intr_pending);
712#endif
713
714EXPORT_SYMBOL(bcmsdh_devremove_reg);
715EXPORT_SYMBOL(bcmsdh_cfg_read);
716EXPORT_SYMBOL(bcmsdh_cfg_write);
717EXPORT_SYMBOL(bcmsdh_cis_read);
718EXPORT_SYMBOL(bcmsdh_reg_read);
719EXPORT_SYMBOL(bcmsdh_reg_write);
720EXPORT_SYMBOL(bcmsdh_regfail);
721EXPORT_SYMBOL(bcmsdh_send_buf);
722EXPORT_SYMBOL(bcmsdh_recv_buf);
723
724EXPORT_SYMBOL(bcmsdh_rwdata);
725EXPORT_SYMBOL(bcmsdh_abort);
726EXPORT_SYMBOL(bcmsdh_query_device);
727EXPORT_SYMBOL(bcmsdh_query_iofnum);
728EXPORT_SYMBOL(bcmsdh_iovar_op);
729EXPORT_SYMBOL(bcmsdh_register);
730EXPORT_SYMBOL(bcmsdh_unregister);
731EXPORT_SYMBOL(bcmsdh_chipmatch);
732EXPORT_SYMBOL(bcmsdh_reset);
733EXPORT_SYMBOL(bcmsdh_waitlockfree);
734
735EXPORT_SYMBOL(bcmsdh_get_dstatus);
736EXPORT_SYMBOL(bcmsdh_cfg_read_word);
737EXPORT_SYMBOL(bcmsdh_cfg_write_word);
738EXPORT_SYMBOL(bcmsdh_cur_sbwad);
739EXPORT_SYMBOL(bcmsdh_chipinfo);
740
741#endif /* BCMSDH_MODULE */
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
new file mode 100644
index 00000000000..7499a1ec55f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c
@@ -0,0 +1,1331 @@
1/*
2 * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmsdh_sdmmc.c 282820 2011-09-09 15:40:35Z $
25 */
26#include <typedefs.h>
27
28#include <bcmdevs.h>
29#include <bcmendian.h>
30#include <bcmutils.h>
31#include <osl.h>
32#include <sdio.h> /* SDIO Device and Protocol Specs */
33#include <sdioh.h> /* Standard SDIO Host Controller Specification */
34#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
35#include <sdiovar.h> /* ioctl/iovars */
36
37#include <linux/mmc/core.h>
38#include <linux/mmc/sdio_func.h>
39#include <linux/mmc/sdio_ids.h>
40
41#include <dngl_stats.h>
42#include <dhd.h>
43
44#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
45#include <linux/suspend.h>
46extern volatile bool dhd_mmc_suspend;
47#endif
48#include "bcmsdh_sdmmc.h"
49
50#ifndef BCMSDH_MODULE
51extern int sdio_function_init(void);
52extern void sdio_function_cleanup(void);
53#endif /* BCMSDH_MODULE */
54
55#if !defined(OOB_INTR_ONLY)
56static void IRQHandler(struct sdio_func *func);
57static void IRQHandlerF2(struct sdio_func *func);
58#endif /* !defined(OOB_INTR_ONLY) */
59static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr);
60extern int sdio_reset_comm(struct mmc_card *card);
61
62extern PBCMSDH_SDMMC_INSTANCE gInstance;
63
64uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */
65uint sd_f2_blocksize = 512; /* Default blocksize */
66
67uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */
68
69uint sd_power = 1; /* Default to SD Slot powered ON */
70uint sd_clock = 1; /* Default to SD Clock turned ON */
71uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */
72uint sd_msglevel = 0x01;
73uint sd_use_dma = TRUE;
74DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait);
75DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait);
76DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait);
77DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait);
78
79#define DMA_ALIGN_MASK 0x03
80
81int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data);
82
83static int
84sdioh_sdmmc_card_enablefuncs(sdioh_info_t *sd)
85{
86 int err_ret;
87 uint32 fbraddr;
88 uint8 func;
89
90 sd_trace(("%s\n", __FUNCTION__));
91
92 /* Get the Card's common CIS address */
93 sd->com_cis_ptr = sdioh_sdmmc_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0);
94 sd->func_cis_ptr[0] = sd->com_cis_ptr;
95 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
96
97 /* Get the Card's function CIS (for each function) */
98 for (fbraddr = SDIOD_FBR_STARTADDR, func = 1;
99 func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
100 sd->func_cis_ptr[func] = sdioh_sdmmc_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr);
101 sd_info(("%s: Function %d CIS Ptr = 0x%x\n",
102 __FUNCTION__, func, sd->func_cis_ptr[func]));
103 }
104
105 sd->func_cis_ptr[0] = sd->com_cis_ptr;
106 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
107
108 /* Enable Function 1 */
109 sdio_claim_host(gInstance->func[1]);
110 err_ret = sdio_enable_func(gInstance->func[1]);
111 sdio_release_host(gInstance->func[1]);
112 if (err_ret) {
113 sd_err(("bcmsdh_sdmmc: Failed to enable F1 Err: 0x%08x", err_ret));
114 }
115
116 return FALSE;
117}
118
119/*
120 * Public entry points & extern's
121 */
122extern sdioh_info_t *
123sdioh_attach(osl_t *osh, void *bar0, uint irq)
124{
125 sdioh_info_t *sd;
126 int err_ret;
127
128 sd_trace(("%s\n", __FUNCTION__));
129
130 if (gInstance == NULL) {
131 sd_err(("%s: SDIO Device not present\n", __FUNCTION__));
132 return NULL;
133 }
134
135 if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
136 sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
137 return NULL;
138 }
139 bzero((char *)sd, sizeof(sdioh_info_t));
140 sd->osh = osh;
141 if (sdioh_sdmmc_osinit(sd) != 0) {
142 sd_err(("%s:sdioh_sdmmc_osinit() failed\n", __FUNCTION__));
143 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
144 return NULL;
145 }
146
147 sd->num_funcs = 2;
148 sd->sd_blockmode = TRUE;
149 sd->use_client_ints = TRUE;
150 sd->client_block_size[0] = 64;
151
152 gInstance->sd = sd;
153
154 /* Claim host controller */
155 sdio_claim_host(gInstance->func[1]);
156
157 sd->client_block_size[1] = 64;
158 err_ret = sdio_set_block_size(gInstance->func[1], 64);
159 if (err_ret) {
160 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
161 }
162
163 /* Release host controller F1 */
164 sdio_release_host(gInstance->func[1]);
165
166 if (gInstance->func[2]) {
167 /* Claim host controller F2 */
168 sdio_claim_host(gInstance->func[2]);
169
170 sd->client_block_size[2] = sd_f2_blocksize;
171 err_ret = sdio_set_block_size(gInstance->func[2], sd_f2_blocksize);
172 if (err_ret) {
173 sd_err(("bcmsdh_sdmmc: Failed to set F2 blocksize to %d\n",
174 sd_f2_blocksize));
175 }
176
177 /* Release host controller F2 */
178 sdio_release_host(gInstance->func[2]);
179 }
180
181 sdioh_sdmmc_card_enablefuncs(sd);
182
183 sd_trace(("%s: Done\n", __FUNCTION__));
184 return sd;
185}
186
187
188extern SDIOH_API_RC
189sdioh_detach(osl_t *osh, sdioh_info_t *sd)
190{
191 sd_trace(("%s\n", __FUNCTION__));
192
193 if (sd) {
194
195 /* Disable Function 2 */
196 sdio_claim_host(gInstance->func[2]);
197 sdio_disable_func(gInstance->func[2]);
198 sdio_release_host(gInstance->func[2]);
199
200 /* Disable Function 1 */
201 if (gInstance->func[1]) {
202 sdio_claim_host(gInstance->func[1]);
203 sdio_disable_func(gInstance->func[1]);
204 sdio_release_host(gInstance->func[1]);
205 }
206
207 gInstance->func[1] = NULL;
208 gInstance->func[2] = NULL;
209
210 /* deregister irq */
211 sdioh_sdmmc_osfree(sd);
212
213 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
214 }
215 return SDIOH_API_RC_SUCCESS;
216}
217
218#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
219
220extern SDIOH_API_RC
221sdioh_enable_func_intr(void)
222{
223 uint8 reg;
224 int err;
225
226 if (gInstance->func[0]) {
227 sdio_claim_host(gInstance->func[0]);
228
229 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
230 if (err) {
231 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
232 sdio_release_host(gInstance->func[0]);
233 return SDIOH_API_RC_FAIL;
234 }
235
236 /* Enable F1 and F2 interrupts, set master enable */
237 reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN | INTR_CTL_MASTER_EN);
238
239 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
240 sdio_release_host(gInstance->func[0]);
241
242 if (err) {
243 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
244 return SDIOH_API_RC_FAIL;
245 }
246 }
247
248 return SDIOH_API_RC_SUCCESS;
249}
250
251#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
252
253extern SDIOH_API_RC
254sdioh_disable_func_intr(int func)
255{
256 uint8 reg;
257 int err;
258
259 if (gInstance->func[func]) {
260 sdio_claim_host(gInstance->func[func]);
261 reg = sdio_readb(gInstance->func[func], SDIOD_CCCR_INTEN, &err);
262 if (err) {
263 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
264 sdio_release_host(gInstance->func[func]);
265 return SDIOH_API_RC_FAIL;
266 }
267#if defined(HW_OOB)
268 reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN);
269#else
270 reg &= ~(1 << func);
271#endif
272 /* Disable master interrupt with the last function interrupt */
273 if (!(reg & 0xFE))
274 reg = 0;
275 sdio_writeb(gInstance->func[func], reg, SDIOD_CCCR_INTEN, &err);
276
277 sdio_release_host(gInstance->func[func]);
278 if (err) {
279 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
280 return SDIOH_API_RC_FAIL;
281 }
282 }
283 return SDIOH_API_RC_SUCCESS;
284}
285
286
287/* Configure callback to client when we recieve client interrupt */
288extern SDIOH_API_RC
289sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
290{
291 sd_trace(("%s: Entering\n", __FUNCTION__));
292 if (fn == NULL) {
293 sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__));
294 return SDIOH_API_RC_FAIL;
295 }
296#if !defined(OOB_INTR_ONLY)
297 sd->intr_handler = fn;
298 sd->intr_handler_arg = argh;
299 sd->intr_handler_valid = TRUE;
300
301 /* register and unmask irq */
302 if (gInstance->func[2]) {
303 sdio_claim_host(gInstance->func[2]);
304 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
305 sdio_release_host(gInstance->func[2]);
306 }
307
308 if (gInstance->func[1]) {
309 sdio_claim_host(gInstance->func[1]);
310 sdio_claim_irq(gInstance->func[1], IRQHandler);
311 sdio_release_host(gInstance->func[1]);
312 }
313#elif defined(HW_OOB)
314 sdioh_enable_func_intr();
315#endif /* !defined(OOB_INTR_ONLY) */
316
317 return SDIOH_API_RC_SUCCESS;
318}
319
320extern SDIOH_API_RC
321sdioh_interrupt_deregister(sdioh_info_t *sd)
322{
323 sd_trace(("%s: Entering\n", __FUNCTION__));
324
325#if !defined(OOB_INTR_ONLY)
326 if (gInstance->func[1]) {
327 sdioh_disable_func_intr(1);
328 /*Wait for the pending interrupts to be cleared*/
329 msleep(300);
330 /* register and unmask irq */
331 sdio_claim_host(gInstance->func[1]);
332 sdio_release_irq(gInstance->func[1]);
333 sdio_release_host(gInstance->func[1]);
334 }
335
336 if (gInstance->func[2]) {
337 sdioh_disable_func_intr(2);
338 /*Wait for the pending interrupts to be cleared*/
339 msleep(300);
340 /* Claim host controller F2 */
341 sdio_claim_host(gInstance->func[2]);
342 sdio_release_irq(gInstance->func[2]);
343 /* Release host controller F2 */
344 sdio_release_host(gInstance->func[2]);
345 }
346
347 sd->intr_handler_valid = FALSE;
348 sd->intr_handler = NULL;
349 sd->intr_handler_arg = NULL;
350#elif defined(HW_OOB)
351 sdioh_disable_func_intr(0);
352#endif /* !defined(OOB_INTR_ONLY) */
353 return SDIOH_API_RC_SUCCESS;
354}
355
356extern SDIOH_API_RC
357sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
358{
359 sd_trace(("%s: Entering\n", __FUNCTION__));
360 *onoff = sd->client_intr_enabled;
361 return SDIOH_API_RC_SUCCESS;
362}
363
364#if defined(DHD_DEBUG)
365extern bool
366sdioh_interrupt_pending(sdioh_info_t *sd)
367{
368 return (0);
369}
370#endif
371
372uint
373sdioh_query_iofnum(sdioh_info_t *sd)
374{
375 return sd->num_funcs;
376}
377
378/* IOVar table */
379enum {
380 IOV_MSGLEVEL = 1,
381 IOV_BLOCKMODE,
382 IOV_BLOCKSIZE,
383 IOV_DMA,
384 IOV_USEINTS,
385 IOV_NUMINTS,
386 IOV_NUMLOCALINTS,
387 IOV_HOSTREG,
388 IOV_DEVREG,
389 IOV_DIVISOR,
390 IOV_SDMODE,
391 IOV_HISPEED,
392 IOV_HCIREGS,
393 IOV_POWER,
394 IOV_CLOCK,
395 IOV_RXCHAIN
396};
397
398const bcm_iovar_t sdioh_iovars[] = {
399 {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
400 {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 },
401 {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */
402 {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 },
403 {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 },
404 {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 },
405 {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 },
406 {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
407 {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
408 {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 },
409 {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 },
410 {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 },
411 {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100},
412 {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 },
413 {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 },
414 {NULL, 0, 0, 0, 0 }
415};
416
417int
418sdioh_iovar_op(sdioh_info_t *si, const char *name,
419 void *params, int plen, void *arg, int len, bool set)
420{
421 const bcm_iovar_t *vi = NULL;
422 int bcmerror = 0;
423 int val_size;
424 int32 int_val = 0;
425 bool bool_val;
426 uint32 actionid;
427
428 ASSERT(name);
429 ASSERT(len >= 0);
430
431 /* Get must have return space; Set does not take qualifiers */
432 ASSERT(set || (arg && len));
433 ASSERT(!set || (!params && !plen));
434
435 sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
436
437 if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
438 bcmerror = BCME_UNSUPPORTED;
439 goto exit;
440 }
441
442 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
443 goto exit;
444
445 /* Set up params so get and set can share the convenience variables */
446 if (params == NULL) {
447 params = arg;
448 plen = len;
449 }
450
451 if (vi->type == IOVT_VOID)
452 val_size = 0;
453 else if (vi->type == IOVT_BUFFER)
454 val_size = len;
455 else
456 val_size = sizeof(int);
457
458 if (plen >= (int)sizeof(int_val))
459 bcopy(params, &int_val, sizeof(int_val));
460
461 bool_val = (int_val != 0) ? TRUE : FALSE;
462
463 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
464 switch (actionid) {
465 case IOV_GVAL(IOV_MSGLEVEL):
466 int_val = (int32)sd_msglevel;
467 bcopy(&int_val, arg, val_size);
468 break;
469
470 case IOV_SVAL(IOV_MSGLEVEL):
471 sd_msglevel = int_val;
472 break;
473
474 case IOV_GVAL(IOV_BLOCKMODE):
475 int_val = (int32)si->sd_blockmode;
476 bcopy(&int_val, arg, val_size);
477 break;
478
479 case IOV_SVAL(IOV_BLOCKMODE):
480 si->sd_blockmode = (bool)int_val;
481 /* Haven't figured out how to make non-block mode with DMA */
482 break;
483
484 case IOV_GVAL(IOV_BLOCKSIZE):
485 if ((uint32)int_val > si->num_funcs) {
486 bcmerror = BCME_BADARG;
487 break;
488 }
489 int_val = (int32)si->client_block_size[int_val];
490 bcopy(&int_val, arg, val_size);
491 break;
492
493 case IOV_SVAL(IOV_BLOCKSIZE):
494 {
495 uint func = ((uint32)int_val >> 16);
496 uint blksize = (uint16)int_val;
497 uint maxsize;
498
499 if (func > si->num_funcs) {
500 bcmerror = BCME_BADARG;
501 break;
502 }
503
504 switch (func) {
505 case 0: maxsize = 32; break;
506 case 1: maxsize = BLOCK_SIZE_4318; break;
507 case 2: maxsize = BLOCK_SIZE_4328; break;
508 default: maxsize = 0;
509 }
510 if (blksize > maxsize) {
511 bcmerror = BCME_BADARG;
512 break;
513 }
514 if (!blksize) {
515 blksize = maxsize;
516 }
517
518 /* Now set it */
519 si->client_block_size[func] = blksize;
520
521 break;
522 }
523
524 case IOV_GVAL(IOV_RXCHAIN):
525 int_val = FALSE;
526 bcopy(&int_val, arg, val_size);
527 break;
528
529 case IOV_GVAL(IOV_DMA):
530 int_val = (int32)si->sd_use_dma;
531 bcopy(&int_val, arg, val_size);
532 break;
533
534 case IOV_SVAL(IOV_DMA):
535 si->sd_use_dma = (bool)int_val;
536 break;
537
538 case IOV_GVAL(IOV_USEINTS):
539 int_val = (int32)si->use_client_ints;
540 bcopy(&int_val, arg, val_size);
541 break;
542
543 case IOV_SVAL(IOV_USEINTS):
544 si->use_client_ints = (bool)int_val;
545 if (si->use_client_ints)
546 si->intmask |= CLIENT_INTR;
547 else
548 si->intmask &= ~CLIENT_INTR;
549
550 break;
551
552 case IOV_GVAL(IOV_DIVISOR):
553 int_val = (uint32)sd_divisor;
554 bcopy(&int_val, arg, val_size);
555 break;
556
557 case IOV_SVAL(IOV_DIVISOR):
558 sd_divisor = int_val;
559 break;
560
561 case IOV_GVAL(IOV_POWER):
562 int_val = (uint32)sd_power;
563 bcopy(&int_val, arg, val_size);
564 break;
565
566 case IOV_SVAL(IOV_POWER):
567 sd_power = int_val;
568 break;
569
570 case IOV_GVAL(IOV_CLOCK):
571 int_val = (uint32)sd_clock;
572 bcopy(&int_val, arg, val_size);
573 break;
574
575 case IOV_SVAL(IOV_CLOCK):
576 sd_clock = int_val;
577 break;
578
579 case IOV_GVAL(IOV_SDMODE):
580 int_val = (uint32)sd_sdmode;
581 bcopy(&int_val, arg, val_size);
582 break;
583
584 case IOV_SVAL(IOV_SDMODE):
585 sd_sdmode = int_val;
586 break;
587
588 case IOV_GVAL(IOV_HISPEED):
589 int_val = (uint32)sd_hiok;
590 bcopy(&int_val, arg, val_size);
591 break;
592
593 case IOV_SVAL(IOV_HISPEED):
594 sd_hiok = int_val;
595 break;
596
597 case IOV_GVAL(IOV_NUMINTS):
598 int_val = (int32)si->intrcount;
599 bcopy(&int_val, arg, val_size);
600 break;
601
602 case IOV_GVAL(IOV_NUMLOCALINTS):
603 int_val = (int32)0;
604 bcopy(&int_val, arg, val_size);
605 break;
606
607 case IOV_GVAL(IOV_HOSTREG):
608 {
609 sdreg_t *sd_ptr = (sdreg_t *)params;
610
611 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
612 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
613 bcmerror = BCME_BADARG;
614 break;
615 }
616
617 sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__,
618 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
619 sd_ptr->offset));
620 if (sd_ptr->offset & 1)
621 int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */
622 else if (sd_ptr->offset & 2)
623 int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */
624 else
625 int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */
626
627 bcopy(&int_val, arg, sizeof(int_val));
628 break;
629 }
630
631 case IOV_SVAL(IOV_HOSTREG):
632 {
633 sdreg_t *sd_ptr = (sdreg_t *)params;
634
635 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
636 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
637 bcmerror = BCME_BADARG;
638 break;
639 }
640
641 sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value,
642 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
643 sd_ptr->offset));
644 break;
645 }
646
647 case IOV_GVAL(IOV_DEVREG):
648 {
649 sdreg_t *sd_ptr = (sdreg_t *)params;
650 uint8 data = 0;
651
652 if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
653 bcmerror = BCME_SDIO_ERROR;
654 break;
655 }
656
657 int_val = (int)data;
658 bcopy(&int_val, arg, sizeof(int_val));
659 break;
660 }
661
662 case IOV_SVAL(IOV_DEVREG):
663 {
664 sdreg_t *sd_ptr = (sdreg_t *)params;
665 uint8 data = (uint8)sd_ptr->value;
666
667 if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
668 bcmerror = BCME_SDIO_ERROR;
669 break;
670 }
671 break;
672 }
673
674 default:
675 bcmerror = BCME_UNSUPPORTED;
676 break;
677 }
678exit:
679
680 return bcmerror;
681}
682
683#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
684
685SDIOH_API_RC
686sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
687{
688 SDIOH_API_RC status;
689 uint8 data;
690
691 if (enable)
692 data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE; /* enable hw oob interrupt */
693 else
694 data = SDIO_SEPINT_ACT_HI; /* disable hw oob interrupt */
695
696#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
697 /* Needed for Android Linux Kernel 2.6.35 */
698 data |= SDIO_SEPINT_ACT_HI; /* Active HIGH */
699#endif
700
701 status = sdioh_request_byte(sd, SDIOH_WRITE, 0, SDIOD_CCCR_BRCM_SEPINT, &data);
702 return status;
703}
704#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
705
706extern SDIOH_API_RC
707sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
708{
709 SDIOH_API_RC status;
710 /* No lock needed since sdioh_request_byte does locking */
711 status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
712 return status;
713}
714
715extern SDIOH_API_RC
716sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
717{
718 /* No lock needed since sdioh_request_byte does locking */
719 SDIOH_API_RC status;
720 status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
721 return status;
722}
723
724static int
725sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr)
726{
727 /* read 24 bits and return valid 17 bit addr */
728 int i;
729 uint32 scratch, regdata;
730 uint8 *ptr = (uint8 *)&scratch;
731 for (i = 0; i < 3; i++) {
732 if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, &regdata)) != SUCCESS)
733 sd_err(("%s: Can't read!\n", __FUNCTION__));
734
735 *ptr++ = (uint8) regdata;
736 regaddr++;
737 }
738
739 /* Only the lower 17-bits are valid */
740 scratch = ltoh32(scratch);
741 scratch &= 0x0001FFFF;
742 return (scratch);
743}
744
745extern SDIOH_API_RC
746sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
747{
748 uint32 count;
749 int offset;
750 uint32 foo;
751 uint8 *cis = cisd;
752
753 sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
754
755 if (!sd->func_cis_ptr[func]) {
756 bzero(cis, length);
757 sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func));
758 return SDIOH_API_RC_FAIL;
759 }
760
761 sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func]));
762
763 for (count = 0; count < length; count++) {
764 offset = sd->func_cis_ptr[func] + count;
765 if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) {
766 sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
767 return SDIOH_API_RC_FAIL;
768 }
769
770 *cis = (uint8)(foo & 0xff);
771 cis++;
772 }
773
774 return SDIOH_API_RC_SUCCESS;
775}
776
777extern SDIOH_API_RC
778sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
779{
780 int err_ret;
781
782 sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr));
783
784 DHD_PM_RESUME_WAIT(sdioh_request_byte_wait);
785 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
786 if(rw) { /* CMD52 Write */
787 if (func == 0) {
788 /* Can only directly write to some F0 registers. Handle F2 enable
789 * as a special case.
790 */
791 if (regaddr == SDIOD_CCCR_IOEN) {
792 if (gInstance->func[2]) {
793 sdio_claim_host(gInstance->func[2]);
794 if (*byte & SDIO_FUNC_ENABLE_2) {
795 /* Enable Function 2 */
796 err_ret = sdio_enable_func(gInstance->func[2]);
797 if (err_ret) {
798 sd_err(("bcmsdh_sdmmc: enable F2 failed:%d",
799 err_ret));
800 }
801 } else {
802 /* Disable Function 2 */
803 err_ret = sdio_disable_func(gInstance->func[2]);
804 if (err_ret) {
805 sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d",
806 err_ret));
807 }
808 }
809 sdio_release_host(gInstance->func[2]);
810 }
811 }
812#if defined(MMC_SDIO_ABORT)
813 /* to allow abort command through F1 */
814 else if (regaddr == SDIOD_CCCR_IOABORT) {
815 sdio_claim_host(gInstance->func[func]);
816 /*
817 * this sdio_f0_writeb() can be replaced with another api
818 * depending upon MMC driver change.
819 * As of this time, this is temporaray one
820 */
821 sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
822 sdio_release_host(gInstance->func[func]);
823 }
824#endif /* MMC_SDIO_ABORT */
825 else if (regaddr < 0xF0) {
826 sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr));
827 } else {
828 /* Claim host controller, perform F0 write, and release */
829 sdio_claim_host(gInstance->func[func]);
830 sdio_f0_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
831 sdio_release_host(gInstance->func[func]);
832 }
833 } else {
834 /* Claim host controller, perform Fn write, and release */
835 sdio_claim_host(gInstance->func[func]);
836 sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
837 sdio_release_host(gInstance->func[func]);
838 }
839 } else { /* CMD52 Read */
840 /* Claim host controller, perform Fn read, and release */
841 sdio_claim_host(gInstance->func[func]);
842
843 if (func == 0) {
844 *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret);
845 } else {
846 *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret);
847 }
848
849 sdio_release_host(gInstance->func[func]);
850 }
851
852 if (err_ret) {
853 sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
854 rw ? "Write" : "Read", func, regaddr, *byte, err_ret));
855 }
856
857 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
858}
859
860extern SDIOH_API_RC
861sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
862 uint32 *word, uint nbytes)
863{
864 int err_ret = SDIOH_API_RC_FAIL;
865
866 if (func == 0) {
867 sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__));
868 return SDIOH_API_RC_FAIL;
869 }
870
871 sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
872 __FUNCTION__, cmd_type, rw, func, addr, nbytes));
873
874 DHD_PM_RESUME_WAIT(sdioh_request_word_wait);
875 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
876 /* Claim host controller */
877 sdio_claim_host(gInstance->func[func]);
878
879 if(rw) { /* CMD52 Write */
880 if (nbytes == 4) {
881 sdio_writel(gInstance->func[func], *word, addr, &err_ret);
882 } else if (nbytes == 2) {
883 sdio_writew(gInstance->func[func], (*word & 0xFFFF), addr, &err_ret);
884 } else {
885 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
886 }
887 } else { /* CMD52 Read */
888 if (nbytes == 4) {
889 *word = sdio_readl(gInstance->func[func], addr, &err_ret);
890 } else if (nbytes == 2) {
891 *word = sdio_readw(gInstance->func[func], addr, &err_ret) & 0xFFFF;
892 } else {
893 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
894 }
895 }
896
897 /* Release host controller */
898 sdio_release_host(gInstance->func[func]);
899
900 if (err_ret) {
901 sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
902 rw ? "Write" : "Read", err_ret));
903 }
904
905 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
906}
907
908static SDIOH_API_RC
909sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
910 uint addr, void *pkt)
911{
912 bool fifo = (fix_inc == SDIOH_DATA_FIX);
913 uint32 SGCount = 0;
914 int err_ret = 0;
915
916 void *pnext;
917
918 sd_trace(("%s: Enter\n", __FUNCTION__));
919
920 ASSERT(pkt);
921 DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
922 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
923
924 /* Claim host controller */
925 sdio_claim_host(gInstance->func[func]);
926 for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
927 uint pkt_len = PKTLEN(sd->osh, pnext);
928 pkt_len += 3;
929 pkt_len &= 0xFFFFFFFC;
930
931#ifdef CONFIG_MMC_MSM7X00A
932 if ((pkt_len % 64) == 32) {
933 sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
934 pkt_len += 32;
935 }
936#endif /* CONFIG_MMC_MSM7X00A */
937 /* Make sure the packet is aligned properly. If it isn't, then this
938 * is the fault of sdioh_request_buffer() which is supposed to give
939 * us something we can work with.
940 */
941 ASSERT(((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) == 0);
942
943 if ((write) && (!fifo)) {
944 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
945 ((uint8*)PKTDATA(sd->osh, pnext)),
946 pkt_len);
947 } else if (write) {
948 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
949 ((uint8*)PKTDATA(sd->osh, pnext)),
950 pkt_len);
951 } else if (fifo) {
952 err_ret = sdio_readsb(gInstance->func[func],
953 ((uint8*)PKTDATA(sd->osh, pnext)),
954 addr,
955 pkt_len);
956 } else {
957 err_ret = sdio_memcpy_fromio(gInstance->func[func],
958 ((uint8*)PKTDATA(sd->osh, pnext)),
959 addr,
960 pkt_len);
961 }
962
963 if (err_ret) {
964 sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
965 __FUNCTION__,
966 (write) ? "TX" : "RX",
967 pnext, SGCount, addr, pkt_len, err_ret));
968 } else {
969 sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
970 __FUNCTION__,
971 (write) ? "TX" : "RX",
972 pnext, SGCount, addr, pkt_len));
973 }
974
975 if (!fifo) {
976 addr += pkt_len;
977 }
978 SGCount ++;
979
980 }
981
982 /* Release host controller */
983 sdio_release_host(gInstance->func[func]);
984
985 sd_trace(("%s: Exit\n", __FUNCTION__));
986 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
987}
988
989
990/*
991 * This function takes a buffer or packet, and fixes everything up so that in the
992 * end, a DMA-able packet is created.
993 *
994 * A buffer does not have an associated packet pointer, and may or may not be aligned.
995 * A packet may consist of a single packet, or a packet chain. If it is a packet chain,
996 * then all the packets in the chain must be properly aligned. If the packet data is not
997 * aligned, then there may only be one packet, and in this case, it is copied to a new
998 * aligned packet.
999 *
1000 */
1001extern SDIOH_API_RC
1002sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func,
1003 uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
1004{
1005 SDIOH_API_RC Status;
1006 void *mypkt = NULL;
1007
1008 sd_trace(("%s: Enter\n", __FUNCTION__));
1009
1010 DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
1011 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
1012 /* Case 1: we don't have a packet. */
1013 if (pkt == NULL) {
1014 sd_data(("%s: Creating new %s Packet, len=%d\n",
1015 __FUNCTION__, write ? "TX" : "RX", buflen_u));
1016#ifdef DHD_USE_STATIC_BUF
1017 if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) {
1018#else
1019 if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) {
1020#endif /* DHD_USE_STATIC_BUF */
1021 sd_err(("%s: PKTGET failed: len %d\n",
1022 __FUNCTION__, buflen_u));
1023 return SDIOH_API_RC_FAIL;
1024 }
1025
1026 /* For a write, copy the buffer data into the packet. */
1027 if (write) {
1028 bcopy(buffer, PKTDATA(sd->osh, mypkt), buflen_u);
1029 }
1030
1031 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1032
1033 /* For a read, copy the packet data back to the buffer. */
1034 if (!write) {
1035 bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u);
1036 }
1037#ifdef DHD_USE_STATIC_BUF
1038 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
1039#else
1040 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
1041#endif /* DHD_USE_STATIC_BUF */
1042 } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) {
1043 /* Case 2: We have a packet, but it is unaligned. */
1044
1045 /* In this case, we cannot have a chain. */
1046 ASSERT(PKTNEXT(sd->osh, pkt) == NULL);
1047
1048 sd_data(("%s: Creating aligned %s Packet, len=%d\n",
1049 __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt)));
1050#ifdef DHD_USE_STATIC_BUF
1051 if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
1052#else
1053 if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
1054#endif /* DHD_USE_STATIC_BUF */
1055 sd_err(("%s: PKTGET failed: len %d\n",
1056 __FUNCTION__, PKTLEN(sd->osh, pkt)));
1057 return SDIOH_API_RC_FAIL;
1058 }
1059
1060 /* For a write, copy the buffer data into the packet. */
1061 if (write) {
1062 bcopy(PKTDATA(sd->osh, pkt),
1063 PKTDATA(sd->osh, mypkt),
1064 PKTLEN(sd->osh, pkt));
1065 }
1066
1067 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1068
1069 /* For a read, copy the packet data back to the buffer. */
1070 if (!write) {
1071 bcopy(PKTDATA(sd->osh, mypkt),
1072 PKTDATA(sd->osh, pkt),
1073 PKTLEN(sd->osh, mypkt));
1074 }
1075#ifdef DHD_USE_STATIC_BUF
1076 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
1077#else
1078 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
1079#endif /* DHD_USE_STATIC_BUF */
1080 } else { /* case 3: We have a packet and it is aligned. */
1081 sd_data(("%s: Aligned %s Packet, direct DMA\n",
1082 __FUNCTION__, write ? "Tx" : "Rx"));
1083 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, pkt);
1084 }
1085
1086 return (Status);
1087}
1088
1089/* this function performs "abort" for both of host & device */
1090extern int
1091sdioh_abort(sdioh_info_t *sd, uint func)
1092{
1093#if defined(MMC_SDIO_ABORT)
1094 char t_func = (char) func;
1095#endif /* defined(MMC_SDIO_ABORT) */
1096 sd_trace(("%s: Enter\n", __FUNCTION__));
1097
1098#if defined(MMC_SDIO_ABORT)
1099 /* issue abort cmd52 command through F1 */
1100 sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func);
1101#endif /* defined(MMC_SDIO_ABORT) */
1102
1103 sd_trace(("%s: Exit\n", __FUNCTION__));
1104 return SDIOH_API_RC_SUCCESS;
1105}
1106
1107/* Reset and re-initialize the device */
1108int sdioh_sdio_reset(sdioh_info_t *si)
1109{
1110 sd_trace(("%s: Enter\n", __FUNCTION__));
1111 sd_trace(("%s: Exit\n", __FUNCTION__));
1112 return SDIOH_API_RC_SUCCESS;
1113}
1114
1115/* Disable device interrupt */
1116void
1117sdioh_sdmmc_devintr_off(sdioh_info_t *sd)
1118{
1119 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1120 sd->intmask &= ~CLIENT_INTR;
1121}
1122
1123/* Enable device interrupt */
1124void
1125sdioh_sdmmc_devintr_on(sdioh_info_t *sd)
1126{
1127 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1128 sd->intmask |= CLIENT_INTR;
1129}
1130
1131/* Read client card reg */
1132int
1133sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
1134{
1135
1136 if ((func == 0) || (regsize == 1)) {
1137 uint8 temp = 0;
1138
1139 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1140 *data = temp;
1141 *data &= 0xff;
1142 sd_data(("%s: byte read data=0x%02x\n",
1143 __FUNCTION__, *data));
1144 } else {
1145 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize);
1146 if (regsize == 2)
1147 *data &= 0xffff;
1148
1149 sd_data(("%s: word read data=0x%08x\n",
1150 __FUNCTION__, *data));
1151 }
1152
1153 return SUCCESS;
1154}
1155
1156#if !defined(OOB_INTR_ONLY)
1157/* bcmsdh_sdmmc interrupt handler */
1158static void IRQHandler(struct sdio_func *func)
1159{
1160 sdioh_info_t *sd;
1161
1162 sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n"));
1163 sd = gInstance->sd;
1164
1165 ASSERT(sd != NULL);
1166 sdio_release_host(gInstance->func[0]);
1167
1168 if (sd->use_client_ints) {
1169 sd->intrcount++;
1170 ASSERT(sd->intr_handler);
1171 ASSERT(sd->intr_handler_arg);
1172 (sd->intr_handler)(sd->intr_handler_arg);
1173 } else {
1174 sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
1175
1176 sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
1177 __FUNCTION__, sd->client_intr_enabled, sd->intr_handler));
1178 }
1179
1180 sdio_claim_host(gInstance->func[0]);
1181}
1182
1183/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */
1184static void IRQHandlerF2(struct sdio_func *func)
1185{
1186 sdioh_info_t *sd;
1187
1188 sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n"));
1189
1190 sd = gInstance->sd;
1191
1192 ASSERT(sd != NULL);
1193}
1194#endif /* !defined(OOB_INTR_ONLY) */
1195
1196#ifdef NOTUSED
1197/* Write client card reg */
1198static int
1199sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data)
1200{
1201
1202 if ((func == 0) || (regsize == 1)) {
1203 uint8 temp;
1204
1205 temp = data & 0xff;
1206 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1207 sd_data(("%s: byte write data=0x%02x\n",
1208 __FUNCTION__, data));
1209 } else {
1210 if (regsize == 2)
1211 data &= 0xffff;
1212
1213 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize);
1214
1215 sd_data(("%s: word write data=0x%08x\n",
1216 __FUNCTION__, data));
1217 }
1218
1219 return SUCCESS;
1220}
1221#endif /* NOTUSED */
1222
1223int
1224sdioh_start(sdioh_info_t *si, int stage)
1225{
1226 int ret;
1227 sdioh_info_t *sd = gInstance->sd;
1228
1229 /* Need to do this stages as we can't enable the interrupt till
1230 downloading of the firmware is complete, other wise polling
1231 sdio access will come in way
1232 */
1233 if (gInstance->func[0]) {
1234 if (stage == 0) {
1235 /* Since the power to the chip is killed, we will have
1236 re enumerate the device again. Set the block size
1237 and enable the fucntion 1 for in preparation for
1238 downloading the code
1239 */
1240 /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux
1241 2.6.27. The implementation prior to that is buggy, and needs broadcom's
1242 patch for it
1243 */
1244 if ((ret = sdio_reset_comm(gInstance->func[0]->card)))
1245 sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
1246 else {
1247 sd->num_funcs = 2;
1248 sd->sd_blockmode = TRUE;
1249 sd->use_client_ints = TRUE;
1250 sd->client_block_size[0] = 64;
1251
1252 /* Claim host controller */
1253 sdio_claim_host(gInstance->func[1]);
1254
1255 sd->client_block_size[1] = 64;
1256 if (sdio_set_block_size(gInstance->func[1], 64)) {
1257 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
1258 }
1259
1260 /* Release host controller F1 */
1261 sdio_release_host(gInstance->func[1]);
1262
1263 if (gInstance->func[2]) {
1264 /* Claim host controller F2 */
1265 sdio_claim_host(gInstance->func[2]);
1266
1267 sd->client_block_size[2] = sd_f2_blocksize;
1268 if (sdio_set_block_size(gInstance->func[2],
1269 sd_f2_blocksize)) {
1270 sd_err(("bcmsdh_sdmmc: Failed to set F2 "
1271 "blocksize to %d\n", sd_f2_blocksize));
1272 }
1273
1274 /* Release host controller F2 */
1275 sdio_release_host(gInstance->func[2]);
1276 }
1277
1278 sdioh_sdmmc_card_enablefuncs(sd);
1279 }
1280 } else {
1281#if !defined(OOB_INTR_ONLY)
1282 sdio_claim_host(gInstance->func[0]);
1283 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
1284 sdio_claim_irq(gInstance->func[1], IRQHandler);
1285 sdio_release_host(gInstance->func[0]);
1286#else /* defined(OOB_INTR_ONLY) */
1287#if defined(HW_OOB)
1288 sdioh_enable_func_intr();
1289#endif
1290 bcmsdh_oob_intr_set(TRUE);
1291#endif /* !defined(OOB_INTR_ONLY) */
1292 }
1293 }
1294 else
1295 sd_err(("%s Failed\n", __FUNCTION__));
1296
1297 return (0);
1298}
1299
1300int
1301sdioh_stop(sdioh_info_t *si)
1302{
1303 /* MSM7201A Android sdio stack has bug with interrupt
1304 So internaly within SDIO stack they are polling
1305 which cause issue when device is turned off. So
1306 unregister interrupt with SDIO stack to stop the
1307 polling
1308 */
1309 if (gInstance->func[0]) {
1310#if !defined(OOB_INTR_ONLY)
1311 sdio_claim_host(gInstance->func[0]);
1312 sdio_release_irq(gInstance->func[1]);
1313 sdio_release_irq(gInstance->func[2]);
1314 sdio_release_host(gInstance->func[0]);
1315#else /* defined(OOB_INTR_ONLY) */
1316#if defined(HW_OOB)
1317 sdioh_disable_func_intr(0);
1318#endif
1319 bcmsdh_oob_intr_set(FALSE);
1320#endif /* !defined(OOB_INTR_ONLY) */
1321 }
1322 else
1323 sd_err(("%s Failed\n", __FUNCTION__));
1324 return (0);
1325}
1326
1327int
1328sdioh_waitlockfree(sdioh_info_t *sd)
1329{
1330 return (1);
1331}
diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
new file mode 100644
index 00000000000..1a370862b33
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c
@@ -0,0 +1,350 @@
1/*
2 * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmsdh_sdmmc_linux.c,v 1.8.6.2 2011-02-01 18:38:36 Exp $
25 */
26
27#include <typedefs.h>
28#include <bcmutils.h>
29#include <sdio.h> /* SDIO Device and Protocol Specs */
30#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
31#include <sdiovar.h> /* to get msglevel bit values */
32
33#include <linux/sched.h> /* request_irq() */
34
35#include <linux/mmc/core.h>
36#include <linux/mmc/card.h>
37#include <linux/mmc/sdio_func.h>
38#include <linux/mmc/sdio_ids.h>
39
40#if !defined(SDIO_VENDOR_ID_BROADCOM)
41#define SDIO_VENDOR_ID_BROADCOM 0x02d0
42#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */
43
44#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000
45
46#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB)
47#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */
48#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */
49#if !defined(SDIO_DEVICE_ID_BROADCOM_4325)
50#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493
51#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */
52#if !defined(SDIO_DEVICE_ID_BROADCOM_4319)
53#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319
54#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */
55#if !defined(SDIO_DEVICE_ID_BROADCOM_4330)
56#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330
57#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */
58
59#include <bcmsdh_sdmmc.h>
60
61#include <dhd_dbg.h>
62
63#ifdef WL_CFG80211
64extern void wl_cfg80211_set_sdio_func(void *func);
65#endif
66
67extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd);
68extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd);
69extern int dhd_os_check_wakelock(void *dhdp);
70extern int dhd_os_check_if_up(void *dhdp);
71extern void *bcmsdh_get_drvdata(void);
72
73int sdio_function_init(void);
74void sdio_function_cleanup(void);
75
76#define DESCRIPTION "bcmsdh_sdmmc Driver"
77#define AUTHOR "Broadcom Corporation"
78
79/* module param defaults */
80static int clockoverride = 0;
81
82module_param(clockoverride, int, 0644);
83MODULE_PARM_DESC(clockoverride, "SDIO card clock override");
84
85PBCMSDH_SDMMC_INSTANCE gInstance;
86
87/* Maximum number of bcmsdh_sdmmc devices supported by driver */
88#define BCMSDH_SDMMC_MAX_DEVICES 1
89
90extern int bcmsdh_probe_bcmdhd(struct device *dev);
91extern int bcmsdh_remove_bcmdhd(struct device *dev);
92
93extern volatile bool dhd_mmc_suspend;
94
95static int bcmsdh_sdmmc_probe(struct sdio_func *func,
96 const struct sdio_device_id *id)
97{
98 int ret = 0;
99 static struct sdio_func sdio_func_0;
100 sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__));
101 sd_trace(("sdio_bcmsdh: func->class=%x\n", func->class));
102 sd_trace(("sdio_vendor: 0x%04x\n", func->vendor));
103 sd_trace(("sdio_device: 0x%04x\n", func->device));
104 sd_trace(("Function#: 0x%04x\n", func->num));
105
106 if (func->num == 1) {
107 sdio_func_0.num = 0;
108 sdio_func_0.card = func->card;
109 gInstance->func[0] = &sdio_func_0;
110 if(func->device == 0x4) { /* 4318 */
111 gInstance->func[2] = NULL;
112 sd_trace(("NIC found, calling bcmsdh_probe_bcmdhd...\n"));
113 ret = bcmsdh_probe_bcmdhd(&func->dev);
114 }
115 }
116
117 gInstance->func[func->num] = func;
118
119 if (func->num == 2) {
120#ifdef WL_CFG80211
121 wl_cfg80211_set_sdio_func(func);
122#endif
123 sd_trace(("F2 found, calling bcmsdh_probe_bcmdhd...\n"));
124 ret = bcmsdh_probe_bcmdhd(&func->dev);
125 }
126
127 return ret;
128}
129
130static void bcmsdh_sdmmc_remove(struct sdio_func *func)
131{
132 sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__));
133 sd_info(("sdio_bcmsdh: func->class=%x\n", func->class));
134 sd_info(("sdio_vendor: 0x%04x\n", func->vendor));
135 sd_info(("sdio_device: 0x%04x\n", func->device));
136 sd_info(("Function#: 0x%04x\n", func->num));
137
138 if (func->num == 2) {
139 sd_trace(("F2 found, calling bcmsdh_remove_bcmdhd...\n"));
140 bcmsdh_remove_bcmdhd(&func->dev);
141 } else if (func->num == 1) {
142 sdio_claim_host(func);
143 sdio_disable_func(func);
144 sdio_release_host(func);
145 gInstance->func[1] = NULL;
146 }
147}
148
149/* devices we support, null terminated */
150static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
151 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) },
152 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) },
153 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) },
154 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) },
155 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) },
156 { /* end: all zeroes */ },
157};
158
159MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
160
161#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
162static int bcmsdh_sdmmc_suspend(struct device *pdev)
163{
164 struct sdio_func *func = dev_to_sdio_func(pdev);
165 mmc_pm_flag_t sdio_flags;
166 int ret = 0;
167
168 if (func->num != 2)
169 return 0;
170 if (dhd_os_check_wakelock(bcmsdh_get_drvdata()))
171 return -EBUSY;
172#if defined(OOB_INTR_ONLY)
173 bcmsdh_oob_intr_set(0);
174#endif
175 smp_mb();
176
177 sdio_flags = sdio_get_host_pm_caps(func);
178
179 if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
180 sd_err(("can't keep power while host "
181 "is suspended\n", __FUNCTION__));
182 ret = -EINVAL;
183 goto out;
184 }
185
186 /* keep power while host suspended */
187 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
188 if (ret) {
189 sd_err(("error while trying to keep power\n", __FUNCTION__));
190 goto out;
191 }
192
193 dhd_mmc_suspend = TRUE;
194
195out:
196 return ret;
197}
198
199static int bcmsdh_sdmmc_resume(struct device *pdev)
200{
201 struct sdio_func *func = dev_to_sdio_func(pdev);
202
203 if (func->num != 2)
204 return 0;
205 dhd_mmc_suspend = FALSE;
206#if defined(OOB_INTR_ONLY)
207 if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
208 bcmsdh_oob_intr_set(1);
209#endif
210 smp_mb();
211 return 0;
212}
213
214static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = {
215 .suspend = bcmsdh_sdmmc_suspend,
216 .resume = bcmsdh_sdmmc_resume,
217};
218#endif
219
220static struct sdio_driver bcmsdh_sdmmc_driver = {
221 .probe = bcmsdh_sdmmc_probe,
222 .remove = bcmsdh_sdmmc_remove,
223 .name = "bcmsdh_sdmmc",
224 .id_table = bcmsdh_sdmmc_ids,
225#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
226 .drv = {
227 .pm = &bcmsdh_sdmmc_pm_ops,
228 },
229#endif
230};
231
232struct sdos_info {
233 sdioh_info_t *sd;
234 spinlock_t lock;
235};
236
237
238int
239sdioh_sdmmc_osinit(sdioh_info_t *sd)
240{
241 struct sdos_info *sdos;
242
243 sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info));
244 sd->sdos_info = (void*)sdos;
245 if (sdos == NULL)
246 return BCME_NOMEM;
247
248 sdos->sd = sd;
249 spin_lock_init(&sdos->lock);
250 return BCME_OK;
251}
252
253void
254sdioh_sdmmc_osfree(sdioh_info_t *sd)
255{
256 struct sdos_info *sdos;
257 ASSERT(sd && sd->sdos_info);
258
259 sdos = (struct sdos_info *)sd->sdos_info;
260 MFREE(sd->osh, sdos, sizeof(struct sdos_info));
261}
262
263/* Interrupt enable/disable */
264SDIOH_API_RC
265sdioh_interrupt_set(sdioh_info_t *sd, bool enable)
266{
267 ulong flags;
268 struct sdos_info *sdos;
269
270 sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling"));
271
272 sdos = (struct sdos_info *)sd->sdos_info;
273 ASSERT(sdos);
274
275#if !defined(OOB_INTR_ONLY)
276 if (enable && !(sd->intr_handler && sd->intr_handler_arg)) {
277 sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__));
278 return SDIOH_API_RC_FAIL;
279 }
280#endif /* !defined(OOB_INTR_ONLY) */
281
282 /* Ensure atomicity for enable/disable calls */
283 spin_lock_irqsave(&sdos->lock, flags);
284
285 sd->client_intr_enabled = enable;
286 if (enable) {
287 sdioh_sdmmc_devintr_on(sd);
288 } else {
289 sdioh_sdmmc_devintr_off(sd);
290 }
291
292 spin_unlock_irqrestore(&sdos->lock, flags);
293
294 return SDIOH_API_RC_SUCCESS;
295}
296
297
298#ifdef BCMSDH_MODULE
299static int __init
300bcmsdh_module_init(void)
301{
302 int error = 0;
303 sdio_function_init();
304 return error;
305}
306
307static void __exit
308bcmsdh_module_cleanup(void)
309{
310 sdio_function_cleanup();
311}
312
313module_init(bcmsdh_module_init);
314module_exit(bcmsdh_module_cleanup);
315
316MODULE_LICENSE("GPL v2");
317MODULE_DESCRIPTION(DESCRIPTION);
318MODULE_AUTHOR(AUTHOR);
319
320#endif /* BCMSDH_MODULE */
321/*
322 * module init
323*/
324int sdio_function_init(void)
325{
326 int error = 0;
327 sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__));
328
329 gInstance = kzalloc(sizeof(BCMSDH_SDMMC_INSTANCE), GFP_KERNEL);
330 if (!gInstance)
331 return -ENOMEM;
332
333 error = sdio_register_driver(&bcmsdh_sdmmc_driver);
334
335 return error;
336}
337
338/*
339 * module cleanup
340*/
341void sdio_function_cleanup(void)
342{
343 sd_trace(("%s Enter\n", __FUNCTION__));
344
345
346 sdio_unregister_driver(&bcmsdh_sdmmc_driver);
347
348 if (gInstance)
349 kfree(gInstance);
350}
diff --git a/drivers/net/wireless/bcmdhd/bcmutils.c b/drivers/net/wireless/bcmdhd/bcmutils.c
new file mode 100644
index 00000000000..fbdd7cd2d19
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmutils.c
@@ -0,0 +1,1967 @@
1/*
2 * Driver O/S-independent utility routines
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 * $Id: bcmutils.c,v 1.277.2.18 2011-01-26 02:32:08 Exp $
24 */
25
26#include <typedefs.h>
27#include <bcmdefs.h>
28#include <stdarg.h>
29
30#ifdef BCMDRIVER
31
32#include <osl.h>
33#include <bcmutils.h>
34#include <siutils.h>
35
36#else /* !BCMDRIVER */
37
38#include <stdio.h>
39#include <string.h>
40#include <bcmutils.h>
41
42#if defined(BCMEXTSUP)
43#include <bcm_osl.h>
44#endif
45
46
47#endif /* !BCMDRIVER */
48
49#include <bcmendian.h>
50#include <bcmdevs.h>
51#include <proto/ethernet.h>
52#include <proto/vlan.h>
53#include <proto/bcmip.h>
54#include <proto/802.1d.h>
55#include <proto/802.11.h>
56
57void *_bcmutils_dummy_fn = NULL;
58
59#ifdef BCMDRIVER
60
61
62
63/* copy a pkt buffer chain into a buffer */
64uint
65pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
66{
67 uint n, ret = 0;
68
69 if (len < 0)
70 len = 4096; /* "infinite" */
71
72 /* skip 'offset' bytes */
73 for (; p && offset; p = PKTNEXT(osh, p)) {
74 if (offset < (uint)PKTLEN(osh, p))
75 break;
76 offset -= PKTLEN(osh, p);
77 }
78
79 if (!p)
80 return 0;
81
82 /* copy the data */
83 for (; p && len; p = PKTNEXT(osh, p)) {
84 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
85 bcopy(PKTDATA(osh, p) + offset, buf, n);
86 buf += n;
87 len -= n;
88 ret += n;
89 offset = 0;
90 }
91
92 return ret;
93}
94
95/* copy a buffer into a pkt buffer chain */
96uint
97pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
98{
99 uint n, ret = 0;
100
101 /* skip 'offset' bytes */
102 for (; p && offset; p = PKTNEXT(osh, p)) {
103 if (offset < (uint)PKTLEN(osh, p))
104 break;
105 offset -= PKTLEN(osh, p);
106 }
107
108 if (!p)
109 return 0;
110
111 /* copy the data */
112 for (; p && len; p = PKTNEXT(osh, p)) {
113 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
114 bcopy(buf, PKTDATA(osh, p) + offset, n);
115 buf += n;
116 len -= n;
117 ret += n;
118 offset = 0;
119 }
120
121 return ret;
122}
123
124
125
126/* return total length of buffer chain */
127uint BCMFASTPATH
128pkttotlen(osl_t *osh, void *p)
129{
130 uint total;
131
132 total = 0;
133 for (; p; p = PKTNEXT(osh, p))
134 total += PKTLEN(osh, p);
135 return (total);
136}
137
138/* return the last buffer of chained pkt */
139void *
140pktlast(osl_t *osh, void *p)
141{
142 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
143 ;
144
145 return (p);
146}
147
148/* count segments of a chained packet */
149uint BCMFASTPATH
150pktsegcnt(osl_t *osh, void *p)
151{
152 uint cnt;
153
154 for (cnt = 0; p; p = PKTNEXT(osh, p))
155 cnt++;
156
157 return cnt;
158}
159
160
161/*
162 * osl multiple-precedence packet queue
163 * hi_prec is always >= the number of the highest non-empty precedence
164 */
165void * BCMFASTPATH
166pktq_penq(struct pktq *pq, int prec, void *p)
167{
168 struct pktq_prec *q;
169
170 ASSERT(prec >= 0 && prec < pq->num_prec);
171 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
172
173 ASSERT(!pktq_full(pq));
174 ASSERT(!pktq_pfull(pq, prec));
175
176 q = &pq->q[prec];
177
178 if (q->head)
179 PKTSETLINK(q->tail, p);
180 else
181 q->head = p;
182
183 q->tail = p;
184 q->len++;
185
186 pq->len++;
187
188 if (pq->hi_prec < prec)
189 pq->hi_prec = (uint8)prec;
190
191 return p;
192}
193
194void * BCMFASTPATH
195pktq_penq_head(struct pktq *pq, int prec, void *p)
196{
197 struct pktq_prec *q;
198
199 ASSERT(prec >= 0 && prec < pq->num_prec);
200 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
201
202 ASSERT(!pktq_full(pq));
203 ASSERT(!pktq_pfull(pq, prec));
204
205 q = &pq->q[prec];
206
207 if (q->head == NULL)
208 q->tail = p;
209
210 PKTSETLINK(p, q->head);
211 q->head = p;
212 q->len++;
213
214 pq->len++;
215
216 if (pq->hi_prec < prec)
217 pq->hi_prec = (uint8)prec;
218
219 return p;
220}
221
222void * BCMFASTPATH
223pktq_pdeq(struct pktq *pq, int prec)
224{
225 struct pktq_prec *q;
226 void *p;
227
228 ASSERT(prec >= 0 && prec < pq->num_prec);
229
230 q = &pq->q[prec];
231
232 if ((p = q->head) == NULL)
233 return NULL;
234
235 if ((q->head = PKTLINK(p)) == NULL)
236 q->tail = NULL;
237
238 q->len--;
239
240 pq->len--;
241
242 PKTSETLINK(p, NULL);
243
244 return p;
245}
246
247void * BCMFASTPATH
248pktq_pdeq_tail(struct pktq *pq, int prec)
249{
250 struct pktq_prec *q;
251 void *p, *prev;
252
253 ASSERT(prec >= 0 && prec < pq->num_prec);
254
255 q = &pq->q[prec];
256
257 if ((p = q->head) == NULL)
258 return NULL;
259
260 for (prev = NULL; p != q->tail; p = PKTLINK(p))
261 prev = p;
262
263 if (prev)
264 PKTSETLINK(prev, NULL);
265 else
266 q->head = NULL;
267
268 q->tail = prev;
269 q->len--;
270
271 pq->len--;
272
273 return p;
274}
275
276void
277pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir, ifpkt_cb_t fn, int arg)
278{
279 struct pktq_prec *q;
280 void *p, *prev = NULL;
281
282 q = &pq->q[prec];
283 p = q->head;
284 while (p) {
285 if (fn == NULL || (*fn)(p, arg)) {
286 bool head = (p == q->head);
287 if (head)
288 q->head = PKTLINK(p);
289 else
290 PKTSETLINK(prev, PKTLINK(p));
291 PKTSETLINK(p, NULL);
292 PKTFREE(osh, p, dir);
293 q->len--;
294 pq->len--;
295 p = (head ? q->head : PKTLINK(prev));
296 } else {
297 prev = p;
298 p = PKTLINK(p);
299 }
300 }
301
302 if (q->head == NULL) {
303 ASSERT(q->len == 0);
304 q->tail = NULL;
305 }
306}
307
308bool BCMFASTPATH
309pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
310{
311 struct pktq_prec *q;
312 void *p;
313
314 ASSERT(prec >= 0 && prec < pq->num_prec);
315
316 if (!pktbuf)
317 return FALSE;
318
319 q = &pq->q[prec];
320
321 if (q->head == pktbuf) {
322 if ((q->head = PKTLINK(pktbuf)) == NULL)
323 q->tail = NULL;
324 } else {
325 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
326 ;
327 if (p == NULL)
328 return FALSE;
329
330 PKTSETLINK(p, PKTLINK(pktbuf));
331 if (q->tail == pktbuf)
332 q->tail = p;
333 }
334
335 q->len--;
336 pq->len--;
337 PKTSETLINK(pktbuf, NULL);
338 return TRUE;
339}
340
341void
342pktq_init(struct pktq *pq, int num_prec, int max_len)
343{
344 int prec;
345
346 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
347
348 /* pq is variable size; only zero out what's requested */
349 bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
350
351 pq->num_prec = (uint16)num_prec;
352
353 pq->max = (uint16)max_len;
354
355 for (prec = 0; prec < num_prec; prec++)
356 pq->q[prec].max = pq->max;
357}
358
359void * BCMFASTPATH
360pktq_deq(struct pktq *pq, int *prec_out)
361{
362 struct pktq_prec *q;
363 void *p;
364 int prec;
365
366 if (pq->len == 0)
367 return NULL;
368
369 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
370 pq->hi_prec--;
371
372 q = &pq->q[prec];
373
374 if ((p = q->head) == NULL)
375 return NULL;
376
377 if ((q->head = PKTLINK(p)) == NULL)
378 q->tail = NULL;
379
380 q->len--;
381
382 pq->len--;
383
384 if (prec_out)
385 *prec_out = prec;
386
387 PKTSETLINK(p, NULL);
388
389 return p;
390}
391
392void * BCMFASTPATH
393pktq_deq_tail(struct pktq *pq, int *prec_out)
394{
395 struct pktq_prec *q;
396 void *p, *prev;
397 int prec;
398
399 if (pq->len == 0)
400 return NULL;
401
402 for (prec = 0; prec < pq->hi_prec; prec++)
403 if (pq->q[prec].head)
404 break;
405
406 q = &pq->q[prec];
407
408 if ((p = q->head) == NULL)
409 return NULL;
410
411 for (prev = NULL; p != q->tail; p = PKTLINK(p))
412 prev = p;
413
414 if (prev)
415 PKTSETLINK(prev, NULL);
416 else
417 q->head = NULL;
418
419 q->tail = prev;
420 q->len--;
421
422 pq->len--;
423
424 if (prec_out)
425 *prec_out = prec;
426
427 PKTSETLINK(p, NULL);
428
429 return p;
430}
431
432void *
433pktq_peek(struct pktq *pq, int *prec_out)
434{
435 int prec;
436
437 if (pq->len == 0)
438 return NULL;
439
440 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
441 pq->hi_prec--;
442
443 if (prec_out)
444 *prec_out = prec;
445
446 return (pq->q[prec].head);
447}
448
449void *
450pktq_peek_tail(struct pktq *pq, int *prec_out)
451{
452 int prec;
453
454 if (pq->len == 0)
455 return NULL;
456
457 for (prec = 0; prec < pq->hi_prec; prec++)
458 if (pq->q[prec].head)
459 break;
460
461 if (prec_out)
462 *prec_out = prec;
463
464 return (pq->q[prec].tail);
465}
466
467void
468pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg)
469{
470 int prec;
471 for (prec = 0; prec < pq->num_prec; prec++)
472 pktq_pflush(osh, pq, prec, dir, fn, arg);
473 if (fn == NULL)
474 ASSERT(pq->len == 0);
475}
476
477/* Return sum of lengths of a specific set of precedences */
478int
479pktq_mlen(struct pktq *pq, uint prec_bmp)
480{
481 int prec, len;
482
483 len = 0;
484
485 for (prec = 0; prec <= pq->hi_prec; prec++)
486 if (prec_bmp & (1 << prec))
487 len += pq->q[prec].len;
488
489 return len;
490}
491
492/* Priority dequeue from a specific set of precedences */
493void * BCMFASTPATH
494pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
495{
496 struct pktq_prec *q;
497 void *p;
498 int prec;
499
500 if (pq->len == 0)
501 return NULL;
502
503 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
504 pq->hi_prec--;
505
506 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
507 if (prec-- == 0)
508 return NULL;
509
510 q = &pq->q[prec];
511
512 if ((p = q->head) == NULL)
513 return NULL;
514
515 if ((q->head = PKTLINK(p)) == NULL)
516 q->tail = NULL;
517
518 q->len--;
519
520 if (prec_out)
521 *prec_out = prec;
522
523 pq->len--;
524
525 PKTSETLINK(p, NULL);
526
527 return p;
528}
529
530#endif /* BCMDRIVER */
531
532const unsigned char bcm_ctype[] = {
533
534 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
535 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
536 _BCM_C, /* 8-15 */
537 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
538 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
539 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
540 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
541 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
542 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
543 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
544 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
545 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
546 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
547 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
548 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
549 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
550 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
551 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
552 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
553 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
554 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
555 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
556 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
557 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
558 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
559 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
560 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
561 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
562 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
563 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
564 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
565 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
566 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
567};
568
569ulong
570bcm_strtoul(char *cp, char **endp, uint base)
571{
572 ulong result, last_result = 0, value;
573 bool minus;
574
575 minus = FALSE;
576
577 while (bcm_isspace(*cp))
578 cp++;
579
580 if (cp[0] == '+')
581 cp++;
582 else if (cp[0] == '-') {
583 minus = TRUE;
584 cp++;
585 }
586
587 if (base == 0) {
588 if (cp[0] == '0') {
589 if ((cp[1] == 'x') || (cp[1] == 'X')) {
590 base = 16;
591 cp = &cp[2];
592 } else {
593 base = 8;
594 cp = &cp[1];
595 }
596 } else
597 base = 10;
598 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
599 cp = &cp[2];
600 }
601
602 result = 0;
603
604 while (bcm_isxdigit(*cp) &&
605 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base)
606 {
607 result = result*base + value;
608 /* Detected overflow */
609 if (result < last_result && !minus)
610 return (ulong)-1;
611 last_result = result;
612 cp++;
613 }
614
615 if (minus)
616 result = (ulong)(-(long)result);
617
618 if (endp)
619 *endp = (char *)cp;
620
621 return (result);
622}
623
624int
625bcm_atoi(char *s)
626{
627 return (int)bcm_strtoul(s, NULL, 10);
628}
629
630/* return pointer to location of substring 'needle' in 'haystack' */
631char*
632bcmstrstr(char *haystack, char *needle)
633{
634 int len, nlen;
635 int i;
636
637 if ((haystack == NULL) || (needle == NULL))
638 return (haystack);
639
640 nlen = strlen(needle);
641 len = strlen(haystack) - nlen + 1;
642
643 for (i = 0; i < len; i++)
644 if (memcmp(needle, &haystack[i], nlen) == 0)
645 return (&haystack[i]);
646 return (NULL);
647}
648
649char*
650bcmstrcat(char *dest, const char *src)
651{
652 char *p;
653
654 p = dest + strlen(dest);
655
656 while ((*p++ = *src++) != '\0')
657 ;
658
659 return (dest);
660}
661
662char*
663bcmstrncat(char *dest, const char *src, uint size)
664{
665 char *endp;
666 char *p;
667
668 p = dest + strlen(dest);
669 endp = p + size;
670
671 while (p != endp && (*p++ = *src++) != '\0')
672 ;
673
674 return (dest);
675}
676
677
678/****************************************************************************
679* Function: bcmstrtok
680*
681* Purpose:
682* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
683* but allows strToken() to be used by different strings or callers at the same
684* time. Each call modifies '*string' by substituting a NULL character for the
685* first delimiter that is encountered, and updates 'string' to point to the char
686* after the delimiter. Leading delimiters are skipped.
687*
688* Parameters:
689* string (mod) Ptr to string ptr, updated by token.
690* delimiters (in) Set of delimiter characters.
691* tokdelim (out) Character that delimits the returned token. (May
692* be set to NULL if token delimiter is not required).
693*
694* Returns: Pointer to the next token found. NULL when no more tokens are found.
695*****************************************************************************
696*/
697char *
698bcmstrtok(char **string, const char *delimiters, char *tokdelim)
699{
700 unsigned char *str;
701 unsigned long map[8];
702 int count;
703 char *nextoken;
704
705 if (tokdelim != NULL) {
706 /* Prime the token delimiter */
707 *tokdelim = '\0';
708 }
709
710 /* Clear control map */
711 for (count = 0; count < 8; count++) {
712 map[count] = 0;
713 }
714
715 /* Set bits in delimiter table */
716 do {
717 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
718 }
719 while (*delimiters++);
720
721 str = (unsigned char*)*string;
722
723 /* Find beginning of token (skip over leading delimiters). Note that
724 * there is no token iff this loop sets str to point to the terminal
725 * null (*str == '\0')
726 */
727 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
728 str++;
729 }
730
731 nextoken = (char*)str;
732
733 /* Find the end of the token. If it is not the end of the string,
734 * put a null there.
735 */
736 for (; *str; str++) {
737 if (map[*str >> 5] & (1 << (*str & 31))) {
738 if (tokdelim != NULL) {
739 *tokdelim = *str;
740 }
741
742 *str++ = '\0';
743 break;
744 }
745 }
746
747 *string = (char*)str;
748
749 /* Determine if a token has been found. */
750 if (nextoken == (char *) str) {
751 return NULL;
752 }
753 else {
754 return nextoken;
755 }
756}
757
758
759#define xToLower(C) \
760 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
761
762
763/****************************************************************************
764* Function: bcmstricmp
765*
766* Purpose: Compare to strings case insensitively.
767*
768* Parameters: s1 (in) First string to compare.
769* s2 (in) Second string to compare.
770*
771* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
772* t1 > t2, when ignoring case sensitivity.
773*****************************************************************************
774*/
775int
776bcmstricmp(const char *s1, const char *s2)
777{
778 char dc, sc;
779
780 while (*s2 && *s1) {
781 dc = xToLower(*s1);
782 sc = xToLower(*s2);
783 if (dc < sc) return -1;
784 if (dc > sc) return 1;
785 s1++;
786 s2++;
787 }
788
789 if (*s1 && !*s2) return 1;
790 if (!*s1 && *s2) return -1;
791 return 0;
792}
793
794
795/****************************************************************************
796* Function: bcmstrnicmp
797*
798* Purpose: Compare to strings case insensitively, upto a max of 'cnt'
799* characters.
800*
801* Parameters: s1 (in) First string to compare.
802* s2 (in) Second string to compare.
803* cnt (in) Max characters to compare.
804*
805* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
806* t1 > t2, when ignoring case sensitivity.
807*****************************************************************************
808*/
809int
810bcmstrnicmp(const char* s1, const char* s2, int cnt)
811{
812 char dc, sc;
813
814 while (*s2 && *s1 && cnt) {
815 dc = xToLower(*s1);
816 sc = xToLower(*s2);
817 if (dc < sc) return -1;
818 if (dc > sc) return 1;
819 s1++;
820 s2++;
821 cnt--;
822 }
823
824 if (!cnt) return 0;
825 if (*s1 && !*s2) return 1;
826 if (!*s1 && *s2) return -1;
827 return 0;
828}
829
830/* parse a xx:xx:xx:xx:xx:xx format ethernet address */
831int
832bcm_ether_atoe(char *p, struct ether_addr *ea)
833{
834 int i = 0;
835
836 for (;;) {
837 ea->octet[i++] = (char) bcm_strtoul(p, &p, 16);
838 if (!*p++ || i == 6)
839 break;
840 }
841
842 return (i == 6);
843}
844
845
846#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
847/* registry routine buffer preparation utility functions:
848 * parameter order is like strncpy, but returns count
849 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
850 */
851ulong
852wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
853{
854 ulong copyct = 1;
855 ushort i;
856
857 if (abuflen == 0)
858 return 0;
859
860 /* wbuflen is in bytes */
861 wbuflen /= sizeof(ushort);
862
863 for (i = 0; i < wbuflen; ++i) {
864 if (--abuflen == 0)
865 break;
866 *abuf++ = (char) *wbuf++;
867 ++copyct;
868 }
869 *abuf = '\0';
870
871 return copyct;
872}
873#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
874
875char *
876bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
877{
878 static const char template[] = "%02x:%02x:%02x:%02x:%02x:%02x";
879 snprintf(buf, 18, template,
880 ea->octet[0]&0xff, ea->octet[1]&0xff, ea->octet[2]&0xff,
881 ea->octet[3]&0xff, ea->octet[4]&0xff, ea->octet[5]&0xff);
882 return (buf);
883}
884
885char *
886bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
887{
888 snprintf(buf, 16, "%d.%d.%d.%d",
889 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
890 return (buf);
891}
892
893#ifdef BCMDRIVER
894
895void
896bcm_mdelay(uint ms)
897{
898 uint i;
899
900 for (i = 0; i < ms; i++) {
901 OSL_DELAY(1000);
902 }
903}
904
905
906
907
908
909#if defined(DHD_DEBUG)
910/* pretty hex print a pkt buffer chain */
911void
912prpkt(const char *msg, osl_t *osh, void *p0)
913{
914 void *p;
915
916 if (msg && (msg[0] != '\0'))
917 printf("%s:\n", msg);
918
919 for (p = p0; p; p = PKTNEXT(osh, p))
920 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
921}
922#endif
923
924/* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
925 * Also updates the inplace vlan tag if requested.
926 * For debugging, it returns an indication of what it did.
927 */
928uint BCMFASTPATH
929pktsetprio(void *pkt, bool update_vtag)
930{
931 struct ether_header *eh;
932 struct ethervlan_header *evh;
933 uint8 *pktdata;
934 int priority = 0;
935 int rc = 0;
936
937 pktdata = (uint8 *) PKTDATA(NULL, pkt);
938 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
939
940 eh = (struct ether_header *) pktdata;
941
942 if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
943 uint16 vlan_tag;
944 int vlan_prio, dscp_prio = 0;
945
946 evh = (struct ethervlan_header *)eh;
947
948 vlan_tag = ntoh16(evh->vlan_tag);
949 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
950
951 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
952 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
953 uint8 tos_tc = IP_TOS46(ip_body);
954 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
955 }
956
957 /* DSCP priority gets precedence over 802.1P (vlan tag) */
958 if (dscp_prio != 0) {
959 priority = dscp_prio;
960 rc |= PKTPRIO_VDSCP;
961 } else {
962 priority = vlan_prio;
963 rc |= PKTPRIO_VLAN;
964 }
965 /*
966 * If the DSCP priority is not the same as the VLAN priority,
967 * then overwrite the priority field in the vlan tag, with the
968 * DSCP priority value. This is required for Linux APs because
969 * the VLAN driver on Linux, overwrites the skb->priority field
970 * with the priority value in the vlan tag
971 */
972 if (update_vtag && (priority != vlan_prio)) {
973 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
974 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
975 evh->vlan_tag = hton16(vlan_tag);
976 rc |= PKTPRIO_UPD;
977 }
978 } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
979 uint8 *ip_body = pktdata + sizeof(struct ether_header);
980 uint8 tos_tc = IP_TOS46(ip_body);
981 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
982 rc |= PKTPRIO_DSCP;
983 }
984
985 ASSERT(priority >= 0 && priority <= MAXPRIO);
986 PKTSETPRIO(pkt, priority);
987 return (rc | priority);
988}
989
990#ifndef BCM_BOOTLOADER
991
992static char bcm_undeferrstr[32];
993static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
994
995/* Convert the error codes into related error strings */
996const char *
997bcmerrorstr(int bcmerror)
998{
999 /* check if someone added a bcmerror code but forgot to add errorstring */
1000 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
1001
1002 if (bcmerror > 0 || bcmerror < BCME_LAST) {
1003 snprintf(bcm_undeferrstr, sizeof(bcm_undeferrstr), "Undefined error %d", bcmerror);
1004 return bcm_undeferrstr;
1005 }
1006
1007 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
1008
1009 return bcmerrorstrtable[-bcmerror];
1010}
1011
1012#endif /* !BCM_BOOTLOADER */
1013
1014
1015
1016/* iovar table lookup */
1017const bcm_iovar_t*
1018bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
1019{
1020 const bcm_iovar_t *vi;
1021 const char *lookup_name;
1022
1023 /* skip any ':' delimited option prefixes */
1024 lookup_name = strrchr(name, ':');
1025 if (lookup_name != NULL)
1026 lookup_name++;
1027 else
1028 lookup_name = name;
1029
1030 ASSERT(table != NULL);
1031
1032 for (vi = table; vi->name; vi++) {
1033 if (!strcmp(vi->name, lookup_name))
1034 return vi;
1035 }
1036 /* ran to end of table */
1037
1038 return NULL; /* var name not found */
1039}
1040
1041int
1042bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1043{
1044 int bcmerror = 0;
1045
1046 /* length check on io buf */
1047 switch (vi->type) {
1048 case IOVT_BOOL:
1049 case IOVT_INT8:
1050 case IOVT_INT16:
1051 case IOVT_INT32:
1052 case IOVT_UINT8:
1053 case IOVT_UINT16:
1054 case IOVT_UINT32:
1055 /* all integers are int32 sized args at the ioctl interface */
1056 if (len < (int)sizeof(int)) {
1057 bcmerror = BCME_BUFTOOSHORT;
1058 }
1059 break;
1060
1061 case IOVT_BUFFER:
1062 /* buffer must meet minimum length requirement */
1063 if (len < vi->minlen) {
1064 bcmerror = BCME_BUFTOOSHORT;
1065 }
1066 break;
1067
1068 case IOVT_VOID:
1069 if (!set) {
1070 /* Cannot return nil... */
1071 bcmerror = BCME_UNSUPPORTED;
1072 } else if (len) {
1073 /* Set is an action w/o parameters */
1074 bcmerror = BCME_BUFTOOLONG;
1075 }
1076 break;
1077
1078 default:
1079 /* unknown type for length check in iovar info */
1080 ASSERT(0);
1081 bcmerror = BCME_UNSUPPORTED;
1082 }
1083
1084 return bcmerror;
1085}
1086
1087#endif /* BCMDRIVER */
1088
1089
1090/*******************************************************************************
1091 * crc8
1092 *
1093 * Computes a crc8 over the input data using the polynomial:
1094 *
1095 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1096 *
1097 * The caller provides the initial value (either CRC8_INIT_VALUE
1098 * or the previous returned value) to allow for processing of
1099 * discontiguous blocks of data. When generating the CRC the
1100 * caller is responsible for complementing the final return value
1101 * and inserting it into the byte stream. When checking, a final
1102 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1103 *
1104 * Reference: Dallas Semiconductor Application Note 27
1105 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1106 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1107 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1108 *
1109 * ****************************************************************************
1110 */
1111
1112static const uint8 crc8_table[256] = {
1113 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1114 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1115 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1116 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1117 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1118 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1119 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1120 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1121 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1122 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1123 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1124 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1125 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1126 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1127 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1128 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1129 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1130 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1131 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1132 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1133 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1134 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1135 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1136 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1137 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1138 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1139 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1140 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1141 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1142 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1143 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1144 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1145};
1146
1147#define CRC_INNER_LOOP(n, c, x) \
1148 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1149
1150uint8
1151hndcrc8(
1152 uint8 *pdata, /* pointer to array of data to process */
1153 uint nbytes, /* number of input data bytes to process */
1154 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1155)
1156{
1157 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1158 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1159 */
1160 while (nbytes-- > 0)
1161 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1162
1163 return crc;
1164}
1165
1166/*******************************************************************************
1167 * crc16
1168 *
1169 * Computes a crc16 over the input data using the polynomial:
1170 *
1171 * x^16 + x^12 +x^5 + 1
1172 *
1173 * The caller provides the initial value (either CRC16_INIT_VALUE
1174 * or the previous returned value) to allow for processing of
1175 * discontiguous blocks of data. When generating the CRC the
1176 * caller is responsible for complementing the final return value
1177 * and inserting it into the byte stream. When checking, a final
1178 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1179 *
1180 * Reference: Dallas Semiconductor Application Note 27
1181 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1182 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1183 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1184 *
1185 * ****************************************************************************
1186 */
1187
1188static const uint16 crc16_table[256] = {
1189 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1190 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1191 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1192 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1193 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1194 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1195 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1196 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1197 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1198 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1199 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1200 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1201 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1202 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1203 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1204 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1205 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1206 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1207 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1208 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1209 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1210 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1211 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1212 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1213 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1214 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1215 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1216 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1217 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1218 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1219 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1220 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1221};
1222
1223uint16
1224hndcrc16(
1225 uint8 *pdata, /* pointer to array of data to process */
1226 uint nbytes, /* number of input data bytes to process */
1227 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1228)
1229{
1230 while (nbytes-- > 0)
1231 CRC_INNER_LOOP(16, crc, *pdata++);
1232 return crc;
1233}
1234
1235static const uint32 crc32_table[256] = {
1236 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1237 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1238 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1239 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1240 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1241 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1242 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1243 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1244 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1245 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1246 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1247 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1248 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1249 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1250 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1251 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1252 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1253 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1254 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1255 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1256 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1257 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1258 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1259 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1260 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1261 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1262 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1263 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1264 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1265 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1266 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1267 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1268 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1269 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1270 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1271 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1272 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1273 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1274 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1275 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1276 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1277 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1278 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1279 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1280 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1281 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1282 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1283 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1284 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1285 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1286 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1287 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1288 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1289 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1290 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1291 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1292 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1293 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1294 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1295 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1296 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1297 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1298 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1299 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1300};
1301
1302/*
1303 * crc input is CRC32_INIT_VALUE for a fresh start, or previous return value if
1304 * accumulating over multiple pieces.
1305 */
1306uint32
1307hndcrc32(uint8 *pdata, uint nbytes, uint32 crc)
1308{
1309 uint8 *pend;
1310#ifdef __mips__
1311 uint8 tmp[4];
1312 ulong *tptr = (ulong *)tmp;
1313
1314 /* in case the beginning of the buffer isn't aligned */
1315 pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
1316 nbytes -= (pend - pdata);
1317 while (pdata < pend)
1318 CRC_INNER_LOOP(32, crc, *pdata++);
1319
1320 /* handle bulk of data as 32-bit words */
1321 pend = pdata + (nbytes & 0xfffffffc);
1322 while (pdata < pend) {
1323 *tptr = *(ulong *)pdata;
1324 pdata += sizeof(ulong *);
1325 CRC_INNER_LOOP(32, crc, tmp[0]);
1326 CRC_INNER_LOOP(32, crc, tmp[1]);
1327 CRC_INNER_LOOP(32, crc, tmp[2]);
1328 CRC_INNER_LOOP(32, crc, tmp[3]);
1329 }
1330
1331 /* 1-3 bytes at end of buffer */
1332 pend = pdata + (nbytes & 0x03);
1333 while (pdata < pend)
1334 CRC_INNER_LOOP(32, crc, *pdata++);
1335#else
1336 pend = pdata + nbytes;
1337 while (pdata < pend)
1338 CRC_INNER_LOOP(32, crc, *pdata++);
1339#endif /* __mips__ */
1340
1341 return crc;
1342}
1343
1344#ifdef notdef
1345#define CLEN 1499 /* CRC Length */
1346#define CBUFSIZ (CLEN+4)
1347#define CNBUFS 5 /* # of bufs */
1348
1349void
1350testcrc32(void)
1351{
1352 uint j, k, l;
1353 uint8 *buf;
1354 uint len[CNBUFS];
1355 uint32 crcr;
1356 uint32 crc32tv[CNBUFS] =
1357 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1358
1359 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1360
1361 /* step through all possible alignments */
1362 for (l = 0; l <= 4; l++) {
1363 for (j = 0; j < CNBUFS; j++) {
1364 len[j] = CLEN;
1365 for (k = 0; k < len[j]; k++)
1366 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1367 }
1368
1369 for (j = 0; j < CNBUFS; j++) {
1370 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1371 ASSERT(crcr == crc32tv[j]);
1372 }
1373 }
1374
1375 MFREE(buf, CBUFSIZ*CNBUFS);
1376 return;
1377}
1378#endif /* notdef */
1379
1380/*
1381 * Advance from the current 1-byte tag/1-byte length/variable-length value
1382 * triple, to the next, returning a pointer to the next.
1383 * If the current or next TLV is invalid (does not fit in given buffer length),
1384 * NULL is returned.
1385 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1386 * by the TLV parameter's length if it is valid.
1387 */
1388bcm_tlv_t *
1389bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
1390{
1391 int len;
1392
1393 /* validate current elt */
1394 if (!bcm_valid_tlv(elt, *buflen))
1395 return NULL;
1396
1397 /* advance to next elt */
1398 len = elt->len;
1399 elt = (bcm_tlv_t*)(elt->data + len);
1400 *buflen -= (2 + len);
1401
1402 /* validate next elt */
1403 if (!bcm_valid_tlv(elt, *buflen))
1404 return NULL;
1405
1406 return elt;
1407}
1408
1409/*
1410 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1411 * triples, returning a pointer to the substring whose first element
1412 * matches tag
1413 */
1414bcm_tlv_t *
1415bcm_parse_tlvs(void *buf, int buflen, uint key)
1416{
1417 bcm_tlv_t *elt;
1418 int totlen;
1419
1420 elt = (bcm_tlv_t*)buf;
1421 totlen = buflen;
1422
1423 /* find tagged parameter */
1424 while (totlen >= 2) {
1425 int len = elt->len;
1426
1427 /* validate remaining totlen */
1428 if ((elt->id == key) && (totlen >= (len + 2)))
1429 return (elt);
1430
1431 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1432 totlen -= (len + 2);
1433 }
1434
1435 return NULL;
1436}
1437
1438/*
1439 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1440 * triples, returning a pointer to the substring whose first element
1441 * matches tag. Stop parsing when we see an element whose ID is greater
1442 * than the target key.
1443 */
1444bcm_tlv_t *
1445bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
1446{
1447 bcm_tlv_t *elt;
1448 int totlen;
1449
1450 elt = (bcm_tlv_t*)buf;
1451 totlen = buflen;
1452
1453 /* find tagged parameter */
1454 while (totlen >= 2) {
1455 uint id = elt->id;
1456 int len = elt->len;
1457
1458 /* Punt if we start seeing IDs > than target key */
1459 if (id > key)
1460 return (NULL);
1461
1462 /* validate remaining totlen */
1463 if ((id == key) && (totlen >= (len + 2)))
1464 return (elt);
1465
1466 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1467 totlen -= (len + 2);
1468 }
1469 return NULL;
1470}
1471
1472#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1473 defined(DHD_DEBUG)
1474int
1475bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
1476{
1477 int i;
1478 char* p = buf;
1479 char hexstr[16];
1480 int slen = 0, nlen = 0;
1481 uint32 bit;
1482 const char* name;
1483
1484 if (len < 2 || !buf)
1485 return 0;
1486
1487 buf[0] = '\0';
1488
1489 for (i = 0; flags != 0; i++) {
1490 bit = bd[i].bit;
1491 name = bd[i].name;
1492 if (bit == 0 && flags != 0) {
1493 /* print any unnamed bits */
1494 snprintf(hexstr, 16, "0x%X", flags);
1495 name = hexstr;
1496 flags = 0; /* exit loop */
1497 } else if ((flags & bit) == 0)
1498 continue;
1499 flags &= ~bit;
1500 nlen = strlen(name);
1501 slen += nlen;
1502 /* count btwn flag space */
1503 if (flags != 0)
1504 slen += 1;
1505 /* need NULL char as well */
1506 if (len <= slen)
1507 break;
1508 /* copy NULL char but don't count it */
1509 strncpy(p, name, nlen + 1);
1510 p += nlen;
1511 /* copy btwn flag space and NULL char */
1512 if (flags != 0)
1513 p += snprintf(p, 2, " ");
1514 len -= slen;
1515 }
1516
1517 /* indicate the str was too short */
1518 if (flags != 0) {
1519 if (len < 2)
1520 p -= 2 - len; /* overwrite last char */
1521 p += snprintf(p, 2, ">");
1522 }
1523
1524 return (int)(p - buf);
1525}
1526#endif
1527
1528#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1529 defined(DHD_DEBUG) || defined(WLMEDIA_PEAKRATE)
1530/* print bytes formatted as hex to a string. return the resulting string length */
1531int
1532bcm_format_hex(char *str, const void *bytes, int len)
1533{
1534 int i;
1535 char *p = str;
1536 const uint8 *src = (const uint8*)bytes;
1537
1538 for (i = 0; i < len; i++) {
1539 p += snprintf(p, 3, "%02X", *src);
1540 src++;
1541 }
1542 return (int)(p - str);
1543}
1544#endif
1545
1546/* pretty hex print a contiguous buffer */
1547void
1548prhex(const char *msg, uchar *buf, uint nbytes)
1549{
1550 char line[128], *p;
1551 int len = sizeof(line);
1552 int nchar;
1553 uint i;
1554
1555 if (msg && (msg[0] != '\0'))
1556 printf("%s:\n", msg);
1557
1558 p = line;
1559 for (i = 0; i < nbytes; i++) {
1560 if (i % 16 == 0) {
1561 nchar = snprintf(p, len, " %04d: ", i); /* line prefix */
1562 p += nchar;
1563 len -= nchar;
1564 }
1565 if (len > 0) {
1566 nchar = snprintf(p, len, "%02x ", buf[i]);
1567 p += nchar;
1568 len -= nchar;
1569 }
1570
1571 if (i % 16 == 15) {
1572 printf("%s\n", line); /* flush line */
1573 p = line;
1574 len = sizeof(line);
1575 }
1576 }
1577
1578 /* flush last partial line */
1579 if (p != line)
1580 printf("%s\n", line);
1581}
1582
1583static const char *crypto_algo_names[] = {
1584 "NONE",
1585 "WEP1",
1586 "TKIP",
1587 "WEP128",
1588 "AES_CCM",
1589 "AES_OCB_MSDU",
1590 "AES_OCB_MPDU",
1591 "NALG"
1592 "UNDEF",
1593 "UNDEF",
1594 "UNDEF",
1595 "UNDEF"
1596};
1597
1598const char *
1599bcm_crypto_algo_name(uint algo)
1600{
1601 return (algo < ARRAYSIZE(crypto_algo_names)) ? crypto_algo_names[algo] : "ERR";
1602}
1603
1604
1605char *
1606bcm_chipname(uint chipid, char *buf, uint len)
1607{
1608 const char *fmt;
1609
1610 fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
1611 snprintf(buf, len, fmt, chipid);
1612 return buf;
1613}
1614
1615/* Produce a human-readable string for boardrev */
1616char *
1617bcm_brev_str(uint32 brev, char *buf)
1618{
1619 if (brev < 0x100)
1620 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1621 else
1622 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1623
1624 return (buf);
1625}
1626
1627#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1628
1629/* dump large strings to console */
1630void
1631printbig(char *buf)
1632{
1633 uint len, max_len;
1634 char c;
1635
1636 len = strlen(buf);
1637
1638 max_len = BUFSIZE_TODUMP_ATONCE;
1639
1640 while (len > max_len) {
1641 c = buf[max_len];
1642 buf[max_len] = '\0';
1643 printf("%s", buf);
1644 buf[max_len] = c;
1645
1646 buf += max_len;
1647 len -= max_len;
1648 }
1649 /* print the remaining string */
1650 printf("%s\n", buf);
1651 return;
1652}
1653
1654/* routine to dump fields in a fileddesc structure */
1655uint
1656bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
1657 char *buf, uint32 bufsize)
1658{
1659 uint filled_len;
1660 int len;
1661 struct fielddesc *cur_ptr;
1662
1663 filled_len = 0;
1664 cur_ptr = fielddesc_array;
1665
1666 while (bufsize > 1) {
1667 if (cur_ptr->nameandfmt == NULL)
1668 break;
1669 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1670 read_rtn(arg0, arg1, cur_ptr->offset));
1671 /* check for snprintf overflow or error */
1672 if (len < 0 || (uint32)len >= bufsize)
1673 len = bufsize - 1;
1674 buf += len;
1675 bufsize -= len;
1676 filled_len += len;
1677 cur_ptr++;
1678 }
1679 return filled_len;
1680}
1681
1682uint
1683bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1684{
1685 uint len;
1686
1687 len = strlen(name) + 1;
1688
1689 if ((len + datalen) > buflen)
1690 return 0;
1691
1692 strncpy(buf, name, buflen);
1693
1694 /* append data onto the end of the name string */
1695 memcpy(&buf[len], data, datalen);
1696 len += datalen;
1697
1698 return len;
1699}
1700
1701/* Quarter dBm units to mW
1702 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1703 * Table is offset so the last entry is largest mW value that fits in
1704 * a uint16.
1705 */
1706
1707#define QDBM_OFFSET 153 /* Offset for first entry */
1708#define QDBM_TABLE_LEN 40 /* Table size */
1709
1710/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1711 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1712 */
1713#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1714
1715/* Largest mW value that will round down to the last table entry,
1716 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1717 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1718 */
1719#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1720
1721static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1722/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1723/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1724/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1725/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1726/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1727/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1728};
1729
1730uint16
1731bcm_qdbm_to_mw(uint8 qdbm)
1732{
1733 uint factor = 1;
1734 int idx = qdbm - QDBM_OFFSET;
1735
1736 if (idx >= QDBM_TABLE_LEN) {
1737 /* clamp to max uint16 mW value */
1738 return 0xFFFF;
1739 }
1740
1741 /* scale the qdBm index up to the range of the table 0-40
1742 * where an offset of 40 qdBm equals a factor of 10 mW.
1743 */
1744 while (idx < 0) {
1745 idx += 40;
1746 factor *= 10;
1747 }
1748
1749 /* return the mW value scaled down to the correct factor of 10,
1750 * adding in factor/2 to get proper rounding.
1751 */
1752 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
1753}
1754
1755uint8
1756bcm_mw_to_qdbm(uint16 mw)
1757{
1758 uint8 qdbm;
1759 int offset;
1760 uint mw_uint = mw;
1761 uint boundary;
1762
1763 /* handle boundary case */
1764 if (mw_uint <= 1)
1765 return 0;
1766
1767 offset = QDBM_OFFSET;
1768
1769 /* move mw into the range of the table */
1770 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1771 mw_uint *= 10;
1772 offset -= 40;
1773 }
1774
1775 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
1776 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
1777 nqdBm_to_mW_map[qdbm])/2;
1778 if (mw_uint < boundary)
1779 break;
1780 }
1781
1782 qdbm += (uint8)offset;
1783
1784 return (qdbm);
1785}
1786
1787
1788uint
1789bcm_bitcount(uint8 *bitmap, uint length)
1790{
1791 uint bitcount = 0, i;
1792 uint8 tmp;
1793 for (i = 0; i < length; i++) {
1794 tmp = bitmap[i];
1795 while (tmp) {
1796 bitcount++;
1797 tmp &= (tmp - 1);
1798 }
1799 }
1800 return bitcount;
1801}
1802
1803#ifdef BCMDRIVER
1804
1805/* Initialization of bcmstrbuf structure */
1806void
1807bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1808{
1809 b->origsize = b->size = size;
1810 b->origbuf = b->buf = buf;
1811}
1812
1813/* Buffer sprintf wrapper to guard against buffer overflow */
1814int
1815bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1816{
1817 va_list ap;
1818 int r;
1819
1820 va_start(ap, fmt);
1821 r = vsnprintf(b->buf, b->size, fmt, ap);
1822
1823 /* Non Ansi C99 compliant returns -1,
1824 * Ansi compliant return r >= b->size,
1825 * bcmstdlib returns 0, handle all
1826 */
1827 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1828 b->size = 0;
1829 } else {
1830 b->size -= r;
1831 b->buf += r;
1832 }
1833
1834 va_end(ap);
1835
1836 return r;
1837}
1838
1839void
1840bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
1841{
1842 int i;
1843
1844 for (i = 0; i < num_bytes; i++) {
1845 num[i] += amount;
1846 if (num[i] >= amount)
1847 break;
1848 amount = 1;
1849 }
1850}
1851
1852int
1853bcm_cmp_bytes(uchar *arg1, uchar *arg2, uint8 nbytes)
1854{
1855 int i;
1856
1857 for (i = nbytes - 1; i >= 0; i--) {
1858 if (arg1[i] != arg2[i])
1859 return (arg1[i] - arg2[i]);
1860 }
1861 return 0;
1862}
1863
1864void
1865bcm_print_bytes(char *name, const uchar *data, int len)
1866{
1867 int i;
1868 int per_line = 0;
1869
1870 printf("%s: %d \n", name ? name : "", len);
1871 for (i = 0; i < len; i++) {
1872 printf("%02x ", *data++);
1873 per_line++;
1874 if (per_line == 16) {
1875 per_line = 0;
1876 printf("\n");
1877 }
1878 }
1879 printf("\n");
1880}
1881#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
1882 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
1883#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
1884
1885int
1886bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
1887{
1888 uint i, c;
1889 char *p = buf;
1890 char *endp = buf + SSID_FMT_BUF_LEN;
1891
1892 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
1893
1894 for (i = 0; i < ssid_len; i++) {
1895 c = (uint)ssid[i];
1896 if (c == '\\') {
1897 *p++ = '\\';
1898 *p++ = '\\';
1899 } else if (bcm_isprint((uchar)c)) {
1900 *p++ = (char)c;
1901 } else {
1902 p += snprintf(p, (endp - p), "\\x%02X", c);
1903 }
1904 }
1905 *p = '\0';
1906 ASSERT(p < endp);
1907
1908 return (int)(p - buf);
1909}
1910#endif
1911
1912#endif /* BCMDRIVER */
1913
1914/*
1915 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
1916 * also accepts nvram files which are already in the format of <var1>=<value>\0\<var2>=<value2>\0
1917 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
1918 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
1919*/
1920
1921unsigned int
1922process_nvram_vars(char *varbuf, unsigned int len)
1923{
1924 char *dp;
1925 bool findNewline;
1926 int column;
1927 unsigned int buf_len, n;
1928 unsigned int pad = 0;
1929
1930 dp = varbuf;
1931
1932 findNewline = FALSE;
1933 column = 0;
1934
1935 for (n = 0; n < len; n++) {
1936 if (varbuf[n] == '\r')
1937 continue;
1938 if (findNewline && varbuf[n] != '\n')
1939 continue;
1940 findNewline = FALSE;
1941 if (varbuf[n] == '#') {
1942 findNewline = TRUE;
1943 continue;
1944 }
1945 if (varbuf[n] == '\n') {
1946 if (column == 0)
1947 continue;
1948 *dp++ = 0;
1949 column = 0;
1950 continue;
1951 }
1952 *dp++ = varbuf[n];
1953 column++;
1954 }
1955 buf_len = (unsigned int)(dp - varbuf);
1956 if (buf_len % 4) {
1957 pad = 4 - buf_len % 4;
1958 if (pad && (buf_len + pad <= len)) {
1959 buf_len += pad;
1960 }
1961 }
1962
1963 while (dp < varbuf + n)
1964 *dp++ = 0;
1965
1966 return buf_len;
1967}
diff --git a/drivers/net/wireless/bcmdhd/bcmwifi.c b/drivers/net/wireless/bcmdhd/bcmwifi.c
new file mode 100644
index 00000000000..70722170bdf
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/bcmwifi.c
@@ -0,0 +1,274 @@
1/*
2 * Misc utility routines used by kernel or app-level.
3 * Contents are wifi-specific, used by any kernel or app-level
4 * software that might want wifi things as it grows.
5 *
6 * Copyright (C) 1999-2011, Broadcom Corporation
7 *
8 * Unless you and Broadcom execute a separate written software license
9 * agreement governing use of this software, this software is licensed to you
10 * under the terms of the GNU General Public License version 2 (the "GPL"),
11 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
12 * following added to such license:
13 *
14 * As a special exception, the copyright holders of this software give you
15 * permission to link this software with independent modules, and to copy and
16 * distribute the resulting executable under terms of your choice, provided that
17 * you also meet, for each linked independent module, the terms and conditions of
18 * the license of that module. An independent module is a module which is not
19 * derived from this software. The special exception does not apply to any
20 * modifications of the software.
21 *
22 * Notwithstanding the above, under no circumstances may you combine this
23 * software in any way with any other Broadcom software provided under a license
24 * other than the GPL, without Broadcom's express prior written consent.
25 * $Id: bcmwifi.c,v 1.31.8.1 2010-08-03 17:47:05 Exp $
26 */
27
28
29#include <typedefs.h>
30
31#ifdef BCMDRIVER
32#include <osl.h>
33#include <bcmutils.h>
34#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
35#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
36#else
37#include <stdio.h>
38#include <stdlib.h>
39#include <ctype.h>
40#ifndef ASSERT
41#define ASSERT(exp)
42#endif
43#endif
44#include <bcmwifi.h>
45
46#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
47#include <bcmstdlib.h>
48#endif
49
50
51
52
53
54char *
55wf_chspec_ntoa(chanspec_t chspec, char *buf)
56{
57 const char *band, *bw, *sb;
58 uint channel;
59
60 band = "";
61 bw = "";
62 sb = "";
63 channel = CHSPEC_CHANNEL(chspec);
64
65 if ((CHSPEC_IS2G(chspec) && channel > CH_MAX_2G_CHANNEL) ||
66 (CHSPEC_IS5G(chspec) && channel <= CH_MAX_2G_CHANNEL))
67 band = (CHSPEC_IS2G(chspec)) ? "b" : "a";
68 if (CHSPEC_IS40(chspec)) {
69 if (CHSPEC_SB_UPPER(chspec)) {
70 sb = "u";
71 channel += CH_10MHZ_APART;
72 } else {
73 sb = "l";
74 channel -= CH_10MHZ_APART;
75 }
76 } else if (CHSPEC_IS10(chspec)) {
77 bw = "n";
78 }
79
80
81 snprintf(buf, 6, "%d%s%s%s", channel, band, bw, sb);
82 return (buf);
83}
84
85
86chanspec_t
87wf_chspec_aton(char *a)
88{
89 char *endp = NULL;
90 uint channel, band, bw, ctl_sb;
91 char c;
92
93 channel = strtoul(a, &endp, 10);
94
95
96 if (endp == a)
97 return 0;
98
99 if (channel > MAXCHANNEL)
100 return 0;
101
102 band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
103 bw = WL_CHANSPEC_BW_20;
104 ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
105
106 a = endp;
107
108 c = tolower(a[0]);
109 if (c == '\0')
110 goto done;
111
112
113 if (c == 'a' || c == 'b') {
114 band = (c == 'a') ? WL_CHANSPEC_BAND_5G : WL_CHANSPEC_BAND_2G;
115 a++;
116 c = tolower(a[0]);
117 if (c == '\0')
118 goto done;
119 }
120
121
122 if (c == 'n') {
123 bw = WL_CHANSPEC_BW_10;
124 } else if (c == 'l') {
125 bw = WL_CHANSPEC_BW_40;
126 ctl_sb = WL_CHANSPEC_CTL_SB_LOWER;
127
128 if (channel <= (MAXCHANNEL - CH_20MHZ_APART))
129 channel += CH_10MHZ_APART;
130 else
131 return 0;
132 } else if (c == 'u') {
133 bw = WL_CHANSPEC_BW_40;
134 ctl_sb = WL_CHANSPEC_CTL_SB_UPPER;
135
136 if (channel > CH_20MHZ_APART)
137 channel -= CH_10MHZ_APART;
138 else
139 return 0;
140 } else {
141 return 0;
142 }
143
144done:
145 return (channel | band | bw | ctl_sb);
146}
147
148
149bool
150wf_chspec_malformed(chanspec_t chanspec)
151{
152
153 if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec))
154 return TRUE;
155
156 if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec))
157 return TRUE;
158
159
160 if (CHSPEC_IS20_UNCOND(chanspec)) {
161 if (!CHSPEC_SB_NONE(chanspec))
162 return TRUE;
163 } else {
164 if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec))
165 return TRUE;
166 }
167
168 return FALSE;
169}
170
171
172uint8
173wf_chspec_ctlchan(chanspec_t chspec)
174{
175 uint8 ctl_chan;
176
177
178 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) {
179 return CHSPEC_CHANNEL(chspec);
180 } else {
181
182 ASSERT(CHSPEC_BW(chspec) == WL_CHANSPEC_BW_40);
183
184 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) {
185
186 ctl_chan = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
187 } else {
188 ASSERT(CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_LOWER);
189
190 ctl_chan = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
191 }
192 }
193
194 return ctl_chan;
195}
196
197chanspec_t
198wf_chspec_ctlchspec(chanspec_t chspec)
199{
200 chanspec_t ctl_chspec = 0;
201 uint8 channel;
202
203 ASSERT(!wf_chspec_malformed(chspec));
204
205
206 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) {
207 return chspec;
208 } else {
209 if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) {
210 channel = UPPER_20_SB(CHSPEC_CHANNEL(chspec));
211 } else {
212 channel = LOWER_20_SB(CHSPEC_CHANNEL(chspec));
213 }
214 ctl_chspec = channel | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE;
215 ctl_chspec |= CHSPEC_BAND(chspec);
216 }
217 return ctl_chspec;
218}
219
220
221int
222wf_mhz2channel(uint freq, uint start_factor)
223{
224 int ch = -1;
225 uint base;
226 int offset;
227
228
229 if (start_factor == 0) {
230 if (freq >= 2400 && freq <= 2500)
231 start_factor = WF_CHAN_FACTOR_2_4_G;
232 else if (freq >= 5000 && freq <= 6000)
233 start_factor = WF_CHAN_FACTOR_5_G;
234 }
235
236 if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G)
237 return 14;
238
239 base = start_factor / 2;
240
241
242 if ((freq < base) || (freq > base + 1000))
243 return -1;
244
245 offset = freq - base;
246 ch = offset / 5;
247
248
249 if (offset != (ch * 5))
250 return -1;
251
252
253 if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13))
254 return -1;
255
256 return ch;
257}
258
259
260int
261wf_channel2mhz(uint ch, uint start_factor)
262{
263 int freq;
264
265 if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) ||
266 (ch > 200))
267 freq = -1;
268 else if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14))
269 freq = 2484;
270 else
271 freq = ch * 5 + start_factor / 2;
272
273 return freq;
274}
diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h
new file mode 100644
index 00000000000..1b7242d4828
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd.h
@@ -0,0 +1,733 @@
1/*
2 * Header file describing the internal (inter-module) DHD interfaces.
3 *
4 * Provides type definitions and function prototypes used to link the
5 * DHD OS, bus, and protocol modules.
6 *
7 * Copyright (C) 1999-2011, Broadcom Corporation
8 *
9 * Unless you and Broadcom execute a separate written software license
10 * agreement governing use of this software, this software is licensed to you
11 * under the terms of the GNU General Public License version 2 (the "GPL"),
12 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
13 * following added to such license:
14 *
15 * As a special exception, the copyright holders of this software give you
16 * permission to link this software with independent modules, and to copy and
17 * distribute the resulting executable under terms of your choice, provided that
18 * you also meet, for each linked independent module, the terms and conditions of
19 * the license of that module. An independent module is a module which is not
20 * derived from this software. The special exception does not apply to any
21 * modifications of the software.
22 *
23 * Notwithstanding the above, under no circumstances may you combine this
24 * software in any way with any other Broadcom software provided under a license
25 * other than the GPL, without Broadcom's express prior written consent.
26 *
27 * $Id: dhd.h 290844 2011-10-20 08:54:39Z $
28 */
29
30/****************
31 * Common types *
32 */
33
34#ifndef _dhd_h_
35#define _dhd_h_
36
37#if defined(CHROMIUMOS_COMPAT_WIRELESS)
38#include <linux/sched.h>
39#endif
40#include <linux/init.h>
41#include <linux/kernel.h>
42#include <linux/slab.h>
43#include <linux/skbuff.h>
44#include <linux/netdevice.h>
45#include <linux/etherdevice.h>
46#include <linux/random.h>
47#include <linux/spinlock.h>
48#include <linux/ethtool.h>
49#include <asm/uaccess.h>
50#include <asm/unaligned.h>
51#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK)
52#include <linux/wakelock.h>
53#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */
54/* The kernel threading is sdio-specific */
55struct task_struct;
56struct sched_param;
57int setScheduler(struct task_struct *p, int policy, struct sched_param *param);
58
59#define ALL_INTERFACES 0xff
60
61#include <wlioctl.h>
62
63
64/* Forward decls */
65struct dhd_bus;
66struct dhd_prot;
67struct dhd_info;
68struct dhd_cmn;
69
70/* The level of bus communication with the dongle */
71enum dhd_bus_state {
72 DHD_BUS_DOWN, /* Not ready for frame transfers */
73 DHD_BUS_LOAD, /* Download access only (CPU reset) */
74 DHD_BUS_DATA /* Ready for frame transfers */
75};
76
77/* Firmware requested operation mode */
78#define STA_MASK 0x0001
79#define HOSTAPD_MASK 0x0002
80#define WFD_MASK 0x0004
81#define SOFTAP_FW_MASK 0x0008
82
83/* max sequential rxcntl timeouts to set HANG event */
84#define MAX_CNTL_TIMEOUT 2
85
86enum dhd_bus_wake_state {
87 WAKE_LOCK_OFF,
88 WAKE_LOCK_PRIV,
89 WAKE_LOCK_DPC,
90 WAKE_LOCK_IOCTL,
91 WAKE_LOCK_DOWNLOAD,
92 WAKE_LOCK_TMOUT,
93 WAKE_LOCK_WATCHDOG,
94 WAKE_LOCK_LINK_DOWN_TMOUT,
95 WAKE_LOCK_PNO_FIND_TMOUT,
96 WAKE_LOCK_SOFTAP_SET,
97 WAKE_LOCK_SOFTAP_STOP,
98 WAKE_LOCK_SOFTAP_START,
99 WAKE_LOCK_SOFTAP_THREAD,
100 WAKE_LOCK_MAX
101};
102
103enum dhd_prealloc_index {
104 DHD_PREALLOC_PROT = 0,
105 DHD_PREALLOC_RXBUF,
106 DHD_PREALLOC_DATABUF,
107 DHD_PREALLOC_OSL_BUF
108};
109
110typedef enum {
111 DHD_IF_NONE = 0,
112 DHD_IF_ADD,
113 DHD_IF_DEL,
114 DHD_IF_CHANGE,
115 DHD_IF_DELETING
116} dhd_if_state_t;
117
118
119#if defined(DHD_USE_STATIC_BUF)
120
121uint8* dhd_os_prealloc(void *osh, int section, uint size);
122void dhd_os_prefree(void *osh, void *addr, uint size);
123#define DHD_OS_PREALLOC(osh, section, size) dhd_os_prealloc(osh, section, size)
124#define DHD_OS_PREFREE(osh, addr, size) dhd_os_prefree(osh, addr, size)
125
126#else
127
128#define DHD_OS_PREALLOC(osh, section, size) MALLOC(osh, size)
129#define DHD_OS_PREFREE(osh, addr, size) MFREE(osh, addr, size)
130
131#endif /* defined(DHD_USE_STATIC_BUF) */
132
133/* Packet alignment for most efficient SDIO (can change based on platform) */
134#ifndef DHD_SDALIGN
135#define DHD_SDALIGN 32
136#endif
137
138/* Common structure for module and instance linkage */
139typedef struct dhd_pub {
140 /* Linkage ponters */
141 osl_t *osh; /* OSL handle */
142 struct dhd_bus *bus; /* Bus module handle */
143 struct dhd_prot *prot; /* Protocol module handle */
144 struct dhd_info *info; /* Info module handle */
145 struct dhd_cmn *cmn; /* dhd_common module handle */
146
147 /* Internal dhd items */
148 bool up; /* Driver up/down (to OS) */
149 bool txoff; /* Transmit flow-controlled */
150 bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */
151 enum dhd_bus_state busstate;
152 uint hdrlen; /* Total DHD header length (proto + bus) */
153 uint maxctl; /* Max size rxctl request from proto to bus */
154 uint rxsz; /* Rx buffer size bus module should use */
155 uint8 wme_dp; /* wme discard priority */
156
157 /* Dongle media info */
158 bool iswl; /* Dongle-resident driver is wl */
159 ulong drv_version; /* Version of dongle-resident driver */
160 struct ether_addr mac; /* MAC address obtained from dongle */
161 dngl_stats_t dstats; /* Stats for dongle-based data */
162
163 /* Additional stats for the bus level */
164 ulong tx_packets; /* Data packets sent to dongle */
165 ulong tx_multicast; /* Multicast data packets sent to dongle */
166 ulong tx_errors; /* Errors in sending data to dongle */
167 ulong tx_ctlpkts; /* Control packets sent to dongle */
168 ulong tx_ctlerrs; /* Errors sending control frames to dongle */
169 ulong rx_packets; /* Packets sent up the network interface */
170 ulong rx_multicast; /* Multicast packets sent up the network interface */
171 ulong rx_errors; /* Errors processing rx data packets */
172 ulong rx_ctlpkts; /* Control frames processed from dongle */
173 ulong rx_ctlerrs; /* Errors in processing rx control frames */
174 ulong rx_dropped; /* Packets dropped locally (no memory) */
175 ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */
176 ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */
177
178 ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */
179 ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */
180 ulong fc_packets; /* Number of flow control pkts recvd */
181
182 /* Last error return */
183 int bcmerror;
184 uint tickcnt;
185
186 /* Last error from dongle */
187 int dongle_error;
188
189 /* Suspend disable flag and "in suspend" flag */
190 int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */
191 int in_suspend; /* flag set to 1 when early suspend called */
192#ifdef PNO_SUPPORT
193 int pno_enable; /* pno status : "1" is pno enable */
194#endif /* PNO_SUPPORT */
195 int dtim_skip; /* dtim skip , default 0 means wake each dtim */
196
197 /* Pkt filter defination */
198 char * pktfilter[100];
199 int pktfilter_count;
200
201 wl_country_t dhd_cspec; /* Current Locale info */
202 char eventmask[WL_EVENTING_MASK_LEN];
203 int op_mode; /* STA, HostAPD, WFD, SoftAP */
204
205#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK)
206 struct wake_lock wakelock[WAKE_LOCK_MAX];
207#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */
208#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
209 struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */
210 struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */
211#endif
212
213 uint16 maxdatablks;
214#ifdef PROP_TXSTATUS
215 int wlfc_enabled;
216 void* wlfc_state;
217#endif
218 bool dongle_isolation;
219 int hang_was_sent;
220 int rxcnt_timeout; /* counter rxcnt timeout to send HANG */
221 int txcnt_timeout; /* counter txcnt timeout to send HANG */
222#ifdef WLMEDIA_HTSF
223 uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */
224#endif
225} dhd_pub_t;
226
227typedef struct dhd_cmn {
228 osl_t *osh; /* OSL handle */
229 dhd_pub_t *dhd;
230} dhd_cmn_t;
231
232
233 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
234
235 #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
236 #define _DHD_PM_RESUME_WAIT(a, b) do {\
237 int retry = 0; \
238 SMP_RD_BARRIER_DEPENDS(); \
239 while (dhd_mmc_suspend && retry++ != b) { \
240 SMP_RD_BARRIER_DEPENDS(); \
241 wait_event_interruptible_timeout(a, !dhd_mmc_suspend, HZ/100); \
242 } \
243 } while (0)
244 #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200)
245 #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0)
246 #define DHD_PM_RESUME_RETURN_ERROR(a) do { if (dhd_mmc_suspend) return a; } while (0)
247 #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0)
248
249 #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
250 #define SPINWAIT_SLEEP(a, exp, us) do { \
251 uint countdown = (us) + 9999; \
252 while ((exp) && (countdown >= 10000)) { \
253 wait_event_interruptible_timeout(a, FALSE, HZ/100); \
254 countdown -= 10000; \
255 } \
256 } while (0)
257
258 #else
259
260 #define DHD_PM_RESUME_WAIT_INIT(a)
261 #define DHD_PM_RESUME_WAIT(a)
262 #define DHD_PM_RESUME_WAIT_FOREVER(a)
263 #define DHD_PM_RESUME_RETURN_ERROR(a)
264 #define DHD_PM_RESUME_RETURN
265
266 #define DHD_SPINWAIT_SLEEP_INIT(a)
267 #define SPINWAIT_SLEEP(a, exp, us) do { \
268 uint countdown = (us) + 9; \
269 while ((exp) && (countdown >= 10)) { \
270 OSL_DELAY(10); \
271 countdown -= 10; \
272 } \
273 } while (0)
274
275 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
276#ifndef DHDTHREAD
277#undef SPINWAIT_SLEEP
278#define SPINWAIT_SLEEP(a, exp, us) SPINWAIT(exp, us)
279#endif /* DHDTHREAD */
280#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */
281
282unsigned long dhd_os_spin_lock(dhd_pub_t *pub);
283void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags);
284
285/* Wakelock Functions */
286extern int dhd_os_wake_lock(dhd_pub_t *pub);
287extern int dhd_os_wake_unlock(dhd_pub_t *pub);
288extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub);
289extern int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val);
290
291inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp)
292{
293#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
294 mutex_init(&dhdp->wl_softap_lock);
295#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
296}
297
298inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp)
299{
300#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
301 mutex_lock(&dhdp->wl_softap_lock);
302#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
303}
304
305inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp)
306{
307#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
308 mutex_unlock(&dhdp->wl_softap_lock);
309#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
310}
311
312#define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub)
313#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub)
314#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub)
315#define DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(pub, val) dhd_os_wake_lock_timeout_enable(pub, val)
316
317#define DHD_PACKET_TIMEOUT 1
318#define DHD_EVENT_TIMEOUT 2
319
320/* interface operations (register, remove) should be atomic, use this lock to prevent race
321 * condition among wifi on/off and interface operation functions
322 */
323void dhd_net_if_lock(struct net_device *dev);
324void dhd_net_if_unlock(struct net_device *dev);
325
326typedef struct dhd_if_event {
327 uint8 ifidx;
328 uint8 action;
329 uint8 flags;
330 uint8 bssidx;
331 uint8 is_AP;
332} dhd_if_event_t;
333
334typedef enum dhd_attach_states
335{
336 DHD_ATTACH_STATE_INIT = 0x0,
337 DHD_ATTACH_STATE_NET_ALLOC = 0x1,
338 DHD_ATTACH_STATE_DHD_ALLOC = 0x2,
339 DHD_ATTACH_STATE_ADD_IF = 0x4,
340 DHD_ATTACH_STATE_PROT_ATTACH = 0x8,
341 DHD_ATTACH_STATE_WL_ATTACH = 0x10,
342 DHD_ATTACH_STATE_THREADS_CREATED = 0x20,
343 DHD_ATTACH_STATE_WAKELOCKS_INIT = 0x40,
344 DHD_ATTACH_STATE_CFG80211 = 0x80,
345 DHD_ATTACH_STATE_EARLYSUSPEND_DONE = 0x100,
346 DHD_ATTACH_STATE_DONE = 0x200
347} dhd_attach_states_t;
348
349/* Value -1 means we are unsuccessful in creating the kthread. */
350#define DHD_PID_KT_INVALID -1
351/* Value -2 means we are unsuccessful in both creating the kthread and tasklet */
352#define DHD_PID_KT_TL_INVALID -2
353
354/*
355 * Exported from dhd OS modules (dhd_linux/dhd_ndis)
356 */
357
358/* To allow osl_attach/detach calls from os-independent modules */
359osl_t *dhd_osl_attach(void *pdev, uint bustype);
360void dhd_osl_detach(osl_t *osh);
361
362/* Indication from bus module regarding presence/insertion of dongle.
363 * Return dhd_pub_t pointer, used as handle to OS module in later calls.
364 * Returned structure should have bus and prot pointers filled in.
365 * bus_hdrlen specifies required headroom for bus module header.
366 */
367extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev);
368extern int dhd_net_attach(dhd_pub_t *dhdp, int idx);
369
370/* Indication from bus module regarding removal/absence of dongle */
371extern void dhd_detach(dhd_pub_t *dhdp);
372extern void dhd_free(dhd_pub_t *dhdp);
373
374/* Indication from bus module to change flow-control state */
375extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on);
376
377extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec);
378
379/* Receive frame for delivery to OS. Callee disposes of rxp. */
380extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt, uint8 chan);
381
382/* Return pointer to interface name */
383extern char *dhd_ifname(dhd_pub_t *dhdp, int idx);
384
385/* Request scheduling of the bus dpc */
386extern void dhd_sched_dpc(dhd_pub_t *dhdp);
387
388/* Notify tx completion */
389extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success);
390
391/* OS independent layer functions */
392extern int dhd_os_proto_block(dhd_pub_t * pub);
393extern int dhd_os_proto_unblock(dhd_pub_t * pub);
394extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending);
395extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub);
396extern unsigned int dhd_os_get_ioctl_resp_timeout(void);
397extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec);
398extern void * dhd_os_open_image(char * filename);
399extern int dhd_os_get_image_block(char * buf, int len, void * image);
400extern void dhd_os_close_image(void * image);
401extern void dhd_os_wd_timer(void *bus, uint wdtick);
402extern void dhd_os_sdlock(dhd_pub_t * pub);
403extern void dhd_os_sdunlock(dhd_pub_t * pub);
404extern void dhd_os_sdlock_txq(dhd_pub_t * pub);
405extern void dhd_os_sdunlock_txq(dhd_pub_t * pub);
406extern void dhd_os_sdlock_rxq(dhd_pub_t * pub);
407extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub);
408extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub);
409extern void dhd_customer_gpio_wlan_ctrl(int onoff);
410extern int dhd_custom_get_mac_address(unsigned char *buf);
411extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub);
412extern void dhd_os_sdlock_eventq(dhd_pub_t * pub);
413extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub);
414extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled);
415extern int dhd_pno_clean(dhd_pub_t *dhd);
416extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid,
417 ushort scan_fr, int pno_repeat, int pno_freq_expo_max);
418extern int dhd_pno_get_status(dhd_pub_t *dhd);
419extern int dhd_dev_pno_reset(struct net_device *dev);
420extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local,
421 int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max);
422extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled);
423extern int dhd_dev_get_pno_status(struct net_device *dev);
424extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
425extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd);
426extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret);
427
428#define DHD_UNICAST_FILTER_NUM 0
429#define DHD_BROADCAST_FILTER_NUM 1
430#define DHD_MULTICAST4_FILTER_NUM 2
431#define DHD_MULTICAST6_FILTER_NUM 3
432extern int net_os_set_packet_filter(struct net_device *dev, int val);
433extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num);
434
435#ifdef DHD_DEBUG
436extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size);
437#endif /* DHD_DEBUG */
438#if defined(OOB_INTR_ONLY)
439extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr);
440#endif /* defined(OOB_INTR_ONLY) */
441extern void dhd_os_sdtxlock(dhd_pub_t * pub);
442extern void dhd_os_sdtxunlock(dhd_pub_t * pub);
443
444typedef struct {
445 uint32 limit; /* Expiration time (usec) */
446 uint32 increment; /* Current expiration increment (usec) */
447 uint32 elapsed; /* Current elapsed time (usec) */
448 uint32 tick; /* O/S tick time (usec) */
449} dhd_timeout_t;
450
451extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec);
452extern int dhd_timeout_expired(dhd_timeout_t *tmo);
453
454extern int dhd_ifname2idx(struct dhd_info *dhd, char *name);
455extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net);
456extern struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx);
457extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata,
458 wl_event_msg_t *, void **data_ptr);
459extern void wl_event_to_host_order(wl_event_msg_t * evt);
460
461extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len);
462extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set,
463 int ifindex);
464
465extern struct dhd_cmn *dhd_common_init(uint16 devid, osl_t *osh);
466extern void dhd_common_deinit(dhd_pub_t *dhd_pub, dhd_cmn_t *sa_cmn);
467
468extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle,
469 char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx);
470extern void dhd_del_if(struct dhd_info *dhd, int ifidx);
471
472extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name);
473extern void dhd_vif_del(struct dhd_info *dhd, int ifidx);
474
475extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx);
476extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len);
477
478
479/* Send packet to dongle via data channel */
480extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt);
481
482/* send up locally generated event */
483extern void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data);
484/* Send event to host */
485extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data);
486extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag);
487extern uint dhd_bus_status(dhd_pub_t *dhdp);
488extern int dhd_bus_start(dhd_pub_t *dhdp);
489extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size);
490extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line);
491extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf);
492
493#if defined(KEEP_ALIVE)
494extern int dhd_keep_alive_onoff(dhd_pub_t *dhd);
495#endif /* KEEP_ALIVE */
496
497#ifdef ARP_OFFLOAD_SUPPORT
498extern void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode);
499extern void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable);
500#endif /* ARP_OFFLOAD_SUPPORT */
501
502
503typedef enum cust_gpio_modes {
504 WLAN_RESET_ON,
505 WLAN_RESET_OFF,
506 WLAN_POWER_ON,
507 WLAN_POWER_OFF
508} cust_gpio_modes_t;
509
510extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag);
511extern int wl_iw_send_priv_event(struct net_device *dev, char *flag);
512/*
513 * Insmod parameters for debug/test
514 */
515
516/* Watchdog timer interval */
517extern uint dhd_watchdog_ms;
518
519#if defined(DHD_DEBUG)
520/* Console output poll interval */
521extern uint dhd_console_ms;
522extern uint wl_msg_level;
523#endif /* defined(DHD_DEBUG) */
524
525/* Use interrupts */
526extern uint dhd_intr;
527
528/* Use polling */
529extern uint dhd_poll;
530
531/* ARP offload agent mode */
532extern uint dhd_arp_mode;
533
534/* ARP offload enable */
535extern uint dhd_arp_enable;
536
537/* Pkt filte enable control */
538extern uint dhd_pkt_filter_enable;
539
540/* Pkt filter init setup */
541extern uint dhd_pkt_filter_init;
542
543/* Pkt filter mode control */
544extern uint dhd_master_mode;
545
546/* Roaming mode control */
547extern uint dhd_roam_disable;
548
549/* Roaming mode control */
550extern uint dhd_radio_up;
551
552/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */
553extern int dhd_idletime;
554#define DHD_IDLETIME_TICKS 1
555
556/* SDIO Drive Strength */
557extern uint dhd_sdiod_drive_strength;
558
559/* Override to force tx queueing all the time */
560extern uint dhd_force_tx_queueing;
561/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */
562#define KEEP_ALIVE_PERIOD 55000
563#define NULL_PKT_STR "null_pkt"
564
565#ifdef SDTEST
566/* Echo packet generator (SDIO), pkts/s */
567extern uint dhd_pktgen;
568
569/* Echo packet len (0 => sawtooth, max 1800) */
570extern uint dhd_pktgen_len;
571#define MAX_PKTGEN_LEN 1800
572#endif
573
574
575/* optionally set by a module_param_string() */
576#define MOD_PARAM_PATHLEN 2048
577extern char fw_path[MOD_PARAM_PATHLEN];
578extern char nv_path[MOD_PARAM_PATHLEN];
579
580#ifdef SOFTAP
581extern char fw_path2[MOD_PARAM_PATHLEN];
582#endif
583
584/* Flag to indicate if we should download firmware on driver load */
585extern uint dhd_download_fw_on_driverload;
586
587/* For supporting multiple interfaces */
588#define DHD_MAX_IFS 16
589#define DHD_DEL_IF -0xe
590#define DHD_BAD_IF -0xf
591
592#ifdef PROP_TXSTATUS
593/* Please be mindful that total pkttag space is 32 octets only */
594typedef struct dhd_pkttag {
595 /*
596 b[11 ] - 1 = this packet was sent in response to one time packet request,
597 do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET].
598 b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on]
599 b[9 ] - 1 = packet is host->firmware (transmit direction)
600 - 0 = packet received from firmware (firmware->host)
601 b[8 ] - 1 = packet was sent due to credit_request (pspoll),
602 packet does not count against FIFO credit.
603 - 0 = normal transaction, packet counts against FIFO credit
604 b[7 ] - 1 = AP, 0 = STA
605 b[6:4] - AC FIFO number
606 b[3:0] - interface index
607 */
608 uint16 if_flags;
609 /* destination MAC address for this packet so that not every
610 module needs to open the packet to find this
611 */
612 uint8 dstn_ether[ETHER_ADDR_LEN];
613 /*
614 This 32-bit goes from host to device for every packet.
615 */
616 uint32 htod_tag;
617 /* bus specific stuff */
618 union {
619 struct {
620 void* stuff;
621 uint32 thing1;
622 uint32 thing2;
623 } sd;
624 struct {
625 void* bus;
626 void* urb;
627 } usb;
628 } bus_specific;
629} dhd_pkttag_t;
630
631#define DHD_PKTTAG_SET_H2DTAG(tag, h2dvalue) ((dhd_pkttag_t*)(tag))->htod_tag = (h2dvalue)
632#define DHD_PKTTAG_H2DTAG(tag) (((dhd_pkttag_t*)(tag))->htod_tag)
633
634#define DHD_PKTTAG_IFMASK 0xf
635#define DHD_PKTTAG_IFTYPE_MASK 0x1
636#define DHD_PKTTAG_IFTYPE_SHIFT 7
637#define DHD_PKTTAG_FIFO_MASK 0x7
638#define DHD_PKTTAG_FIFO_SHIFT 4
639
640#define DHD_PKTTAG_SIGNALONLY_MASK 0x1
641#define DHD_PKTTAG_SIGNALONLY_SHIFT 10
642
643#define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1
644#define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11
645
646#define DHD_PKTTAG_PKTDIR_MASK 0x1
647#define DHD_PKTTAG_PKTDIR_SHIFT 9
648
649#define DHD_PKTTAG_CREDITCHECK_MASK 0x1
650#define DHD_PKTTAG_CREDITCHECK_SHIFT 8
651
652#define DHD_PKTTAG_INVALID_FIFOID 0x7
653
654#define DHD_PKTTAG_SETFIFO(tag, fifo) ((dhd_pkttag_t*)(tag))->if_flags = \
655 (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_FIFO_MASK << DHD_PKTTAG_FIFO_SHIFT)) | \
656 (((fifo) & DHD_PKTTAG_FIFO_MASK) << DHD_PKTTAG_FIFO_SHIFT)
657#define DHD_PKTTAG_FIFO(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
658 DHD_PKTTAG_FIFO_SHIFT) & DHD_PKTTAG_FIFO_MASK)
659
660#define DHD_PKTTAG_SETIF(tag, if) ((dhd_pkttag_t*)(tag))->if_flags = \
661 (((dhd_pkttag_t*)(tag))->if_flags & ~DHD_PKTTAG_IFMASK) | ((if) & DHD_PKTTAG_IFMASK)
662#define DHD_PKTTAG_IF(tag) (((dhd_pkttag_t*)(tag))->if_flags & DHD_PKTTAG_IFMASK)
663
664#define DHD_PKTTAG_SETIFTYPE(tag, isAP) ((dhd_pkttag_t*)(tag))->if_flags = \
665 (((dhd_pkttag_t*)(tag))->if_flags & \
666 ~(DHD_PKTTAG_IFTYPE_MASK << DHD_PKTTAG_IFTYPE_SHIFT)) | \
667 (((isAP) & DHD_PKTTAG_IFTYPE_MASK) << DHD_PKTTAG_IFTYPE_SHIFT)
668#define DHD_PKTTAG_IFTYPE(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
669 DHD_PKTTAG_IFTYPE_SHIFT) & DHD_PKTTAG_IFTYPE_MASK)
670
671#define DHD_PKTTAG_SETCREDITCHECK(tag, check) ((dhd_pkttag_t*)(tag))->if_flags = \
672 (((dhd_pkttag_t*)(tag))->if_flags & \
673 ~(DHD_PKTTAG_CREDITCHECK_MASK << DHD_PKTTAG_CREDITCHECK_SHIFT)) | \
674 (((check) & DHD_PKTTAG_CREDITCHECK_MASK) << DHD_PKTTAG_CREDITCHECK_SHIFT)
675#define DHD_PKTTAG_CREDITCHECK(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
676 DHD_PKTTAG_CREDITCHECK_SHIFT) & DHD_PKTTAG_CREDITCHECK_MASK)
677
678#define DHD_PKTTAG_SETPKTDIR(tag, dir) ((dhd_pkttag_t*)(tag))->if_flags = \
679 (((dhd_pkttag_t*)(tag))->if_flags & \
680 ~(DHD_PKTTAG_PKTDIR_MASK << DHD_PKTTAG_PKTDIR_SHIFT)) | \
681 (((dir) & DHD_PKTTAG_PKTDIR_MASK) << DHD_PKTTAG_PKTDIR_SHIFT)
682#define DHD_PKTTAG_PKTDIR(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
683 DHD_PKTTAG_PKTDIR_SHIFT) & DHD_PKTTAG_PKTDIR_MASK)
684
685#define DHD_PKTTAG_SETSIGNALONLY(tag, signalonly) ((dhd_pkttag_t*)(tag))->if_flags = \
686 (((dhd_pkttag_t*)(tag))->if_flags & \
687 ~(DHD_PKTTAG_SIGNALONLY_MASK << DHD_PKTTAG_SIGNALONLY_SHIFT)) | \
688 (((signalonly) & DHD_PKTTAG_SIGNALONLY_MASK) << DHD_PKTTAG_SIGNALONLY_SHIFT)
689#define DHD_PKTTAG_SIGNALONLY(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
690 DHD_PKTTAG_SIGNALONLY_SHIFT) & DHD_PKTTAG_SIGNALONLY_MASK)
691
692#define DHD_PKTTAG_SETONETIMEPKTRQST(tag) ((dhd_pkttag_t*)(tag))->if_flags = \
693 (((dhd_pkttag_t*)(tag))->if_flags & \
694 ~(DHD_PKTTAG_ONETIMEPKTRQST_MASK << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)) | \
695 (1 << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)
696#define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \
697 DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK)
698
699#define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \
700 (dstn_MAC_ea), ETHER_ADDR_LEN)
701#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether
702
703typedef int (*f_commitpkt_t)(void* ctx, void* p);
704int dhd_wlfc_enable(dhd_pub_t *dhd);
705int dhd_wlfc_interface_event(struct dhd_info *, uint8 action, uint8 ifid, uint8 iftype, uint8* ea);
706int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data);
707int dhd_wlfc_event(struct dhd_info *dhd);
708int dhd_os_wlfc_block(dhd_pub_t *pub);
709int dhd_os_wlfc_unblock(dhd_pub_t *pub);
710
711#ifdef PROP_TXSTATUS_DEBUG
712#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0)
713#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do { (entry)->opened_ct++; } while (0)
714#else
715#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do {} while (0)
716#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0)
717#endif
718
719#endif /* PROP_TXSTATUS */
720
721extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar);
722extern void dhd_wait_event_wakeup(dhd_pub_t*dhd);
723
724#ifdef ARP_OFFLOAD_SUPPORT
725#define MAX_IPV4_ENTRIES 8
726/* dhd_commn arp offload wrapers */
727void dhd_aoe_hostip_clr(dhd_pub_t *dhd);
728void dhd_aoe_arp_clr(dhd_pub_t *dhd);
729int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen);
730void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr);
731#endif /* ARP_OFFLOAD_SUPPORT */
732
733#endif /* _dhd_h_ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_bta.c b/drivers/net/wireless/bcmdhd/dhd_bta.c
new file mode 100644
index 00000000000..6b782ea4a4d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_bta.c
@@ -0,0 +1,335 @@
1/*
2 * BT-AMP support routines
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: dhd_bta.c,v 1.10.4.2 2010-12-22 23:47:23 Exp $
25 */
26
27#include <typedefs.h>
28#include <osl.h>
29#include <bcmcdc.h>
30#include <bcmutils.h>
31#include <bcmendian.h>
32#include <proto/802.11.h>
33#include <proto/802.11_bta.h>
34#include <proto/bt_amp_hci.h>
35#include <dngl_stats.h>
36#include <dhd.h>
37#include <dhd_bus.h>
38#include <dhd_proto.h>
39#include <dhdioctl.h>
40#include <dhd_dbg.h>
41
42#include <dhd_bta.h>
43
44
45#ifdef SEND_HCI_CMD_VIA_IOCTL
46#define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE
47
48/* Send HCI cmd via wl iovar HCI_cmd to the dongle. */
49int
50dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len)
51{
52 amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf;
53 uint8 buf[BTA_HCI_CMD_MAX_LEN + 16];
54 uint len = sizeof(buf);
55 wl_ioctl_t ioc;
56
57 if (cmd_len < HCI_CMD_PREAMBLE_SIZE)
58 return BCME_BADLEN;
59
60 if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len)
61 return BCME_BADLEN;
62
63 len = bcm_mkiovar("HCI_cmd",
64 (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len);
65
66
67 memset(&ioc, 0, sizeof(ioc));
68
69 ioc.cmd = WLC_SET_VAR;
70 ioc.buf = buf;
71 ioc.len = len;
72 ioc.set = TRUE;
73
74 return dhd_wl_ioctl(pub, &ioc, ioc.buf, ioc.len);
75}
76#else /* !SEND_HCI_CMD_VIA_IOCTL */
77
78static void
79dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh)
80{
81 int prec;
82 struct pktq *q;
83 uint count = 0;
84
85 q = dhd_bus_txq(pub->bus);
86 if (q == NULL)
87 return;
88
89 DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh));
90
91 dhd_os_sdlock_txq(pub);
92
93 /* Walk through the txq and toss all HCI ACL data packets */
94 PKTQ_PREC_ITER(q, prec) {
95 void *head_pkt = NULL;
96
97 while (pktq_ppeek(q, prec) != head_pkt) {
98 void *pkt = pktq_pdeq(q, prec);
99 int ifidx;
100
101 PKTPULL(pub->osh, pkt, dhd_bus_hdrlen(pub->bus));
102 dhd_prot_hdrpull(pub, &ifidx, pkt);
103
104 if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) {
105 struct ether_header *eh =
106 (struct ether_header *)PKTDATA(pub->osh, pkt);
107
108 if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) {
109 struct dot11_llc_snap_header *lsh =
110 (struct dot11_llc_snap_header *)&eh[1];
111
112 if (bcmp(lsh, BT_SIG_SNAP_MPROT,
113 DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
114 ntoh16(lsh->type) == BTA_PROT_L2CAP) {
115 amp_hci_ACL_data_t *ACL_data =
116 (amp_hci_ACL_data_t *)&lsh[1];
117 uint16 handle = ltoh16(ACL_data->handle);
118
119 if (HCI_ACL_DATA_HANDLE(handle) == llh) {
120 PKTFREE(pub->osh, pkt, TRUE);
121 count ++;
122 continue;
123 }
124 }
125 }
126 }
127
128 dhd_prot_hdrpush(pub, ifidx, pkt);
129 PKTPUSH(pub->osh, pkt, dhd_bus_hdrlen(pub->bus));
130
131 if (head_pkt == NULL)
132 head_pkt = pkt;
133 pktq_penq(q, prec, pkt);
134 }
135 }
136
137 dhd_os_sdunlock_txq(pub);
138
139 DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh));
140}
141
142/* Handle HCI cmd locally.
143 * Return 0: continue to send the cmd across SDIO
144 * < 0: stop, fail
145 * > 0: stop, succuess
146 */
147static int
148_dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd)
149{
150 int status = 0;
151
152 switch (ltoh16_ua((uint8 *)&cmd->opcode)) {
153 case HCI_Enhanced_Flush: {
154 eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms;
155 dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh));
156 break;
157 }
158 default:
159 break;
160 }
161
162 return status;
163}
164
165/* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */
166int
167dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len)
168{
169 amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf;
170 struct ether_header *eh;
171 struct dot11_llc_snap_header *lsh;
172 osl_t *osh = pub->osh;
173 uint len;
174 void *p;
175 int status;
176
177 if (cmd_len < HCI_CMD_PREAMBLE_SIZE) {
178 DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len));
179 return BCME_BADLEN;
180 }
181
182 if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) {
183 DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n",
184 len, cmd_len));
185 /* return BCME_BADLEN; */
186 }
187
188 p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE);
189 if (p == NULL) {
190 DHD_ERROR(("dhd_bta_docmd: out of memory\n"));
191 return BCME_NOMEM;
192 }
193
194
195 /* intercept and handle the HCI cmd locally */
196 if ((status = _dhd_bta_docmd(pub, cmd)) > 0)
197 return 0;
198 else if (status < 0)
199 return status;
200
201 /* copy in HCI cmd */
202 PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN);
203 bcopy(cmd, PKTDATA(osh, p), len);
204
205 /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */
206 PKTPUSH(osh, p, RFC1042_HDR_LEN);
207 eh = (struct ether_header *)PKTDATA(osh, p);
208 bzero(eh->ether_dhost, ETHER_ADDR_LEN);
209 ETHER_SET_LOCALADDR(eh->ether_dhost);
210 bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN);
211 eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN);
212 lsh = (struct dot11_llc_snap_header *)&eh[1];
213 bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2);
214 lsh->type = 0;
215
216 return dhd_sendpkt(pub, 0, p);
217}
218#endif /* !SEND_HCI_CMD_VIA_IOCTL */
219
220/* Send HCI ACL data to dongle via data channel */
221int
222dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len)
223{
224 amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf;
225 struct ether_header *eh;
226 struct dot11_llc_snap_header *lsh;
227 osl_t *osh = pub->osh;
228 uint len;
229 void *p;
230
231 if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) {
232 DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len));
233 return BCME_BADLEN;
234 }
235
236 if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) {
237 DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n",
238 len, data_len));
239 /* return BCME_BADLEN; */
240 }
241
242 p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE);
243 if (p == NULL) {
244 DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n"));
245 return BCME_NOMEM;
246 }
247
248
249 /* copy in HCI ACL data header and HCI ACL data */
250 PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN);
251 bcopy(data, PKTDATA(osh, p), len);
252
253 /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */
254 PKTPUSH(osh, p, RFC1042_HDR_LEN);
255 eh = (struct ether_header *)PKTDATA(osh, p);
256 bzero(eh->ether_dhost, ETHER_ADDR_LEN);
257 bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN);
258 eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN);
259 lsh = (struct dot11_llc_snap_header *)&eh[1];
260 bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2);
261 lsh->type = HTON16(BTA_PROT_L2CAP);
262
263 return dhd_sendpkt(pub, 0, p);
264}
265
266/* txcomplete callback */
267void
268dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success)
269{
270 uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp);
271 amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN);
272 uint16 handle = ltoh16(ACL_data->handle);
273 uint16 llh = HCI_ACL_DATA_HANDLE(handle);
274
275 wl_event_msg_t event;
276 uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)];
277 amp_hci_event_t *evt;
278 num_completed_data_blocks_evt_parms_t *parms;
279
280 uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t);
281
282 /* update the event struct */
283 memset(&event, 0, sizeof(event));
284 event.version = hton16(BCM_EVENT_MSG_VERSION);
285 event.event_type = hton32(WLC_E_BTA_HCI_EVENT);
286 event.status = 0;
287 event.reason = 0;
288 event.auth_type = 0;
289 event.datalen = hton32(len);
290 event.flags = 0;
291
292 /* generate Number of Completed Blocks event */
293 evt = (amp_hci_event_t *)data;
294 evt->ecode = HCI_Number_of_Completed_Data_Blocks;
295 evt->plen = sizeof(num_completed_data_blocks_evt_parms_t);
296
297 parms = (num_completed_data_blocks_evt_parms_t *)evt->parms;
298 htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks);
299 parms->num_handles = 1;
300 htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle);
301 parms->completed[0].pkts = 1;
302 parms->completed[0].blocks = 1;
303
304 dhd_sendup_event_common(dhdp, &event, data);
305}
306
307/* event callback */
308void
309dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len)
310{
311 amp_hci_event_t *evt = (amp_hci_event_t *)data_buf;
312
313 switch (evt->ecode) {
314 case HCI_Command_Complete: {
315 cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms;
316 switch (ltoh16_ua((uint8 *)&parms->opcode)) {
317 case HCI_Read_Data_Block_Size: {
318 read_data_block_size_evt_parms_t *parms2 =
319 (read_data_block_size_evt_parms_t *)parms->parms;
320 dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num);
321 break;
322 }
323 }
324 break;
325 }
326
327 case HCI_Flush_Occurred: {
328 flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms;
329 dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle));
330 break;
331 }
332 default:
333 break;
334 }
335}
diff --git a/drivers/net/wireless/bcmdhd/dhd_bta.h b/drivers/net/wireless/bcmdhd/dhd_bta.h
new file mode 100644
index 00000000000..07d9cebb883
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_bta.h
@@ -0,0 +1,39 @@
1/*
2 * BT-AMP support routines
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: dhd_bta.h,v 1.2 2009-02-26 22:35:56 Exp $
25 */
26#ifndef __dhd_bta_h__
27#define __dhd_bta_h__
28
29struct dhd_pub;
30
31extern int dhd_bta_docmd(struct dhd_pub *pub, void *cmd_buf, uint cmd_len);
32
33extern void dhd_bta_doevt(struct dhd_pub *pub, void *data_buf, uint data_len);
34
35extern int dhd_bta_tx_hcidata(struct dhd_pub *pub, void *data_buf, uint data_len);
36extern void dhd_bta_tx_hcidata_complete(struct dhd_pub *dhdp, void *txp, bool success);
37
38
39#endif /* __dhd_bta_h__ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_bus.h b/drivers/net/wireless/bcmdhd/dhd_bus.h
new file mode 100644
index 00000000000..bccb8b6603f
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_bus.h
@@ -0,0 +1,99 @@
1/*
2 * Header file describing the internal (inter-module) DHD interfaces.
3 *
4 * Provides type definitions and function prototypes used to link the
5 * DHD OS, bus, and protocol modules.
6 *
7 * Copyright (C) 1999-2011, Broadcom Corporation
8 *
9 * Unless you and Broadcom execute a separate written software license
10 * agreement governing use of this software, this software is licensed to you
11 * under the terms of the GNU General Public License version 2 (the "GPL"),
12 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
13 * following added to such license:
14 *
15 * As a special exception, the copyright holders of this software give you
16 * permission to link this software with independent modules, and to copy and
17 * distribute the resulting executable under terms of your choice, provided that
18 * you also meet, for each linked independent module, the terms and conditions of
19 * the license of that module. An independent module is a module which is not
20 * derived from this software. The special exception does not apply to any
21 * modifications of the software.
22 *
23 * Notwithstanding the above, under no circumstances may you combine this
24 * software in any way with any other Broadcom software provided under a license
25 * other than the GPL, without Broadcom's express prior written consent.
26 *
27 * $Id: dhd_bus.h,v 1.14.28.1 2010-12-23 01:13:17 Exp $
28 */
29
30#ifndef _dhd_bus_h_
31#define _dhd_bus_h_
32
33/*
34 * Exported from dhd bus module (dhd_usb, dhd_sdio)
35 */
36
37/* Indicate (dis)interest in finding dongles. */
38extern int dhd_bus_register(void);
39extern void dhd_bus_unregister(void);
40
41/* Download firmware image and nvram image */
42extern bool dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
43 char *fw_path, char *nv_path);
44
45/* Stop bus module: clear pending frames, disable data flow */
46extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex);
47
48/* Initialize bus module: prepare for communication w/dongle */
49extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex);
50
51/* Get the Bus Idle Time */
52extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime);
53
54/* Set the Bus Idle Time*/
55extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time);
56/* Send a data frame to the dongle. Callee disposes of txp. */
57extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp);
58
59/* Send/receive a control message to/from the dongle.
60 * Expects caller to enforce a single outstanding transaction.
61 */
62extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen);
63extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen);
64
65/* Watchdog timer function */
66extern bool dhd_bus_watchdog(dhd_pub_t *dhd);
67extern void dhd_disable_intr(dhd_pub_t *dhd);
68
69#if defined(DHD_DEBUG)
70/* Device console input function */
71extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen);
72#endif /* defined(DHD_DEBUG) */
73
74/* Deferred processing for the bus, return TRUE requests reschedule */
75extern bool dhd_bus_dpc(struct dhd_bus *bus);
76extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg);
77
78
79/* Check for and handle local prot-specific iovar commands */
80extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
81 void *params, int plen, void *arg, int len, bool set);
82
83/* Add bus dump output to a buffer */
84extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
85
86/* Clear any bus counters */
87extern void dhd_bus_clearcounts(dhd_pub_t *dhdp);
88
89/* return the dongle chipid */
90extern uint dhd_bus_chip(struct dhd_bus *bus);
91
92/* Set user-specified nvram parameters. */
93extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params);
94
95extern void *dhd_bus_pub(struct dhd_bus *bus);
96extern void *dhd_bus_txq(struct dhd_bus *bus);
97extern uint dhd_bus_hdrlen(struct dhd_bus *bus);
98
99#endif /* _dhd_bus_h_ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c
new file mode 100644
index 00000000000..3a4de96c002
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c
@@ -0,0 +1,2530 @@
1/*
2 * DHD Protocol Module for CDC and BDC.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: dhd_cdc.c,v 1.51.6.31 2011-02-09 14:31:43 Exp $
25 *
26 * BDC is like CDC, except it includes a header for data packets to convey
27 * packet priority over the bus, and flags (e.g. to indicate checksum status
28 * for dongle offload.)
29 */
30
31#include <typedefs.h>
32#include <osl.h>
33
34#include <bcmutils.h>
35#include <bcmcdc.h>
36#include <bcmendian.h>
37
38#include <dngl_stats.h>
39#include <dhd.h>
40#include <dhd_proto.h>
41#include <dhd_bus.h>
42#include <dhd_dbg.h>
43
44
45#ifdef PROP_TXSTATUS
46#include <wlfc_proto.h>
47#include <dhd_wlfc.h>
48#endif
49
50
51#define RETRIES 2 /* # of retries to retrieve matching ioctl response */
52#define BUS_HEADER_LEN (16+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE
53 * defined in dhd_sdio.c (amount of header tha might be added)
54 * plus any space that might be needed for alignment padding.
55 */
56#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for
57 * round off at the end of buffer
58 */
59
60#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */
61
62#ifdef PROP_TXSTATUS
63typedef struct dhd_wlfc_commit_info {
64 uint8 needs_hdr;
65 uint8 ac_fifo_credit_spent;
66 ewlfc_packet_state_t pkt_type;
67 wlfc_mac_descriptor_t* mac_entry;
68 void* p;
69} dhd_wlfc_commit_info_t;
70#endif /* PROP_TXSTATUS */
71
72typedef struct dhd_prot {
73 uint16 reqid;
74 uint8 pending;
75 uint32 lastcmd;
76 uint8 bus_header[BUS_HEADER_LEN];
77 cdc_ioctl_t msg;
78 unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
79} dhd_prot_t;
80
81static int
82dhdcdc_msg(dhd_pub_t *dhd)
83{
84 int err = 0;
85 dhd_prot_t *prot = dhd->prot;
86 int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t);
87
88 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
89
90 DHD_OS_WAKE_LOCK(dhd);
91
92 /* NOTE : cdc->msg.len holds the desired length of the buffer to be
93 * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
94 * is actually sent to the dongle
95 */
96 if (len > CDC_MAX_MSG_SIZE)
97 len = CDC_MAX_MSG_SIZE;
98
99 /* Send request */
100 err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len);
101
102 DHD_OS_WAKE_UNLOCK(dhd);
103 return err;
104}
105
106static int
107dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
108{
109 int ret;
110 int cdc_len = len+sizeof(cdc_ioctl_t);
111 dhd_prot_t *prot = dhd->prot;
112
113 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
114
115 do {
116 ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len);
117 if (ret < 0)
118 break;
119 } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
120
121 return ret;
122}
123
124static int
125dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
126{
127 dhd_prot_t *prot = dhd->prot;
128 cdc_ioctl_t *msg = &prot->msg;
129 void *info;
130 int ret = 0, retries = 0;
131 uint32 id, flags = 0;
132
133 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
134 DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
135
136
137 /* Respond "bcmerror" and "bcmerrorstr" with local cache */
138 if (cmd == WLC_GET_VAR && buf)
139 {
140 if (!strcmp((char *)buf, "bcmerrorstr"))
141 {
142 strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN);
143 goto done;
144 }
145 else if (!strcmp((char *)buf, "bcmerror"))
146 {
147 *(int *)buf = dhd->dongle_error;
148 goto done;
149 }
150 }
151
152 memset(msg, 0, sizeof(cdc_ioctl_t));
153
154 msg->cmd = htol32(cmd);
155 msg->len = htol32(len);
156 msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
157 CDC_SET_IF_IDX(msg, ifidx);
158 /* add additional action bits */
159 action &= WL_IOCTL_ACTION_MASK;
160 msg->flags |= (action << CDCF_IOC_ACTION_SHIFT);
161 msg->flags = htol32(msg->flags);
162
163 if (buf)
164 memcpy(prot->buf, buf, len);
165
166 if ((ret = dhdcdc_msg(dhd)) < 0) {
167 if (!dhd->hang_was_sent)
168 DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
169 goto done;
170 }
171
172retry:
173 /* wait for interrupt and get first fragment */
174 if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
175 goto done;
176
177 flags = ltoh32(msg->flags);
178 id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
179
180 if ((id < prot->reqid) && (++retries < RETRIES))
181 goto retry;
182 if (id != prot->reqid) {
183 DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
184 dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
185 ret = -EINVAL;
186 goto done;
187 }
188
189 /* Check info buffer */
190 info = (void*)&msg[1];
191
192 /* Copy info buffer */
193 if (buf)
194 {
195 if (ret < (int)len)
196 len = ret;
197 memcpy(buf, info, len);
198 }
199
200 /* Check the ERROR flag */
201 if (flags & CDCF_IOC_ERROR)
202 {
203 ret = ltoh32(msg->status);
204 /* Cache error from dongle */
205 dhd->dongle_error = ret;
206 }
207
208done:
209 return ret;
210}
211
212static int
213dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action)
214{
215 dhd_prot_t *prot = dhd->prot;
216 cdc_ioctl_t *msg = &prot->msg;
217 int ret = 0;
218 uint32 flags, id;
219
220 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
221 DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
222
223 if (dhd->busstate == DHD_BUS_DOWN) {
224 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
225 return -EIO;
226 }
227
228 /* don't talk to the dongle if fw is about to be reloaded */
229 if (dhd->hang_was_sent) {
230 DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n",
231 __FUNCTION__));
232 return -EIO;
233 }
234
235 memset(msg, 0, sizeof(cdc_ioctl_t));
236
237 msg->cmd = htol32(cmd);
238 msg->len = htol32(len);
239 msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
240 CDC_SET_IF_IDX(msg, ifidx);
241 /* add additional action bits */
242 action &= WL_IOCTL_ACTION_MASK;
243 msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET;
244 msg->flags = htol32(msg->flags);
245
246 if (buf)
247 memcpy(prot->buf, buf, len);
248
249 if ((ret = dhdcdc_msg(dhd)) < 0) {
250 DHD_ERROR(("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret));
251 goto done;
252 }
253
254 if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
255 goto done;
256
257 flags = ltoh32(msg->flags);
258 id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
259
260 if (id != prot->reqid) {
261 DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
262 dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
263 ret = -EINVAL;
264 goto done;
265 }
266
267 /* Check the ERROR flag */
268 if (flags & CDCF_IOC_ERROR)
269 {
270 ret = ltoh32(msg->status);
271 /* Cache error from dongle */
272 dhd->dongle_error = ret;
273 }
274
275done:
276 return ret;
277}
278
279
280int
281dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len)
282{
283 dhd_prot_t *prot = dhd->prot;
284 int ret = -1;
285 uint8 action;
286
287 if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) {
288 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
289 goto done;
290 }
291
292 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
293
294 ASSERT(len <= WLC_IOCTL_MAXLEN);
295
296 if (len > WLC_IOCTL_MAXLEN)
297 goto done;
298
299 if (prot->pending == TRUE) {
300 DHD_ERROR(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n",
301 ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd,
302 (unsigned long)prot->lastcmd));
303 if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) {
304 DHD_TRACE(("iovar cmd=%s\n", (char*)buf));
305 }
306 goto done;
307 }
308
309 prot->pending = TRUE;
310 prot->lastcmd = ioc->cmd;
311 action = ioc->set;
312 if (action & WL_IOCTL_ACTION_SET)
313 ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action);
314 else {
315 ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action);
316 if (ret > 0)
317 ioc->used = ret - sizeof(cdc_ioctl_t);
318 }
319
320 /* Too many programs assume ioctl() returns 0 on success */
321 if (ret >= 0)
322 ret = 0;
323 else {
324 cdc_ioctl_t *msg = &prot->msg;
325 ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */
326 }
327
328 /* Intercept the wme_dp ioctl here */
329 if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) {
330 int slen, val = 0;
331
332 slen = strlen("wme_dp") + 1;
333 if (len >= (int)(slen + sizeof(int)))
334 bcopy(((char *)buf + slen), &val, sizeof(int));
335 dhd->wme_dp = (uint8) ltoh32(val);
336 }
337
338 prot->pending = FALSE;
339
340done:
341 return ret;
342}
343
344int
345dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
346 void *params, int plen, void *arg, int len, bool set)
347{
348 return BCME_UNSUPPORTED;
349}
350
351#ifdef PROP_TXSTATUS
352void
353dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
354{
355 int i;
356 uint8* ea;
357 athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
358 dhdp->wlfc_state;
359 wlfc_hanger_t* h;
360 wlfc_mac_descriptor_t* mac_table;
361 wlfc_mac_descriptor_t* interfaces;
362 char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"};
363
364 if (wlfc == NULL) {
365 bcm_bprintf(strbuf, "wlfc not initialized yet\n");
366 return;
367 }
368 h = (wlfc_hanger_t*)wlfc->hanger;
369 if (h == NULL) {
370 bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n");
371 }
372
373 mac_table = wlfc->destination_entries.nodes;
374 interfaces = wlfc->destination_entries.interfaces;
375 bcm_bprintf(strbuf, "---- wlfc stats ----\n");
376 if (h) {
377 bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push,"
378 "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n",
379 h->pushed,
380 h->popped,
381 h->failed_to_push,
382 h->failed_to_pop,
383 h->failed_slotfind,
384 (h->pushed - h->popped));
385 }
386
387 bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), "
388 "(dq_full,sendq_full, rollback_fail) = (%d,%d,%d,%d), (%d,%d,%d)\n",
389 wlfc->stats.tlv_parse_failed,
390 wlfc->stats.credit_request_failed,
391 wlfc->stats.mac_update_failed,
392 wlfc->stats.psmode_update_failed,
393 wlfc->stats.delayq_full_error,
394 wlfc->stats.sendq_full_error,
395 wlfc->stats.rollback_failed);
396
397 bcm_bprintf(strbuf, "SENDQ (len,credit,sent) "
398 "(AC0[%d,%d,%d],AC1[%d,%d,%d],AC2[%d,%d,%d],AC3[%d,%d,%d],BC_MC[%d,%d,%d])\n",
399 wlfc->SENDQ.q[0].len, wlfc->FIFO_credit[0], wlfc->stats.sendq_pkts[0],
400 wlfc->SENDQ.q[1].len, wlfc->FIFO_credit[1], wlfc->stats.sendq_pkts[1],
401 wlfc->SENDQ.q[2].len, wlfc->FIFO_credit[2], wlfc->stats.sendq_pkts[2],
402 wlfc->SENDQ.q[3].len, wlfc->FIFO_credit[3], wlfc->stats.sendq_pkts[3],
403 wlfc->SENDQ.q[4].len, wlfc->FIFO_credit[4], wlfc->stats.sendq_pkts[4]);
404
405#ifdef PROP_TXSTATUS_DEBUG
406 bcm_bprintf(strbuf, "SENDQ dropped: AC[0-3]:(%d,%d,%d,%d), (bcmc,atim):(%d,%d)\n",
407 wlfc->stats.dropped_qfull[0], wlfc->stats.dropped_qfull[1],
408 wlfc->stats.dropped_qfull[2], wlfc->stats.dropped_qfull[3],
409 wlfc->stats.dropped_qfull[4], wlfc->stats.dropped_qfull[5]);
410#endif
411
412 bcm_bprintf(strbuf, "\n");
413 for (i = 0; i < WLFC_MAX_IFNUM; i++) {
414 if (interfaces[i].occupied) {
415 char* iftype_desc;
416
417 if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT)
418 iftype_desc = "<Unknown";
419 else
420 iftype_desc = iftypes[interfaces[i].iftype];
421
422 ea = interfaces[i].ea;
423 bcm_bprintf(strbuf, "INTERFACE[%d].ea = "
424 "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d, type: %s\n", i,
425 ea[0], ea[1], ea[2], ea[3], ea[4], ea[5],
426 interfaces[i].interface_id,
427 iftype_desc);
428
429 bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ(len,state,credit)"
430 "= (%d,%s,%d)\n",
431 i,
432 interfaces[i].psq.len,
433 ((interfaces[i].state ==
434 WLFC_STATE_OPEN) ? " OPEN":"CLOSE"),
435 interfaces[i].requested_credit);
436
437 bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ"
438 "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = "
439 "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n",
440 i,
441 interfaces[i].psq.q[0].len,
442 interfaces[i].psq.q[1].len,
443 interfaces[i].psq.q[2].len,
444 interfaces[i].psq.q[3].len,
445 interfaces[i].psq.q[4].len,
446 interfaces[i].psq.q[5].len,
447 interfaces[i].psq.q[6].len,
448 interfaces[i].psq.q[7].len);
449 }
450 }
451
452 bcm_bprintf(strbuf, "\n");
453 for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) {
454 if (mac_table[i].occupied) {
455 ea = mac_table[i].ea;
456 bcm_bprintf(strbuf, "MAC_table[%d].ea = "
457 "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d\n", i,
458 ea[0], ea[1], ea[2], ea[3], ea[4], ea[5],
459 mac_table[i].interface_id);
460
461 bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ(len,state,credit)"
462 "= (%d,%s,%d)\n",
463 i,
464 mac_table[i].psq.len,
465 ((mac_table[i].state ==
466 WLFC_STATE_OPEN) ? " OPEN":"CLOSE"),
467 mac_table[i].requested_credit);
468#ifdef PROP_TXSTATUS_DEBUG
469 bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n",
470 i, mac_table[i].opened_ct, mac_table[i].closed_ct);
471#endif
472 bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ"
473 "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = "
474 "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n",
475 i,
476 mac_table[i].psq.q[0].len,
477 mac_table[i].psq.q[1].len,
478 mac_table[i].psq.q[2].len,
479 mac_table[i].psq.q[3].len,
480 mac_table[i].psq.q[4].len,
481 mac_table[i].psq.q[5].len,
482 mac_table[i].psq.q[6].len,
483 mac_table[i].psq.q[7].len);
484 }
485 }
486
487#ifdef PROP_TXSTATUS_DEBUG
488 {
489 int avg;
490 int moving_avg = 0;
491 int moving_samples;
492
493 if (wlfc->stats.latency_sample_count) {
494 moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32);
495
496 for (i = 0; i < moving_samples; i++)
497 moving_avg += wlfc->stats.deltas[i];
498 moving_avg /= moving_samples;
499
500 avg = (100 * wlfc->stats.total_status_latency) /
501 wlfc->stats.latency_sample_count;
502 bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = "
503 "(%d.%d, %03d, %03d)\n",
504 moving_samples, avg/100, (avg - (avg/100)*100),
505 wlfc->stats.latency_most_recent,
506 moving_avg);
507 }
508 }
509
510 bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), "
511 "back = (%d,%d,%d,%d,%d,%d)\n",
512 wlfc->stats.fifo_credits_sent[0],
513 wlfc->stats.fifo_credits_sent[1],
514 wlfc->stats.fifo_credits_sent[2],
515 wlfc->stats.fifo_credits_sent[3],
516 wlfc->stats.fifo_credits_sent[4],
517 wlfc->stats.fifo_credits_sent[5],
518
519 wlfc->stats.fifo_credits_back[0],
520 wlfc->stats.fifo_credits_back[1],
521 wlfc->stats.fifo_credits_back[2],
522 wlfc->stats.fifo_credits_back[3],
523 wlfc->stats.fifo_credits_back[4],
524 wlfc->stats.fifo_credits_back[5]);
525 {
526 uint32 fifo_cr_sent = 0;
527 uint32 fifo_cr_acked = 0;
528 uint32 request_cr_sent = 0;
529 uint32 request_cr_ack = 0;
530 uint32 bc_mc_cr_ack = 0;
531
532 for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) {
533 fifo_cr_sent += wlfc->stats.fifo_credits_sent[i];
534 }
535
536 for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) {
537 fifo_cr_acked += wlfc->stats.fifo_credits_back[i];
538 }
539
540 for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) {
541 if (wlfc->destination_entries.nodes[i].occupied) {
542 request_cr_sent +=
543 wlfc->destination_entries.nodes[i].dstncredit_sent_packets;
544 }
545 }
546 for (i = 0; i < WLFC_MAX_IFNUM; i++) {
547 if (wlfc->destination_entries.interfaces[i].occupied) {
548 request_cr_sent +=
549 wlfc->destination_entries.interfaces[i].dstncredit_sent_packets;
550 }
551 }
552 for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) {
553 if (wlfc->destination_entries.nodes[i].occupied) {
554 request_cr_ack +=
555 wlfc->destination_entries.nodes[i].dstncredit_acks;
556 }
557 }
558 for (i = 0; i < WLFC_MAX_IFNUM; i++) {
559 if (wlfc->destination_entries.interfaces[i].occupied) {
560 request_cr_ack +=
561 wlfc->destination_entries.interfaces[i].dstncredit_acks;
562 }
563 }
564 bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d),"
565 "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)",
566 fifo_cr_sent, fifo_cr_acked,
567 request_cr_sent, request_cr_ack,
568 wlfc->destination_entries.other.dstncredit_acks,
569 bc_mc_cr_ack,
570 wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed);
571 }
572#endif /* PROP_TXSTATUS_DEBUG */
573 bcm_bprintf(strbuf, "\n");
574 bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull),(dropped,hdr_only,wlc_tossed)"
575 "(freed,free_err,rollback)) = "
576 "((%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n",
577 wlfc->stats.pktin,
578 wlfc->stats.pkt2bus,
579 wlfc->stats.txstatus_in,
580 wlfc->stats.dhd_hdrpulls,
581
582 wlfc->stats.pktdropped,
583 wlfc->stats.wlfc_header_only_pkt,
584 wlfc->stats.wlc_tossed_pkts,
585
586 wlfc->stats.pkt_freed,
587 wlfc->stats.pkt_free_err, wlfc->stats.rollback);
588
589 bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = "
590 "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n",
591
592 wlfc->stats.d11_suppress,
593 wlfc->stats.wl_suppress,
594 wlfc->stats.bad_suppress,
595
596 wlfc->stats.psq_d11sup_enq,
597 wlfc->stats.psq_wlsup_enq,
598 wlfc->stats.psq_hostq_enq,
599 wlfc->stats.mac_handle_notfound,
600
601 wlfc->stats.psq_d11sup_retx,
602 wlfc->stats.psq_wlsup_retx,
603 wlfc->stats.psq_hostq_retx);
604 return;
605}
606
607/* Create a place to store all packet pointers submitted to the firmware until
608 a status comes back, suppress or otherwise.
609
610 hang-er: noun, a contrivance on which things are hung, as a hook.
611*/
612static void*
613dhd_wlfc_hanger_create(osl_t *osh, int max_items)
614{
615 int i;
616 wlfc_hanger_t* hanger;
617
618 /* allow only up to a specific size for now */
619 ASSERT(max_items == WLFC_HANGER_MAXITEMS);
620
621 if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL)
622 return NULL;
623
624 memset(hanger, 0, WLFC_HANGER_SIZE(max_items));
625 hanger->max_items = max_items;
626
627 for (i = 0; i < hanger->max_items; i++) {
628 hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE;
629 }
630 return hanger;
631}
632
633static int
634dhd_wlfc_hanger_delete(osl_t *osh, void* hanger)
635{
636 wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
637
638 if (h) {
639 MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items));
640 return BCME_OK;
641 }
642 return BCME_BADARG;
643}
644
645static uint16
646dhd_wlfc_hanger_get_free_slot(void* hanger)
647{
648 int i;
649 wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
650
651 if (h) {
652 for (i = 0; i < h->max_items; i++) {
653 if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE)
654 return (uint16)i;
655 }
656 h->failed_slotfind++;
657 }
658 return WLFC_HANGER_MAXITEMS;
659}
660
661static int
662dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id)
663{
664 int rc = BCME_OK;
665 wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
666
667 if (h && (slot_id < WLFC_HANGER_MAXITEMS)) {
668 if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) {
669 h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE;
670 h->items[slot_id].pkt = pkt;
671 h->items[slot_id].identifier = slot_id;
672 h->pushed++;
673 }
674 else {
675 h->failed_to_push++;
676 rc = BCME_NOTFOUND;
677 }
678 }
679 else
680 rc = BCME_BADARG;
681 return rc;
682}
683
684static int
685dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger)
686{
687 int rc = BCME_OK;
688 wlfc_hanger_t* h = (wlfc_hanger_t*)hanger;
689
690 /* this packet was not pushed at the time it went to the firmware */
691 if (slot_id == WLFC_HANGER_MAXITEMS)
692 return BCME_NOTFOUND;
693
694 if (h) {
695 if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) {
696 *pktout = h->items[slot_id].pkt;
697 if (remove_from_hanger) {
698 h->items[slot_id].state =
699 WLFC_HANGER_ITEM_STATE_FREE;
700 h->items[slot_id].pkt = NULL;
701 h->items[slot_id].identifier = 0;
702 h->popped++;
703 }
704 }
705 else {
706 h->failed_to_pop++;
707 rc = BCME_NOTFOUND;
708 }
709 }
710 else
711 rc = BCME_BADARG;
712 return rc;
713}
714
715static int
716_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal,
717 uint8 tim_bmp, uint8 mac_handle, uint32 htodtag)
718{
719 uint32 wl_pktinfo = 0;
720 uint8* wlh;
721 uint8 dataOffset;
722 uint8 fillers;
723 uint8 tim_signal_len = 0;
724
725 struct bdc_header *h;
726
727 if (tim_signal) {
728 tim_signal_len = 1 + 1 + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP;
729 }
730
731 /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
732 dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + 2 + tim_signal_len;
733 fillers = ROUNDUP(dataOffset, 4) - dataOffset;
734 dataOffset += fillers;
735
736 PKTPUSH(ctx->osh, p, dataOffset);
737 wlh = (uint8*) PKTDATA(ctx->osh, p);
738
739 wl_pktinfo = htol32(htodtag);
740
741 wlh[0] = WLFC_CTL_TYPE_PKTTAG;
742 wlh[1] = WLFC_CTL_VALUE_LEN_PKTTAG;
743 memcpy(&wlh[2], &wl_pktinfo, sizeof(uint32));
744
745 if (tim_signal_len) {
746 wlh[dataOffset - fillers - tim_signal_len ] =
747 WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP;
748 wlh[dataOffset - fillers - tim_signal_len + 1] =
749 WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP;
750 wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle;
751 wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp;
752 }
753 if (fillers)
754 memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers);
755
756 PKTPUSH(ctx->osh, p, BDC_HEADER_LEN);
757 h = (struct bdc_header *)PKTDATA(ctx->osh, p);
758 h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
759 if (PKTSUMNEEDED(p))
760 h->flags |= BDC_FLAG_SUM_NEEDED;
761
762
763 h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK);
764 h->flags2 = 0;
765 h->dataOffset = dataOffset >> 2;
766 BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p)));
767 return BCME_OK;
768}
769
770static int
771_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf)
772{
773 struct bdc_header *h;
774
775 if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) {
776 WLFC_DBGMESG(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
777 PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN));
778 return BCME_ERROR;
779 }
780 h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf);
781
782 /* pull BDC header */
783 PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN);
784 /* pull wl-header */
785 PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2));
786 return BCME_OK;
787}
788
789static wlfc_mac_descriptor_t*
790_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p)
791{
792 int i;
793 wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes;
794 uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p));
795 uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p));
796
797 /* no lookup necessary, only if this packet belongs to STA interface */
798 if (((ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_STA) ||
799 ETHER_ISMULTI(dstn) ||
800 (ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_P2P_CLIENT)) &&
801 (ctx->destination_entries.interfaces[ifid].occupied)) {
802 return &ctx->destination_entries.interfaces[ifid];
803 }
804
805 for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) {
806 if (table[i].occupied) {
807 if (table[i].interface_id == ifid) {
808 if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN))
809 return &table[i];
810 }
811 }
812 }
813 return &ctx->destination_entries.other;
814}
815
816static int
817_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx,
818 void* p, ewlfc_packet_state_t pkt_type, uint32 hslot)
819{
820 /*
821 put the packet back to the head of queue
822
823 - a packet from send-q will need to go back to send-q and not delay-q
824 since that will change the order of packets.
825 - suppressed packet goes back to suppress sub-queue
826 - pull out the header, if new or delayed packet
827
828 Note: hslot is used only when header removal is done.
829 */
830 wlfc_mac_descriptor_t* entry;
831 void* pktout;
832 int rc = BCME_OK;
833 int prec;
834
835 entry = _dhd_wlfc_find_table_entry(ctx, p);
836 prec = DHD_PKTTAG_FIFO(PKTTAG(p));
837 if (entry != NULL) {
838 if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) {
839 /* wl-header is saved for suppressed packets */
840 if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, ((prec << 1) + 1), p) == NULL) {
841 WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
842 rc = BCME_ERROR;
843 }
844 }
845 else {
846 /* remove header first */
847 _dhd_wlfc_pullheader(ctx, p);
848
849 if (pkt_type == eWLFC_PKTTYPE_DELAYED) {
850 /* delay-q packets are going to delay-q */
851 if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, (prec << 1), p) == NULL) {
852 WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
853 rc = BCME_ERROR;
854 }
855 }
856 else {
857 /* these are going to SENDQ */
858 if (WLFC_PKTQ_PENQ_HEAD(&ctx->SENDQ, prec, p) == NULL) {
859 WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
860 rc = BCME_ERROR;
861 }
862 }
863 /* free the hanger slot */
864 dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1);
865
866 /* decrement sequence count */
867 WLFC_DECR_SEQCOUNT(entry, prec);
868 }
869 /*
870 if this packet did not count against FIFO credit, it must have
871 taken a requested_credit from the firmware (for pspoll etc.)
872 */
873 if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) {
874 entry->requested_credit++;
875 }
876 }
877 else {
878 WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
879 rc = BCME_ERROR;
880 }
881 if (rc != BCME_OK)
882 ctx->stats.rollback_failed++;
883 else
884 ctx->stats.rollback++;
885
886 return rc;
887}
888
889static void
890_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id)
891{
892 if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) {
893 /* start traffic */
894 ctx->hostif_flow_state[if_id] = OFF;
895 /*
896 WLFC_DBGMESG(("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n",
897 pq->len, if_id, __FUNCTION__));
898 */
899 WLFC_DBGMESG(("F"));
900 /* dhd_txflowcontrol(ctx->dhdp, if_id, OFF); */
901 ctx->toggle_host_if = 0;
902 }
903 if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) {
904 /* stop traffic */
905 ctx->hostif_flow_state[if_id] = ON;
906 /*
907 WLFC_DBGMESG(("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n",
908 pq->len, if_id, __FUNCTION__));
909 */
910 WLFC_DBGMESG(("N"));
911 /* dhd_txflowcontrol(ctx->dhdp, if_id, ON); */
912 ctx->host_ifidx = if_id;
913 ctx->toggle_host_if = 1;
914 }
915 return;
916}
917
918static int
919_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry,
920 uint8 ta_bmp)
921{
922 int rc = BCME_OK;
923 void* p = NULL;
924 int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 12;
925
926 /* allocate a dummy packet */
927 p = PKTGET(ctx->osh, dummylen, TRUE);
928 if (p) {
929 PKTPULL(ctx->osh, p, dummylen);
930 DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0);
931 _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0);
932 DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1);
933#ifdef PROP_TXSTATUS_DEBUG
934 ctx->stats.signal_only_pkts_sent++;
935#endif
936 rc = dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p);
937 if (rc != BCME_OK) {
938 PKTFREE(ctx->osh, p, TRUE);
939 }
940 }
941 else {
942 DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
943 __FUNCTION__, dummylen));
944 rc = BCME_NOMEM;
945 }
946 return rc;
947}
948
949/* Return TRUE if traffic availability changed */
950static bool
951_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry,
952 int prec)
953{
954 bool rc = FALSE;
955
956 if (entry->state == WLFC_STATE_CLOSE) {
957 if ((pktq_plen(&entry->psq, (prec << 1)) == 0) &&
958 (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) {
959
960 if (entry->traffic_pending_bmp & NBITVAL(prec)) {
961 rc = TRUE;
962 entry->traffic_pending_bmp =
963 entry->traffic_pending_bmp & ~ NBITVAL(prec);
964 }
965 }
966 else {
967 if (!(entry->traffic_pending_bmp & NBITVAL(prec))) {
968 rc = TRUE;
969 entry->traffic_pending_bmp =
970 entry->traffic_pending_bmp | NBITVAL(prec);
971 }
972 }
973 }
974 if (rc) {
975 /* request a TIM update to firmware at the next piggyback opportunity */
976 if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) {
977 entry->send_tim_signal = 1;
978 _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp);
979 entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
980 entry->send_tim_signal = 0;
981 }
982 else {
983 rc = FALSE;
984 }
985 }
986 return rc;
987}
988
989static int
990_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p)
991{
992 wlfc_mac_descriptor_t* entry;
993
994 entry = _dhd_wlfc_find_table_entry(ctx, p);
995 if (entry == NULL) {
996 WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
997 return BCME_NOTFOUND;
998 }
999 /*
1000 - suppressed packets go to sub_queue[2*prec + 1] AND
1001 - delayed packets go to sub_queue[2*prec + 0] to ensure
1002 order of delivery.
1003 */
1004 if (WLFC_PKTQ_PENQ(&entry->psq, ((prec << 1) + 1), p) == NULL) {
1005 ctx->stats.delayq_full_error++;
1006 /* WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); */
1007 WLFC_DBGMESG(("s"));
1008 return BCME_ERROR;
1009 }
1010 /* A packet has been pushed, update traffic availability bitmap, if applicable */
1011 _dhd_wlfc_traffic_pending_check(ctx, entry, prec);
1012 _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p)));
1013 return BCME_OK;
1014}
1015
1016static int
1017_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx,
1018 wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot)
1019{
1020 int rc = BCME_OK;
1021 int hslot = WLFC_HANGER_MAXITEMS;
1022 bool send_tim_update = FALSE;
1023 uint32 htod = 0;
1024 uint8 free_ctr;
1025
1026 *slot = hslot;
1027
1028 if (entry == NULL) {
1029 entry = _dhd_wlfc_find_table_entry(ctx, p);
1030 }
1031
1032 if (entry == NULL) {
1033 WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
1034 return BCME_ERROR;
1035 }
1036 if (entry->send_tim_signal) {
1037 send_tim_update = TRUE;
1038 entry->send_tim_signal = 0;
1039 entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
1040 }
1041 if (header_needed) {
1042 hslot = dhd_wlfc_hanger_get_free_slot(ctx->hanger);
1043 free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p)));
1044 DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod);
1045 }
1046 else {
1047 hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p)));
1048 free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p)));
1049 }
1050 WLFC_PKTID_HSLOT_SET(htod, hslot);
1051 WLFC_PKTID_FREERUNCTR_SET(htod, free_ctr);
1052 DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1);
1053 WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST);
1054 WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p)));
1055 WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation);
1056
1057 if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) {
1058 /*
1059 Indicate that this packet is being sent in response to an
1060 explicit request from the firmware side.
1061 */
1062 WLFC_PKTFLAG_SET_PKTREQUESTED(htod);
1063 }
1064 else {
1065 WLFC_PKTFLAG_CLR_PKTREQUESTED(htod);
1066 }
1067 if (header_needed) {
1068 rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update,
1069 entry->traffic_lastreported_bmp, entry->mac_handle, htod);
1070 if (rc == BCME_OK) {
1071 DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod);
1072 /*
1073 a new header was created for this packet.
1074 push to hanger slot and scrub q. Since bus
1075 send succeeded, increment seq number as well.
1076 */
1077 rc = dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot);
1078 if (rc == BCME_OK) {
1079 /* increment free running sequence count */
1080 WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p)));
1081#ifdef PROP_TXSTATUS_DEBUG
1082 ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time =
1083 OSL_SYSUPTIME();
1084#endif
1085 }
1086 else {
1087 WLFC_DBGMESG(("%s() hanger_pushpkt() failed, rc: %d\n",
1088 __FUNCTION__, rc));
1089 }
1090 }
1091 }
1092 else {
1093 /* remove old header */
1094 _dhd_wlfc_pullheader(ctx, p);
1095
1096 hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p)));
1097 free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p)));
1098 /* push new header */
1099 _dhd_wlfc_pushheader(ctx, p, send_tim_update,
1100 entry->traffic_lastreported_bmp, entry->mac_handle, htod);
1101 }
1102 *slot = hslot;
1103 return rc;
1104}
1105
1106static int
1107_dhd_wlfc_is_destination_closed(athost_wl_status_info_t* ctx,
1108 wlfc_mac_descriptor_t* entry, int prec)
1109{
1110 if (ctx->destination_entries.interfaces[entry->interface_id].iftype ==
1111 WLC_E_IF_ROLE_P2P_GO) {
1112 /* - destination interface is of type p2p GO.
1113 For a p2pGO interface, if the destination is OPEN but the interface is
1114 CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is
1115 destination-specific-credit left send packets. This is because the
1116 firmware storing the destination-specific-requested packet in queue.
1117 */
1118 if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) &&
1119 (entry->requested_packet == 0))
1120 return 1;
1121 }
1122 /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */
1123 if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) &&
1124 (entry->requested_packet == 0)) ||
1125 (!(entry->ac_bitmap & (1 << prec))))
1126 return 1;
1127
1128 return 0;
1129}
1130
1131static void*
1132_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx,
1133 int prec, uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out)
1134{
1135 wlfc_mac_descriptor_t* entry;
1136 wlfc_mac_descriptor_t* table;
1137 uint8 token_pos;
1138 int total_entries;
1139 void* p = NULL;
1140 int pout;
1141 int i;
1142
1143 *entry_out = NULL;
1144 token_pos = ctx->token_pos[prec];
1145 /* most cases a packet will count against FIFO credit */
1146 *ac_credit_spent = 1;
1147 *needs_hdr = 1;
1148
1149 /* search all entries, include nodes as well as interfaces */
1150 table = (wlfc_mac_descriptor_t*)&ctx->destination_entries;
1151 total_entries = sizeof(ctx->destination_entries)/sizeof(wlfc_mac_descriptor_t);
1152
1153 for (i = 0; i < total_entries; i++) {
1154 entry = &table[(token_pos + i) % total_entries];
1155 if (entry->occupied) {
1156 if (!_dhd_wlfc_is_destination_closed(ctx, entry, prec)) {
1157 p = pktq_mdeq(&entry->psq,
1158 /* higher precedence will be picked up first,
1159 i.e. suppressed packets before delayed ones
1160 */
1161 (NBITVAL((prec << 1) + 1) | NBITVAL((prec << 1))),
1162 &pout);
1163 if (p != NULL) {
1164 /* did the packet come from suppress sub-queue? */
1165 if (pout == ((prec << 1) + 1)) {
1166 /*
1167 this packet was suppressed and was sent on the bus
1168 previously; this already has a header
1169 */
1170 *needs_hdr = 0;
1171 }
1172 if (entry->requested_credit > 0) {
1173 entry->requested_credit--;
1174#ifdef PROP_TXSTATUS_DEBUG
1175 entry->dstncredit_sent_packets++;
1176#endif
1177 /*
1178 if the packet was pulled out while destination is in
1179 closed state but had a non-zero packets requested,
1180 then this should not count against the FIFO credit.
1181 That is due to the fact that the firmware will
1182 most likely hold onto this packet until a suitable
1183 time later to push it to the appropriate AC FIFO.
1184 */
1185 if (entry->state == WLFC_STATE_CLOSE)
1186 *ac_credit_spent = 0;
1187 }
1188 else if (entry->requested_packet > 0) {
1189 entry->requested_packet--;
1190 DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p));
1191 if (entry->state == WLFC_STATE_CLOSE)
1192 *ac_credit_spent = 0;
1193 }
1194 /* move token to ensure fair round-robin */
1195 ctx->token_pos[prec] =
1196 (token_pos + i + 1) % total_entries;
1197 *entry_out = entry;
1198 _dhd_wlfc_flow_control_check(ctx, &entry->psq,
1199 DHD_PKTTAG_IF(PKTTAG(p)));
1200 /*
1201 A packet has been picked up, update traffic
1202 availability bitmap, if applicable
1203 */
1204 _dhd_wlfc_traffic_pending_check(ctx, entry, prec);
1205 return p;
1206 }
1207 }
1208 }
1209 }
1210 return NULL;
1211}
1212
1213static void*
1214_dhd_wlfc_deque_sendq(athost_wl_status_info_t* ctx, int prec, uint8* ac_credit_spent)
1215{
1216 wlfc_mac_descriptor_t* entry;
1217 void* p;
1218
1219 /* most cases a packet will count against FIFO credit */
1220 *ac_credit_spent = 1;
1221
1222 p = pktq_pdeq(&ctx->SENDQ, prec);
1223 if (p != NULL) {
1224 if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p))))
1225 /* bc/mc packets do not have a delay queue */
1226 return p;
1227
1228 entry = _dhd_wlfc_find_table_entry(ctx, p);
1229
1230 if (entry == NULL) {
1231 WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
1232 return p;
1233 }
1234
1235 while ((p != NULL) && _dhd_wlfc_is_destination_closed(ctx, entry, prec)) {
1236 /*
1237 - suppressed packets go to sub_queue[2*prec + 1] AND
1238 - delayed packets go to sub_queue[2*prec + 0] to ensure
1239 order of delivery.
1240 */
1241 if (WLFC_PKTQ_PENQ(&entry->psq, (prec << 1), p) == NULL) {
1242 WLFC_DBGMESG(("D"));
1243 /* dhd_txcomplete(ctx->dhdp, p, FALSE); */
1244 PKTFREE(ctx->osh, p, TRUE);
1245 ctx->stats.delayq_full_error++;
1246 }
1247 /*
1248 A packet has been pushed, update traffic availability bitmap,
1249 if applicable
1250 */
1251 _dhd_wlfc_traffic_pending_check(ctx, entry, prec);
1252 _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p)));
1253 p = pktq_pdeq(&ctx->SENDQ, prec);
1254 if (p == NULL)
1255 break;
1256
1257 entry = _dhd_wlfc_find_table_entry(ctx, p);
1258
1259 if ((entry == NULL) || (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p))))) {
1260 return p;
1261 }
1262 }
1263 if (p) {
1264 if (entry->requested_packet == 0) {
1265 if (entry->requested_credit > 0)
1266 entry->requested_credit--;
1267 }
1268 else {
1269 entry->requested_packet--;
1270 DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p));
1271 }
1272 if (entry->state == WLFC_STATE_CLOSE)
1273 *ac_credit_spent = 0;
1274#ifdef PROP_TXSTATUS_DEBUG
1275 entry->dstncredit_sent_packets++;
1276#endif
1277 }
1278 if (p)
1279 _dhd_wlfc_flow_control_check(ctx, &ctx->SENDQ, DHD_PKTTAG_IF(PKTTAG(p)));
1280 }
1281 return p;
1282}
1283
1284static int
1285_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry,
1286 ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea)
1287{
1288 int rc = BCME_OK;
1289
1290 if (action == eWLFC_MAC_ENTRY_ACTION_ADD) {
1291 entry->occupied = 1;
1292 entry->state = WLFC_STATE_OPEN;
1293 entry->requested_credit = 0;
1294 entry->interface_id = ifid;
1295 entry->iftype = iftype;
1296 entry->ac_bitmap = 0xff; /* update this when handling APSD */
1297 /* for an interface entry we may not care about the MAC address */
1298 if (ea != NULL)
1299 memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN);
1300 pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN);
1301 }
1302 else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) {
1303 entry->occupied = 0;
1304 entry->state = WLFC_STATE_CLOSE;
1305 entry->requested_credit = 0;
1306 /* enable after packets are queued-deqeued properly.
1307 pktq_flush(dhd->osh, &entry->psq, FALSE, NULL, 0);
1308 */
1309 }
1310 return rc;
1311}
1312
1313int
1314_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, uint8 available_credit_map, int borrower_ac)
1315{
1316 int lender_ac;
1317 int rc = BCME_ERROR;
1318
1319 if (ctx == NULL || available_credit_map == 0) {
1320 WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
1321 return BCME_BADARG;
1322 }
1323
1324 /* Borrow from lowest priority available AC (including BC/MC credits) */
1325 for (lender_ac = 0; lender_ac <= AC_COUNT; lender_ac++) {
1326 if ((available_credit_map && (1 << lender_ac)) &&
1327 (ctx->FIFO_credit[lender_ac] > 0)) {
1328 ctx->credits_borrowed[borrower_ac][lender_ac]++;
1329 ctx->FIFO_credit[lender_ac]--;
1330 rc = BCME_OK;
1331 break;
1332 }
1333 }
1334
1335 return rc;
1336}
1337
1338int
1339dhd_wlfc_interface_entry_update(void* state,
1340 ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea)
1341{
1342 athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state;
1343 wlfc_mac_descriptor_t* entry;
1344
1345 if (ifid >= WLFC_MAX_IFNUM)
1346 return BCME_BADARG;
1347
1348 entry = &ctx->destination_entries.interfaces[ifid];
1349 return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea);
1350}
1351
1352int
1353dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits)
1354{
1355 athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state;
1356
1357 /* update the AC FIFO credit map */
1358 ctx->FIFO_credit[0] = credits[0];
1359 ctx->FIFO_credit[1] = credits[1];
1360 ctx->FIFO_credit[2] = credits[2];
1361 ctx->FIFO_credit[3] = credits[3];
1362 /* credit for bc/mc packets */
1363 ctx->FIFO_credit[4] = credits[4];
1364 /* credit for ATIM FIFO is not used yet. */
1365 ctx->FIFO_credit[5] = 0;
1366 return BCME_OK;
1367}
1368
1369int
1370dhd_wlfc_enque_sendq(void* state, int prec, void* p)
1371{
1372 athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state;
1373
1374 if ((state == NULL) ||
1375 /* prec = AC_COUNT is used for bc/mc queue */
1376 (prec > AC_COUNT) ||
1377 (p == NULL)) {
1378 WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
1379 return BCME_BADARG;
1380 }
1381 if (FALSE == dhd_prec_enq(ctx->dhdp, &ctx->SENDQ, p, prec)) {
1382 ctx->stats.sendq_full_error++;
1383 /*
1384 WLFC_DBGMESG(("Error: %s():%d, qlen:%d\n",
1385 __FUNCTION__, __LINE__, ctx->SENDQ.len));
1386 */
1387 WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, prec);
1388 WLFC_DBGMESG(("Q"));
1389 PKTFREE(ctx->osh, p, TRUE);
1390 return BCME_ERROR;
1391 }
1392 ctx->stats.pktin++;
1393 /* _dhd_wlfc_flow_control_check(ctx, &ctx->SENDQ, DHD_PKTTAG_IF(PKTTAG(p))); */
1394 return BCME_OK;
1395}
1396
1397int
1398_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac,
1399 dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx)
1400{
1401 uint32 hslot;
1402 int rc;
1403
1404 /*
1405 if ac_fifo_credit_spent = 0
1406
1407 This packet will not count against the FIFO credit.
1408 To ensure the txstatus corresponding to this packet
1409 does not provide an implied credit (default behavior)
1410 mark the packet accordingly.
1411
1412 if ac_fifo_credit_spent = 1
1413
1414 This is a normal packet and it counts against the FIFO
1415 credit count.
1416 */
1417 DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent);
1418 rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p,
1419 commit_info->needs_hdr, &hslot);
1420
1421 if (rc == BCME_OK)
1422 rc = fcommit(commit_ctx, commit_info->p);
1423 else
1424 ctx->stats.generic_error++;
1425
1426 if (rc == BCME_OK) {
1427 ctx->stats.pkt2bus++;
1428 if (commit_info->ac_fifo_credit_spent) {
1429 ctx->stats.sendq_pkts[ac]++;
1430 WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac);
1431 }
1432 }
1433 else {
1434 /*
1435 bus commit has failed, rollback.
1436 - remove wl-header for a delayed packet
1437 - save wl-header header for suppressed packets
1438 */
1439 rc = _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p,
1440 (commit_info->pkt_type), hslot);
1441 if (rc != BCME_OK)
1442 ctx->stats.rollback_failed++;
1443
1444 rc = BCME_ERROR;
1445 }
1446
1447 return rc;
1448}
1449
1450int
1451dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx)
1452{
1453 int ac;
1454 int credit;
1455 int rc;
1456 dhd_wlfc_commit_info_t commit_info;
1457 athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state;
1458 int credit_count = 0;
1459 int bus_retry_count = 0;
1460 uint8 ac_available = 0; /* Bitmask for 4 ACs + BC/MC */
1461
1462 if ((state == NULL) ||
1463 (fcommit == NULL)) {
1464 WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__));
1465 return BCME_BADARG;
1466 }
1467
1468 memset(&commit_info, 0, sizeof(commit_info));
1469
1470 /*
1471 Commit packets for regular AC traffic. Higher priority first.
1472 First, use up FIFO credits available to each AC. Based on distribution
1473 and credits left, borrow from other ACs as applicable
1474
1475 -NOTE:
1476 If the bus between the host and firmware is overwhelmed by the
1477 traffic from host, it is possible that higher priority traffic
1478 starves the lower priority queue. If that occurs often, we may
1479 have to employ weighted round-robin or ucode scheme to avoid
1480 low priority packet starvation.
1481 */
1482
1483 for (ac = AC_COUNT; ac >= 0; ac--) {
1484
1485 int initial_credit_count = ctx->FIFO_credit[ac];
1486
1487 for (credit = 0; credit < ctx->FIFO_credit[ac];) {
1488 commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac,
1489 &(commit_info.ac_fifo_credit_spent),
1490 &(commit_info.needs_hdr),
1491 &(commit_info.mac_entry));
1492
1493 if (commit_info.p == NULL)
1494 break;
1495
1496 commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED :
1497 eWLFC_PKTTYPE_SUPPRESSED;
1498
1499 rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info,
1500 fcommit, commit_ctx);
1501
1502 /* Bus commits may fail (e.g. flow control); abort after retries */
1503 if (rc == BCME_OK) {
1504 if (commit_info.ac_fifo_credit_spent) {
1505 credit++;
1506 }
1507 }
1508 else {
1509 bus_retry_count++;
1510 if (bus_retry_count >= BUS_RETRIES) {
1511 DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
1512 ctx->FIFO_credit[ac] -= credit;
1513 return rc;
1514 }
1515 }
1516 }
1517
1518 ctx->FIFO_credit[ac] -= credit;
1519
1520 /* packets from SENDQ are fresh and they'd need header and have no MAC entry */
1521 commit_info.needs_hdr = 1;
1522 commit_info.mac_entry = NULL;
1523 commit_info.pkt_type = eWLFC_PKTTYPE_NEW;
1524
1525 for (credit = 0; credit < ctx->FIFO_credit[ac];) {
1526 commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac,
1527 &(commit_info.ac_fifo_credit_spent));
1528 if (commit_info.p == NULL)
1529 break;
1530
1531 rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info,
1532 fcommit, commit_ctx);
1533
1534 /* Bus commits may fail (e.g. flow control); abort after retries */
1535 if (rc == BCME_OK) {
1536 if (commit_info.ac_fifo_credit_spent) {
1537 credit++;
1538 }
1539 }
1540 else {
1541 bus_retry_count++;
1542 if (bus_retry_count >= BUS_RETRIES) {
1543 DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
1544 ctx->FIFO_credit[ac] -= credit;
1545 return rc;
1546 }
1547 }
1548 }
1549
1550 ctx->FIFO_credit[ac] -= credit;
1551
1552 /* If no credits were used, the queue is idle and can be re-used
1553 Note that resv credits cannot be borrowed
1554 */
1555 if (initial_credit_count == ctx->FIFO_credit[ac]) {
1556 ac_available |= (1 << ac);
1557 credit_count += ctx->FIFO_credit[ac];
1558 }
1559 }
1560
1561 /* We borrow only for AC_BE and only if no other traffic seen for DEFER_PERIOD
1562
1563 Note that (ac_available & WLFC_AC_BE_TRAFFIC_ONLY) is done to:
1564 a) ignore BC/MC for deferring borrow
1565 b) ignore AC_BE being available along with other ACs
1566 (this should happen only for pure BC/MC traffic)
1567
1568 i.e. AC_VI, AC_VO, AC_BK all MUST be available (i.e. no traffic) and
1569 we do not care if AC_BE and BC/MC are available or not
1570 */
1571 if ((ac_available & WLFC_AC_BE_TRAFFIC_ONLY) == WLFC_AC_BE_TRAFFIC_ONLY) {
1572
1573 if (ctx->allow_credit_borrow) {
1574 ac = 1; /* Set ac to AC_BE and borrow credits */
1575 }
1576 else {
1577 int delta;
1578 int curr_t = OSL_SYSUPTIME();
1579
1580 if (curr_t > ctx->borrow_defer_timestamp)
1581 delta = curr_t - ctx->borrow_defer_timestamp;
1582 else
1583 delta = 0xffffffff + curr_t - ctx->borrow_defer_timestamp;
1584
1585 if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) {
1586 /* Reset borrow but defer to next iteration (defensive borrowing) */
1587 ctx->allow_credit_borrow = TRUE;
1588 ctx->borrow_defer_timestamp = 0;
1589 }
1590 return BCME_OK;
1591 }
1592 }
1593 else {
1594 /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */
1595 ctx->allow_credit_borrow = FALSE;
1596 ctx->borrow_defer_timestamp = OSL_SYSUPTIME();
1597 return BCME_OK;
1598 }
1599
1600 /* At this point, borrow all credits only for "ac" (which should be set above to AC_BE)
1601 Generically use "ac" only in case we extend to all ACs in future
1602 */
1603 for (; (credit_count > 0);) {
1604
1605 commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac,
1606 &(commit_info.ac_fifo_credit_spent),
1607 &(commit_info.needs_hdr),
1608 &(commit_info.mac_entry));
1609 if (commit_info.p == NULL)
1610 break;
1611
1612 commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED :
1613 eWLFC_PKTTYPE_SUPPRESSED;
1614
1615 rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info,
1616 fcommit, commit_ctx);
1617
1618 /* Bus commits may fail (e.g. flow control); abort after retries */
1619 if (rc == BCME_OK) {
1620 if (commit_info.ac_fifo_credit_spent) {
1621 (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac);
1622 credit_count--;
1623 }
1624 }
1625 else {
1626 bus_retry_count++;
1627 if (bus_retry_count >= BUS_RETRIES) {
1628 DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
1629 return rc;
1630 }
1631 }
1632 }
1633
1634 /* packets from SENDQ are fresh and they'd need header and have no MAC entry */
1635 commit_info.needs_hdr = 1;
1636 commit_info.mac_entry = NULL;
1637 commit_info.pkt_type = eWLFC_PKTTYPE_NEW;
1638
1639 for (; (credit_count > 0);) {
1640
1641 commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac,
1642 &(commit_info.ac_fifo_credit_spent));
1643 if (commit_info.p == NULL)
1644 break;
1645
1646 rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info,
1647 fcommit, commit_ctx);
1648
1649 /* Bus commits may fail (e.g. flow control); abort after retries */
1650 if (rc == BCME_OK) {
1651 if (commit_info.ac_fifo_credit_spent) {
1652 (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac);
1653 credit_count--;
1654 }
1655 }
1656 else {
1657 bus_retry_count++;
1658 if (bus_retry_count >= BUS_RETRIES) {
1659 DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n"));
1660 return rc;
1661 }
1662 }
1663 }
1664
1665 return BCME_OK;
1666}
1667
1668static uint8
1669dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea)
1670{
1671 wlfc_mac_descriptor_t* table =
1672 ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes;
1673 uint8 table_index;
1674
1675 if (ea != NULL) {
1676 for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) {
1677 if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) &&
1678 table[table_index].occupied)
1679 return table_index;
1680 }
1681 }
1682 return WLFC_MAC_DESC_ID_INVALID;
1683}
1684
1685void
1686dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success)
1687{
1688 athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
1689 dhd->wlfc_state;
1690 void* p;
1691 int fifo_id;
1692
1693 if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) {
1694#ifdef PROP_TXSTATUS_DEBUG
1695 wlfc->stats.signal_only_pkts_freed++;
1696#endif
1697 /* is this a signal-only packet? */
1698 PKTFREE(wlfc->osh, txp, TRUE);
1699 return;
1700 }
1701 if (!success) {
1702 WLFC_DBGMESG(("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n",
1703 __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp))));
1704 dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG
1705 (PKTTAG(txp))), &p, 1);
1706
1707 /* indicate failure and free the packet */
1708 dhd_txcomplete(dhd, txp, FALSE);
1709
1710 /* return the credit, if necessary */
1711 if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) {
1712 int lender, credit_returned = 0; /* Note that borrower is fifo_id */
1713
1714 fifo_id = DHD_PKTTAG_FIFO(PKTTAG(txp));
1715
1716 /* Return credits to highest priority lender first */
1717 for (lender = AC_COUNT; lender >= 0; lender--) {
1718 if (wlfc->credits_borrowed[fifo_id][lender] > 0) {
1719 wlfc->FIFO_credit[lender]++;
1720 wlfc->credits_borrowed[fifo_id][lender]--;
1721 credit_returned = 1;
1722 break;
1723 }
1724 }
1725
1726 if (!credit_returned) {
1727 wlfc->FIFO_credit[fifo_id]++;
1728 }
1729 }
1730
1731 PKTFREE(wlfc->osh, txp, TRUE);
1732 }
1733 return;
1734}
1735
1736/* Handle discard or suppress indication */
1737static int
1738dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info)
1739{
1740 uint8 status_flag;
1741 uint32 status;
1742 int ret;
1743 int remove_from_hanger = 1;
1744 void* pktbuf;
1745 uint8 fifo_id;
1746 wlfc_mac_descriptor_t* entry = NULL;
1747 athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
1748 dhd->wlfc_state;
1749
1750 memcpy(&status, pkt_info, sizeof(uint32));
1751 status_flag = WL_TXSTATUS_GET_FLAGS(status);
1752 wlfc->stats.txstatus_in++;
1753
1754 if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) {
1755 wlfc->stats.pkt_freed++;
1756 }
1757
1758 else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) {
1759 wlfc->stats.d11_suppress++;
1760 remove_from_hanger = 0;
1761 }
1762
1763 else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) {
1764 wlfc->stats.wl_suppress++;
1765 remove_from_hanger = 0;
1766 }
1767
1768 else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) {
1769 wlfc->stats.wlc_tossed_pkts++;
1770 }
1771
1772 ret = dhd_wlfc_hanger_poppkt(wlfc->hanger,
1773 WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger);
1774 if (ret != BCME_OK) {
1775 /* do something */
1776 return ret;
1777 }
1778
1779 if (!remove_from_hanger) {
1780 /* this packet was suppressed */
1781
1782 entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf);
1783 entry->generation = WLFC_PKTID_GEN(status);
1784 }
1785
1786#ifdef PROP_TXSTATUS_DEBUG
1787 {
1788 uint32 new_t = OSL_SYSUPTIME();
1789 uint32 old_t;
1790 uint32 delta;
1791 old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[
1792 WLFC_PKTID_HSLOT_GET(status)].push_time;
1793
1794
1795 wlfc->stats.latency_sample_count++;
1796 if (new_t > old_t)
1797 delta = new_t - old_t;
1798 else
1799 delta = 0xffffffff + new_t - old_t;
1800 wlfc->stats.total_status_latency += delta;
1801 wlfc->stats.latency_most_recent = delta;
1802
1803 wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta;
1804 if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32))
1805 wlfc->stats.idx_delta = 0;
1806 }
1807#endif /* PROP_TXSTATUS_DEBUG */
1808
1809 fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf));
1810
1811 /* pick up the implicit credit from this packet */
1812 if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) {
1813 if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) {
1814
1815 int lender, credit_returned = 0; /* Note that borrower is fifo_id */
1816
1817 /* Return credits to highest priority lender first */
1818 for (lender = AC_COUNT; lender >= 0; lender--) {
1819 if (wlfc->credits_borrowed[fifo_id][lender] > 0) {
1820 wlfc->FIFO_credit[lender]++;
1821 wlfc->credits_borrowed[fifo_id][lender]--;
1822 credit_returned = 1;
1823 break;
1824 }
1825 }
1826
1827 if (!credit_returned) {
1828 wlfc->FIFO_credit[fifo_id]++;
1829 }
1830 }
1831 }
1832 else {
1833 /*
1834 if this packet did not count against FIFO credit, it must have
1835 taken a requested_credit from the destination entry (for pspoll etc.)
1836 */
1837 if (!entry) {
1838
1839 entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf);
1840 }
1841 if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf)))
1842 entry->requested_credit++;
1843#ifdef PROP_TXSTATUS_DEBUG
1844 entry->dstncredit_acks++;
1845#endif
1846 }
1847 if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) ||
1848 (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) {
1849 ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf);
1850 if (ret != BCME_OK) {
1851 /* delay q is full, drop this packet */
1852 dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status),
1853 &pktbuf, 1);
1854
1855 /* indicate failure and free the packet */
1856 dhd_txcomplete(dhd, pktbuf, FALSE);
1857 PKTFREE(wlfc->osh, pktbuf, TRUE);
1858 }
1859 }
1860 else {
1861 dhd_txcomplete(dhd, pktbuf, TRUE);
1862 /* free the packet */
1863 PKTFREE(wlfc->osh, pktbuf, TRUE);
1864 }
1865 return BCME_OK;
1866}
1867
1868static int
1869dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits)
1870{
1871 int i;
1872 athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
1873 dhd->wlfc_state;
1874 for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) {
1875#ifdef PROP_TXSTATUS_DEBUG
1876 wlfc->stats.fifo_credits_back[i] += credits[i];
1877#endif
1878 /* update FIFO credits */
1879 if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT)
1880 {
1881 int lender; /* Note that borrower is i */
1882
1883 /* Return credits to highest priority lender first */
1884 for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) {
1885 if (wlfc->credits_borrowed[i][lender] > 0) {
1886 if (credits[i] >= wlfc->credits_borrowed[i][lender]) {
1887 credits[i] -= wlfc->credits_borrowed[i][lender];
1888 wlfc->FIFO_credit[lender] +=
1889 wlfc->credits_borrowed[i][lender];
1890 wlfc->credits_borrowed[i][lender] = 0;
1891 }
1892 else {
1893 wlfc->credits_borrowed[i][lender] -= credits[i];
1894 wlfc->FIFO_credit[lender] += credits[i];
1895 credits[i] = 0;
1896 }
1897 }
1898 }
1899
1900 /* If we have more credits left over, these must belong to the AC */
1901 if (credits[i] > 0) {
1902 wlfc->FIFO_credit[i] += credits[i];
1903 }
1904 }
1905 }
1906
1907 return BCME_OK;
1908}
1909
1910static int
1911dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi)
1912{
1913 (void)dhd;
1914 (void)rssi;
1915 return BCME_OK;
1916}
1917
1918static int
1919dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type)
1920{
1921 int rc;
1922 athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
1923 dhd->wlfc_state;
1924 wlfc_mac_descriptor_t* table;
1925 uint8 existing_index;
1926 uint8 table_index;
1927 uint8 ifid;
1928 uint8* ea;
1929
1930 WLFC_DBGMESG(("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n",
1931 __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7],
1932 ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"),
1933 WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0]));
1934
1935 table = wlfc->destination_entries.nodes;
1936 table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]);
1937 ifid = value[1];
1938 ea = &value[2];
1939
1940 if (type == WLFC_CTL_TYPE_MACDESC_ADD) {
1941 existing_index = dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]);
1942 if (existing_index == WLFC_MAC_DESC_ID_INVALID) {
1943 /* this MAC entry does not exist, create one */
1944 if (!table[table_index].occupied) {
1945 table[table_index].mac_handle = value[0];
1946 rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index],
1947 eWLFC_MAC_ENTRY_ACTION_ADD, ifid,
1948 wlfc->destination_entries.interfaces[ifid].iftype,
1949 ea);
1950 }
1951 else {
1952 /* the space should have been empty, but it's not */
1953 wlfc->stats.mac_update_failed++;
1954 }
1955 }
1956 else {
1957 /*
1958 there is an existing entry, move it to new index
1959 if necessary.
1960 */
1961 if (existing_index != table_index) {
1962 /* if we already have an entry, free the old one */
1963 table[existing_index].occupied = 0;
1964 table[existing_index].state = WLFC_STATE_CLOSE;
1965 table[existing_index].requested_credit = 0;
1966 table[existing_index].interface_id = 0;
1967 }
1968 }
1969 }
1970 if (type == WLFC_CTL_TYPE_MACDESC_DEL) {
1971 if (table[table_index].occupied) {
1972 rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index],
1973 eWLFC_MAC_ENTRY_ACTION_DEL, ifid,
1974 wlfc->destination_entries.interfaces[ifid].iftype,
1975 ea);
1976 }
1977 else {
1978 /* the space should have been occupied, but it's not */
1979 wlfc->stats.mac_update_failed++;
1980 }
1981 }
1982 return BCME_OK;
1983}
1984
1985static int
1986dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type)
1987{
1988 /* Handle PS on/off indication */
1989 athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
1990 dhd->wlfc_state;
1991 wlfc_mac_descriptor_t* table;
1992 wlfc_mac_descriptor_t* desc;
1993 uint8 mac_handle = value[0];
1994 int i;
1995
1996 table = wlfc->destination_entries.nodes;
1997 desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)];
1998 if (desc->occupied) {
1999 /* a fresh PS mode should wipe old ps credits? */
2000 desc->requested_credit = 0;
2001 if (type == WLFC_CTL_TYPE_MAC_OPEN) {
2002 desc->state = WLFC_STATE_OPEN;
2003 DHD_WLFC_CTRINC_MAC_OPEN(desc);
2004 }
2005 else {
2006 desc->state = WLFC_STATE_CLOSE;
2007 DHD_WLFC_CTRINC_MAC_CLOSE(desc);
2008 /*
2009 Indicate to firmware if there is any traffic pending.
2010 */
2011 for (i = AC_BE; i < AC_COUNT; i++) {
2012 _dhd_wlfc_traffic_pending_check(wlfc, desc, i);
2013 }
2014 }
2015 }
2016 else {
2017 wlfc->stats.psmode_update_failed++;
2018 }
2019 return BCME_OK;
2020}
2021
2022static int
2023dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type)
2024{
2025 /* Handle PS on/off indication */
2026 athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
2027 dhd->wlfc_state;
2028 wlfc_mac_descriptor_t* table;
2029 uint8 if_id = value[0];
2030
2031 if (if_id < WLFC_MAX_IFNUM) {
2032 table = wlfc->destination_entries.interfaces;
2033 if (table[if_id].occupied) {
2034 if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) {
2035 table[if_id].state = WLFC_STATE_OPEN;
2036 /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */
2037 }
2038 else {
2039 table[if_id].state = WLFC_STATE_CLOSE;
2040 /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */
2041 }
2042 return BCME_OK;
2043 }
2044 }
2045 wlfc->stats.interface_update_failed++;
2046
2047 return BCME_OK;
2048}
2049
2050static int
2051dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value)
2052{
2053 athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
2054 dhd->wlfc_state;
2055 wlfc_mac_descriptor_t* table;
2056 wlfc_mac_descriptor_t* desc;
2057 uint8 mac_handle;
2058 uint8 credit;
2059
2060 table = wlfc->destination_entries.nodes;
2061 mac_handle = value[1];
2062 credit = value[0];
2063
2064 desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)];
2065 if (desc->occupied) {
2066 desc->requested_credit = credit;
2067
2068 desc->ac_bitmap = value[2];
2069 }
2070 else {
2071 wlfc->stats.credit_request_failed++;
2072 }
2073 return BCME_OK;
2074}
2075
2076static int
2077dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value)
2078{
2079 athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
2080 dhd->wlfc_state;
2081 wlfc_mac_descriptor_t* table;
2082 wlfc_mac_descriptor_t* desc;
2083 uint8 mac_handle;
2084 uint8 packet_count;
2085
2086 table = wlfc->destination_entries.nodes;
2087 mac_handle = value[1];
2088 packet_count = value[0];
2089
2090 desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)];
2091 if (desc->occupied) {
2092 desc->requested_packet = packet_count;
2093
2094 desc->ac_bitmap = value[2];
2095 }
2096 else {
2097 wlfc->stats.packet_request_failed++;
2098 }
2099 return BCME_OK;
2100}
2101
2102static int
2103dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len)
2104{
2105 uint8 type, len;
2106 uint8* value;
2107 uint8* tmpbuf;
2108 uint16 remainder = tlv_hdr_len;
2109 uint16 processed = 0;
2110 athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
2111 dhd->wlfc_state;
2112 tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf);
2113 if (remainder) {
2114 while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) {
2115 type = tmpbuf[processed];
2116 if (type == WLFC_CTL_TYPE_FILLER) {
2117 remainder -= 1;
2118 processed += 1;
2119 continue;
2120 }
2121
2122 len = tmpbuf[processed + 1];
2123 value = &tmpbuf[processed + 2];
2124
2125 if (remainder < (2 + len))
2126 break;
2127
2128 remainder -= 2 + len;
2129 processed += 2 + len;
2130 if (type == WLFC_CTL_TYPE_TXSTATUS)
2131 dhd_wlfc_txstatus_update(dhd, value);
2132
2133 else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK)
2134 dhd_wlfc_fifocreditback_indicate(dhd, value);
2135
2136 else if (type == WLFC_CTL_TYPE_RSSI)
2137 dhd_wlfc_rssi_indicate(dhd, value);
2138
2139 else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT)
2140 dhd_wlfc_credit_request(dhd, value);
2141
2142 else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET)
2143 dhd_wlfc_packet_request(dhd, value);
2144
2145 else if ((type == WLFC_CTL_TYPE_MAC_OPEN) ||
2146 (type == WLFC_CTL_TYPE_MAC_CLOSE))
2147 dhd_wlfc_psmode_update(dhd, value, type);
2148
2149 else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) ||
2150 (type == WLFC_CTL_TYPE_MACDESC_DEL))
2151 dhd_wlfc_mac_table_update(dhd, value, type);
2152
2153 else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) ||
2154 (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) {
2155 dhd_wlfc_interface_update(dhd, value, type);
2156 }
2157 }
2158 if (remainder != 0) {
2159 /* trouble..., something is not right */
2160 wlfc->stats.tlv_parse_failed++;
2161 }
2162 }
2163 return BCME_OK;
2164}
2165
2166int
2167dhd_wlfc_init(dhd_pub_t *dhd)
2168{
2169 char iovbuf[12]; /* Room for "tlv" + '\0' + parameter */
2170 /* enable all signals & indicate host proptxstatus logic is active */
2171 uint32 tlv = dhd->wlfc_enabled?
2172 WLFC_FLAGS_RSSI_SIGNALS |
2173 WLFC_FLAGS_XONXOFF_SIGNALS |
2174 WLFC_FLAGS_CREDIT_STATUS_SIGNALS |
2175 WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE : 0;
2176
2177
2178 /*
2179 try to enable/disable signaling by sending "tlv" iovar. if that fails,
2180 fallback to no flow control? Print a message for now.
2181 */
2182
2183 /* enable proptxtstatus signaling by default */
2184 bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf));
2185 if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) {
2186 DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n"));
2187 }
2188 else {
2189 /*
2190 Leaving the message for now, it should be removed after a while; once
2191 the tlv situation is stable.
2192 */
2193 DHD_ERROR(("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n",
2194 dhd->wlfc_enabled?"enabled":"disabled", tlv));
2195 }
2196 return BCME_OK;
2197}
2198
2199int
2200dhd_wlfc_enable(dhd_pub_t *dhd)
2201{
2202 int i;
2203 athost_wl_status_info_t* wlfc;
2204
2205 if (!dhd->wlfc_enabled || dhd->wlfc_state)
2206 return BCME_OK;
2207
2208 /* allocate space to track txstatus propagated from firmware */
2209 dhd->wlfc_state = MALLOC(dhd->osh, sizeof(athost_wl_status_info_t));
2210 if (dhd->wlfc_state == NULL)
2211 return BCME_NOMEM;
2212
2213 /* initialize state space */
2214 wlfc = (athost_wl_status_info_t*)dhd->wlfc_state;
2215 memset(wlfc, 0, sizeof(athost_wl_status_info_t));
2216
2217 /* remember osh & dhdp */
2218 wlfc->osh = dhd->osh;
2219 wlfc->dhdp = dhd;
2220
2221 wlfc->hanger =
2222 dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS);
2223 if (wlfc->hanger == NULL) {
2224 MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t));
2225 dhd->wlfc_state = NULL;
2226 return BCME_NOMEM;
2227 }
2228
2229 /* initialize all interfaces to accept traffic */
2230 for (i = 0; i < WLFC_MAX_IFNUM; i++) {
2231 wlfc->hostif_flow_state[i] = OFF;
2232 }
2233
2234 /*
2235 create the SENDQ containing
2236 sub-queues for all AC precedences + 1 for bc/mc traffic
2237 */
2238 pktq_init(&wlfc->SENDQ, (AC_COUNT + 1), WLFC_SENDQ_LEN);
2239
2240 wlfc->destination_entries.other.state = WLFC_STATE_OPEN;
2241 /* bc/mc FIFO is always open [credit aside], i.e. b[5] */
2242 wlfc->destination_entries.other.ac_bitmap = 0x1f;
2243 wlfc->destination_entries.other.interface_id = 0;
2244
2245 wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT;
2246
2247 wlfc->allow_credit_borrow = TRUE;
2248 wlfc->borrow_defer_timestamp = 0;
2249
2250 return BCME_OK;
2251}
2252
2253/* release all packet resources */
2254void
2255dhd_wlfc_cleanup(dhd_pub_t *dhd)
2256{
2257 int i;
2258 int total_entries;
2259 athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
2260 dhd->wlfc_state;
2261 wlfc_mac_descriptor_t* table;
2262 wlfc_hanger_t* h;
2263
2264 if (dhd->wlfc_state == NULL)
2265 return;
2266
2267 total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t);
2268 /* search all entries, include nodes as well as interfaces */
2269 table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries;
2270
2271 for (i = 0; i < total_entries; i++) {
2272 if (table[i].occupied) {
2273 if (table[i].psq.len) {
2274 WLFC_DBGMESG(("%s(): DELAYQ[%d].len = %d\n",
2275 __FUNCTION__, i, table[i].psq.len));
2276 /* release packets held in DELAYQ */
2277 pktq_flush(wlfc->osh, &table[i].psq, TRUE, NULL, 0);
2278 }
2279 table[i].occupied = 0;
2280 }
2281 }
2282 /* release packets held in SENDQ */
2283 if (wlfc->SENDQ.len)
2284 pktq_flush(wlfc->osh, &wlfc->SENDQ, TRUE, NULL, 0);
2285 /* any in the hanger? */
2286 h = (wlfc_hanger_t*)wlfc->hanger;
2287 for (i = 0; i < h->max_items; i++) {
2288 if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) {
2289 PKTFREE(wlfc->osh, h->items[i].pkt, TRUE);
2290 }
2291 }
2292 return;
2293}
2294
2295void
2296dhd_wlfc_deinit(dhd_pub_t *dhd)
2297{
2298 /* cleanup all psq related resources */
2299 athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*)
2300 dhd->wlfc_state;
2301
2302 if (dhd->wlfc_state == NULL)
2303 return;
2304
2305#ifdef PROP_TXSTATUS_DEBUG
2306 {
2307 int i;
2308 wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger;
2309 for (i = 0; i < h->max_items; i++) {
2310 if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) {
2311 WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n",
2312 __FUNCTION__, i, h->items[i].pkt,
2313 DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt))));
2314 }
2315 }
2316 }
2317#endif
2318 /* delete hanger */
2319 dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger);
2320
2321 /* free top structure */
2322 MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t));
2323 dhd->wlfc_state = NULL;
2324 return;
2325}
2326#endif /* PROP_TXSTATUS */
2327
2328void
2329dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
2330{
2331 bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid);
2332#ifdef PROP_TXSTATUS
2333 if (dhdp->wlfc_state)
2334 dhd_wlfc_dump(dhdp, strbuf);
2335#endif
2336}
2337
2338void
2339dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf)
2340{
2341#ifdef BDC
2342 struct bdc_header *h;
2343#endif /* BDC */
2344
2345 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2346
2347#ifdef BDC
2348 /* Push BDC header used to convey priority for buses that don't */
2349
2350 PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN);
2351
2352 h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);
2353
2354 h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
2355 if (PKTSUMNEEDED(pktbuf))
2356 h->flags |= BDC_FLAG_SUM_NEEDED;
2357
2358
2359 h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK);
2360 h->flags2 = 0;
2361 h->dataOffset = 0;
2362#endif /* BDC */
2363 BDC_SET_IF_IDX(h, ifidx);
2364}
2365
2366int
2367dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf)
2368{
2369#ifdef BDC
2370 struct bdc_header *h;
2371#endif
2372
2373 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2374
2375#ifdef BDC
2376 /* Pop BDC header used to convey priority for buses that don't */
2377
2378 if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) {
2379 DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
2380 PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN));
2381 return BCME_ERROR;
2382 }
2383
2384 h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);
2385
2386 if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) {
2387 DHD_ERROR(("%s: rx data ifnum out of range (%d)\n",
2388 __FUNCTION__, *ifidx));
2389 return BCME_ERROR;
2390 }
2391
2392 if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) {
2393 DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n",
2394 dhd_ifname(dhd, *ifidx), h->flags));
2395 if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1)
2396 h->dataOffset = 0;
2397 else
2398 return BCME_ERROR;
2399 }
2400
2401 if (h->flags & BDC_FLAG_SUM_GOOD) {
2402 DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n",
2403 dhd_ifname(dhd, *ifidx), h->flags));
2404 PKTSETSUMGOOD(pktbuf, TRUE);
2405 }
2406
2407 PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK));
2408 PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN);
2409#endif /* BDC */
2410
2411 if (PKTLEN(dhd->osh, pktbuf) < (uint32) (h->dataOffset << 2)) {
2412 DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
2413 PKTLEN(dhd->osh, pktbuf), (h->dataOffset * 4)));
2414 return BCME_ERROR;
2415 }
2416
2417#ifdef PROP_TXSTATUS
2418 if (dhd->wlfc_state &&
2419 ((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode
2420 != WLFC_FCMODE_NONE &&
2421 (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf)))) {
2422 /*
2423 - parse txstatus only for packets that came from the firmware
2424 */
2425 dhd_os_wlfc_block(dhd);
2426 dhd_wlfc_parse_header_info(dhd, pktbuf, (h->dataOffset << 2));
2427 ((athost_wl_status_info_t*)dhd->wlfc_state)->stats.dhd_hdrpulls++;
2428 dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata,
2429 (void *)dhd->bus);
2430 dhd_os_wlfc_unblock(dhd);
2431 }
2432#endif /* PROP_TXSTATUS */
2433 PKTPULL(dhd->osh, pktbuf, (h->dataOffset << 2));
2434 return 0;
2435}
2436
2437int
2438dhd_prot_attach(dhd_pub_t *dhd)
2439{
2440 dhd_prot_t *cdc;
2441
2442 if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd->osh, DHD_PREALLOC_PROT,
2443 sizeof(dhd_prot_t)))) {
2444 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
2445 goto fail;
2446 }
2447 memset(cdc, 0, sizeof(dhd_prot_t));
2448
2449 /* ensure that the msg buf directly follows the cdc msg struct */
2450 if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) {
2451 DHD_ERROR(("dhd_prot_t is not correctly defined\n"));
2452 goto fail;
2453 }
2454
2455 dhd->prot = cdc;
2456#ifdef BDC
2457 dhd->hdrlen += BDC_HEADER_LEN;
2458#endif
2459 dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN;
2460 return 0;
2461
2462fail:
2463#ifndef DHD_USE_STATIC_BUF
2464 if (cdc != NULL)
2465 MFREE(dhd->osh, cdc, sizeof(dhd_prot_t));
2466#endif
2467 return BCME_NOMEM;
2468}
2469
2470/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */
2471void
2472dhd_prot_detach(dhd_pub_t *dhd)
2473{
2474#ifdef PROP_TXSTATUS
2475 dhd_wlfc_deinit(dhd);
2476#endif
2477#ifndef DHD_USE_STATIC_BUF
2478 MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t));
2479#endif
2480 dhd->prot = NULL;
2481}
2482
2483void
2484dhd_prot_dstats(dhd_pub_t *dhd)
2485{
2486 /* No stats from dongle added yet, copy bus stats */
2487 dhd->dstats.tx_packets = dhd->tx_packets;
2488 dhd->dstats.tx_errors = dhd->tx_errors;
2489 dhd->dstats.rx_packets = dhd->rx_packets;
2490 dhd->dstats.rx_errors = dhd->rx_errors;
2491 dhd->dstats.rx_dropped = dhd->rx_dropped;
2492 dhd->dstats.multicast = dhd->rx_multicast;
2493 return;
2494}
2495
2496int
2497dhd_prot_init(dhd_pub_t *dhd)
2498{
2499 int ret = 0;
2500 wlc_rev_info_t revinfo;
2501 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2502
2503
2504 /* Get the device rev info */
2505 memset(&revinfo, 0, sizeof(revinfo));
2506 ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0);
2507 if (ret < 0)
2508 goto done;
2509
2510
2511#ifdef PROP_TXSTATUS
2512 ret = dhd_wlfc_init(dhd);
2513#endif
2514
2515#if !defined(WL_CFG80211)
2516 ret = dhd_preinit_ioctls(dhd);
2517#endif /* WL_CFG80211 */
2518
2519 /* Always assumes wl for now */
2520 dhd->iswl = TRUE;
2521
2522done:
2523 return ret;
2524}
2525
2526void
2527dhd_prot_stop(dhd_pub_t *dhd)
2528{
2529 /* Nothing to do for CDC */
2530}
diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c
new file mode 100644
index 00000000000..372ec80c866
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_common.c
@@ -0,0 +1,2306 @@
1/*
2 * Broadcom Dongle Host Driver (DHD), common DHD core.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: dhd_common.c 290546 2011-10-19 01:55:21Z $
25 */
26#include <typedefs.h>
27#include <osl.h>
28
29#include <epivers.h>
30#include <bcmutils.h>
31
32#include <bcmendian.h>
33#include <dngl_stats.h>
34#include <wlioctl.h>
35#include <dhd.h>
36
37#include <proto/bcmevent.h>
38
39#include <dhd_bus.h>
40#include <dhd_proto.h>
41#include <dhd_dbg.h>
42#include <msgtrace.h>
43
44#ifdef WL_CFG80211
45#include <wl_cfg80211.h>
46#endif
47#include <proto/bt_amp_hci.h>
48#include <dhd_bta.h>
49#ifdef SET_RANDOM_MAC_SOFTAP
50#include <linux/random.h>
51#include <linux/jiffies.h>
52#endif
53
54#ifdef PROP_TXSTATUS
55#include <wlfc_proto.h>
56#include <dhd_wlfc.h>
57#endif
58
59
60#ifdef WLMEDIA_HTSF
61extern void htsf_update(struct dhd_info *dhd, void *data);
62#endif
63int dhd_msg_level = DHD_ERROR_VAL;
64
65
66#include <wl_iw.h>
67
68char fw_path[MOD_PARAM_PATHLEN];
69char nv_path[MOD_PARAM_PATHLEN];
70
71#ifdef SOFTAP
72char fw_path2[MOD_PARAM_PATHLEN];
73extern bool softap_enabled;
74#endif
75
76/* Last connection success/failure status */
77uint32 dhd_conn_event;
78uint32 dhd_conn_status;
79uint32 dhd_conn_reason;
80
81#define htod32(i) i
82#define htod16(i) i
83#define dtoh32(i) i
84#define dtoh16(i) i
85extern int dhd_iscan_request(void * dhdp, uint16 action);
86extern void dhd_ind_scan_confirm(void *h, bool status);
87extern int dhd_iscan_in_progress(void *h);
88void dhd_iscan_lock(void);
89void dhd_iscan_unlock(void);
90extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx);
91bool ap_cfg_running = FALSE;
92bool ap_fw_loaded = FALSE;
93
94
95#ifdef DHD_DEBUG
96const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on "
97 __DATE__ " at " __TIME__;
98#else
99const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR;
100#endif
101
102void dhd_set_timer(void *bus, uint wdtick);
103
104/* IOVar table */
105enum {
106 IOV_VERSION = 1,
107 IOV_MSGLEVEL,
108 IOV_BCMERRORSTR,
109 IOV_BCMERROR,
110 IOV_WDTICK,
111 IOV_DUMP,
112 IOV_CLEARCOUNTS,
113 IOV_LOGDUMP,
114 IOV_LOGCAL,
115 IOV_LOGSTAMP,
116 IOV_GPIOOB,
117 IOV_IOCTLTIMEOUT,
118 IOV_HCI_CMD, /* HCI command */
119 IOV_HCI_ACL_DATA, /* HCI data packet */
120#if defined(DHD_DEBUG)
121 IOV_CONS,
122 IOV_DCONSOLE_POLL,
123#endif /* defined(DHD_DEBUG) */
124#ifdef PROP_TXSTATUS
125 IOV_PROPTXSTATUS_ENABLE,
126 IOV_PROPTXSTATUS_MODE,
127#endif
128 IOV_BUS_TYPE,
129#ifdef WLMEDIA_HTSF
130 IOV_WLPKTDLYSTAT_SZ,
131#endif
132 IOV_CHANGEMTU,
133 IOV_LAST
134};
135
136const bcm_iovar_t dhd_iovars[] = {
137 {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) },
138#ifdef DHD_DEBUG
139 {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
140#endif /* DHD_DEBUG */
141 {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN },
142 {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 },
143 {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 },
144 {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
145#ifdef DHD_DEBUG
146 {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 },
147 {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 },
148#endif
149 {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 },
150 {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 },
151 {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 },
152 {"HCI_cmd", IOV_HCI_CMD, 0, IOVT_BUFFER, 0},
153 {"HCI_ACL_data", IOV_HCI_ACL_DATA, 0, IOVT_BUFFER, 0},
154#ifdef PROP_TXSTATUS
155 {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_UINT32, 0 },
156 /*
157 set the proptxtstatus operation mode:
158 0 - Do not do any proptxtstatus flow control
159 1 - Use implied credit from a packet status
160 2 - Use explicit credit
161 */
162 {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 },
163#endif
164 {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0},
165#ifdef WLMEDIA_HTSF
166 {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 },
167#endif
168 {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 },
169 {NULL, 0, 0, 0, 0 }
170};
171
172struct dhd_cmn *
173dhd_common_init(uint16 devid, osl_t *osh)
174{
175 dhd_cmn_t *cmn;
176
177 /* Init global variables at run-time, not as part of the declaration.
178 * This is required to support init/de-init of the driver. Initialization
179 * of globals as part of the declaration results in non-deterministic
180 * behavior since the value of the globals may be different on the
181 * first time that the driver is initialized vs subsequent initializations.
182 */
183 /* Allocate private bus interface state */
184 if (!(cmn = MALLOC(osh, sizeof(dhd_cmn_t)))) {
185 DHD_ERROR(("%s: MALLOC failed\n", __FUNCTION__));
186 return NULL;
187 }
188 memset(cmn, 0, sizeof(dhd_cmn_t));
189 cmn->osh = osh;
190
191#ifdef CONFIG_BCMDHD_FW_PATH
192 bcm_strncpy_s(fw_path, sizeof(fw_path), CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1);
193#elif defined(CONFIG_BCMDHD_FW_DIR) /* CONFIG_BCMDHD_FW_PATH */
194 sprintf(fw_path, "%s/bcm%x/fw_bcmdhd.bin", CONFIG_BCMDHD_FW_DIR, devid);
195#else
196 fw_path[0] = '\0';
197#endif /* CONFIG_BCMDHD_FW_DIR */
198#ifdef CONFIG_BCMDHD_NVRAM_PATH
199 bcm_strncpy_s(nv_path, sizeof(nv_path), CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1);
200#elif defined(CONFIG_BCMDHD_NVRAM_DIR) /* CONFIG_BCMDHD_NVRAM_PATH */
201 sprintf(nv_path, "%s/nvram_%x.txt", CONFIG_BCMDHD_NVRAM_DIR, devid);
202#else
203 nv_path[0] = '\0';
204#endif /* CONFIG_BCMDHD_NVRAM_PATH */
205#ifdef SOFTAP
206 fw_path2[0] = '\0';
207#endif
208 DHD_ERROR(("bcmdhd: fw_path: %s nvram_path: %s\n", fw_path, nv_path));
209 return cmn;
210}
211
212void
213dhd_common_deinit(dhd_pub_t *dhd_pub, dhd_cmn_t *sa_cmn)
214{
215 osl_t *osh;
216 dhd_cmn_t *cmn;
217
218 if (dhd_pub != NULL)
219 cmn = dhd_pub->cmn;
220 else
221 cmn = sa_cmn;
222
223 if (!cmn)
224 return;
225
226 osh = cmn->osh;
227
228 if (dhd_pub != NULL)
229 dhd_pub->cmn = NULL;
230 MFREE(osh, cmn, sizeof(dhd_cmn_t));
231}
232
233static int
234dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
235{
236 char eabuf[ETHER_ADDR_STR_LEN];
237
238 struct bcmstrbuf b;
239 struct bcmstrbuf *strbuf = &b;
240
241 bcm_binit(strbuf, buf, buflen);
242
243 /* Base DHD info */
244 bcm_bprintf(strbuf, "%s\n", dhd_version);
245 bcm_bprintf(strbuf, "\n");
246 bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
247 dhdp->up, dhdp->txoff, dhdp->busstate);
248 bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n",
249 dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz);
250 bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n",
251 dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf));
252 bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror, dhdp->tickcnt);
253
254 bcm_bprintf(strbuf, "dongle stats:\n");
255 bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n",
256 dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes,
257 dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped);
258 bcm_bprintf(strbuf, "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n",
259 dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes,
260 dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped);
261 bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast);
262
263 bcm_bprintf(strbuf, "bus stats:\n");
264 bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n",
265 dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors);
266 bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n",
267 dhdp->tx_ctlpkts, dhdp->tx_ctlerrs);
268 bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n",
269 dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors);
270 bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld\n",
271 dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped);
272 bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld\n",
273 dhdp->rx_readahead_cnt, dhdp->tx_realloc);
274 bcm_bprintf(strbuf, "\n");
275
276 /* Add any prot info */
277 dhd_prot_dump(dhdp, strbuf);
278 bcm_bprintf(strbuf, "\n");
279
280 /* Add any bus info */
281 dhd_bus_dump(dhdp, strbuf);
282
283 return (!strbuf->size ? BCME_BUFTOOSHORT : 0);
284}
285
286int
287dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex)
288{
289 wl_ioctl_t ioc;
290
291 ioc.cmd = cmd;
292 ioc.buf = arg;
293 ioc.len = len;
294 ioc.set = set;
295
296 return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len);
297}
298
299
300int
301dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len)
302{
303 int ret;
304
305 dhd_os_proto_block(dhd_pub);
306
307 ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len);
308 if (!ret)
309 dhd_os_check_hang(dhd_pub, ifindex, ret);
310
311 dhd_os_proto_unblock(dhd_pub);
312 return ret;
313}
314
315static int
316dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name,
317 void *params, int plen, void *arg, int len, int val_size)
318{
319 int bcmerror = 0;
320 int32 int_val = 0;
321
322 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
323 DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name));
324
325 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
326 goto exit;
327
328 if (plen >= (int)sizeof(int_val))
329 bcopy(params, &int_val, sizeof(int_val));
330
331 switch (actionid) {
332 case IOV_GVAL(IOV_VERSION):
333 /* Need to have checked buffer length */
334 bcm_strncpy_s((char*)arg, len, dhd_version, len);
335 break;
336
337 case IOV_GVAL(IOV_MSGLEVEL):
338 int_val = (int32)dhd_msg_level;
339 bcopy(&int_val, arg, val_size);
340 break;
341
342 case IOV_SVAL(IOV_MSGLEVEL):
343 dhd_msg_level = int_val;
344 break;
345 case IOV_GVAL(IOV_BCMERRORSTR):
346 bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN);
347 ((char *)arg)[BCME_STRLEN - 1] = 0x00;
348 break;
349
350 case IOV_GVAL(IOV_BCMERROR):
351 int_val = (int32)dhd_pub->bcmerror;
352 bcopy(&int_val, arg, val_size);
353 break;
354
355 case IOV_GVAL(IOV_WDTICK):
356 int_val = (int32)dhd_watchdog_ms;
357 bcopy(&int_val, arg, val_size);
358 break;
359
360 case IOV_SVAL(IOV_WDTICK):
361 if (!dhd_pub->up) {
362 bcmerror = BCME_NOTUP;
363 break;
364 }
365 dhd_os_wd_timer(dhd_pub, (uint)int_val);
366 break;
367
368 case IOV_GVAL(IOV_DUMP):
369 bcmerror = dhd_dump(dhd_pub, arg, len);
370 break;
371
372#ifdef DHD_DEBUG
373 case IOV_GVAL(IOV_DCONSOLE_POLL):
374 int_val = (int32)dhd_console_ms;
375 bcopy(&int_val, arg, val_size);
376 break;
377
378 case IOV_SVAL(IOV_DCONSOLE_POLL):
379 dhd_console_ms = (uint)int_val;
380 break;
381
382 case IOV_SVAL(IOV_CONS):
383 if (len > 0)
384 bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
385 break;
386#endif /* DHD_DEBUG */
387
388 case IOV_SVAL(IOV_CLEARCOUNTS):
389 dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
390 dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
391 dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
392 dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
393 dhd_pub->rx_dropped = 0;
394 dhd_pub->rx_readahead_cnt = 0;
395 dhd_pub->tx_realloc = 0;
396 dhd_pub->wd_dpc_sched = 0;
397 memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats));
398 dhd_bus_clearcounts(dhd_pub);
399#ifdef PROP_TXSTATUS
400 /* clear proptxstatus related counters */
401 if (dhd_pub->wlfc_state) {
402 athost_wl_status_info_t *wlfc =
403 (athost_wl_status_info_t*)dhd_pub->wlfc_state;
404 wlfc_hanger_t* hanger;
405
406 memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t));
407
408 hanger = (wlfc_hanger_t*)wlfc->hanger;
409 hanger->pushed = 0;
410 hanger->popped = 0;
411 hanger->failed_slotfind = 0;
412 hanger->failed_to_pop = 0;
413 hanger->failed_to_push = 0;
414 }
415#endif /* PROP_TXSTATUS */
416 break;
417
418
419 case IOV_GVAL(IOV_IOCTLTIMEOUT): {
420 int_val = (int32)dhd_os_get_ioctl_resp_timeout();
421 bcopy(&int_val, arg, sizeof(int_val));
422 break;
423 }
424
425 case IOV_SVAL(IOV_IOCTLTIMEOUT): {
426 if (int_val <= 0)
427 bcmerror = BCME_BADARG;
428 else
429 dhd_os_set_ioctl_resp_timeout((unsigned int)int_val);
430 break;
431 }
432
433 case IOV_SVAL(IOV_HCI_CMD): {
434 amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)arg;
435
436 /* sanity check: command preamble present */
437 if (len < HCI_CMD_PREAMBLE_SIZE)
438 return BCME_BUFTOOSHORT;
439
440 /* sanity check: command parameters are present */
441 if (len < (int)(HCI_CMD_PREAMBLE_SIZE + cmd->plen))
442 return BCME_BUFTOOSHORT;
443
444 dhd_bta_docmd(dhd_pub, cmd, len);
445 break;
446 }
447
448 case IOV_SVAL(IOV_HCI_ACL_DATA): {
449 amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)arg;
450
451 /* sanity check: HCI header present */
452 if (len < HCI_ACL_DATA_PREAMBLE_SIZE)
453 return BCME_BUFTOOSHORT;
454
455 /* sanity check: ACL data is present */
456 if (len < (int)(HCI_ACL_DATA_PREAMBLE_SIZE + ACL_data->dlen))
457 return BCME_BUFTOOSHORT;
458
459 dhd_bta_tx_hcidata(dhd_pub, ACL_data, len);
460 break;
461 }
462
463#ifdef PROP_TXSTATUS
464 case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE):
465 int_val = dhd_pub->wlfc_enabled? 1 : 0;
466 bcopy(&int_val, arg, val_size);
467 break;
468
469 case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE):
470 dhd_pub->wlfc_enabled = int_val? 1 : 0;
471 break;
472
473 case IOV_GVAL(IOV_PROPTXSTATUS_MODE): {
474 athost_wl_status_info_t *wlfc =
475 (athost_wl_status_info_t*)dhd_pub->wlfc_state;
476 int_val = dhd_pub->wlfc_state ? (int32)wlfc->proptxstatus_mode : 0;
477 bcopy(&int_val, arg, val_size);
478 break;
479 }
480
481 case IOV_SVAL(IOV_PROPTXSTATUS_MODE):
482 if (dhd_pub->wlfc_state) {
483 athost_wl_status_info_t *wlfc =
484 (athost_wl_status_info_t*)dhd_pub->wlfc_state;
485 wlfc->proptxstatus_mode = int_val & 0xff;
486 }
487 break;
488#endif /* PROP_TXSTATUS */
489
490 case IOV_GVAL(IOV_BUS_TYPE):
491 /* The dhd application queries the driver to check if its usb or sdio. */
492#ifdef BCMDHDUSB
493 int_val = BUS_TYPE_USB;
494#endif
495 int_val = BUS_TYPE_SDIO;
496 bcopy(&int_val, arg, val_size);
497 break;
498
499
500#ifdef WLMEDIA_HTSF
501 case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ):
502 int_val = dhd_pub->htsfdlystat_sz;
503 bcopy(&int_val, arg, val_size);
504 break;
505
506 case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ):
507 dhd_pub->htsfdlystat_sz = int_val & 0xff;
508 printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz);
509 break;
510#endif
511 case IOV_SVAL(IOV_CHANGEMTU):
512 int_val &= 0xffff;
513 bcmerror = dhd_change_mtu(dhd_pub, int_val, 0);
514 break;
515
516 default:
517 bcmerror = BCME_UNSUPPORTED;
518 break;
519 }
520
521exit:
522 DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror));
523 return bcmerror;
524}
525
526/* Store the status of a connection attempt for later retrieval by an iovar */
527void
528dhd_store_conn_status(uint32 event, uint32 status, uint32 reason)
529{
530 /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID
531 * because an encryption/rsn mismatch results in both events, and
532 * the important information is in the WLC_E_PRUNE.
533 */
534 if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL &&
535 dhd_conn_event == WLC_E_PRUNE)) {
536 dhd_conn_event = event;
537 dhd_conn_status = status;
538 dhd_conn_reason = reason;
539 }
540}
541
542bool
543dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
544{
545 void *p;
546 int eprec = -1; /* precedence to evict from */
547 bool discard_oldest;
548
549 /* Fast case, precedence queue is not full and we are also not
550 * exceeding total queue length
551 */
552 if (!pktq_pfull(q, prec) && !pktq_full(q)) {
553 pktq_penq(q, prec, pkt);
554 return TRUE;
555 }
556
557 /* Determine precedence from which to evict packet, if any */
558 if (pktq_pfull(q, prec))
559 eprec = prec;
560 else if (pktq_full(q)) {
561 p = pktq_peek_tail(q, &eprec);
562 ASSERT(p);
563 if (eprec > prec || eprec < 0)
564 return FALSE;
565 }
566
567 /* Evict if needed */
568 if (eprec >= 0) {
569 /* Detect queueing to unconfigured precedence */
570 ASSERT(!pktq_pempty(q, eprec));
571 discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec);
572 if (eprec == prec && !discard_oldest)
573 return FALSE; /* refuse newer (incoming) packet */
574 /* Evict packet according to discard policy */
575 p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec);
576 ASSERT(p);
577
578 PKTFREE(dhdp->osh, p, TRUE);
579 }
580
581 /* Enqueue */
582 p = pktq_penq(q, prec, pkt);
583 ASSERT(p);
584
585 return TRUE;
586}
587
588static int
589dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name,
590 void *params, int plen, void *arg, int len, bool set)
591{
592 int bcmerror = 0;
593 int val_size;
594 const bcm_iovar_t *vi = NULL;
595 uint32 actionid;
596
597 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
598
599 ASSERT(name);
600 ASSERT(len >= 0);
601
602 /* Get MUST have return space */
603 ASSERT(set || (arg && len));
604
605 /* Set does NOT take qualifiers */
606 ASSERT(!set || (!params && !plen));
607
608 if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) {
609 bcmerror = BCME_UNSUPPORTED;
610 goto exit;
611 }
612
613 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
614 name, (set ? "set" : "get"), len, plen));
615
616 /* set up 'params' pointer in case this is a set command so that
617 * the convenience int and bool code can be common to set and get
618 */
619 if (params == NULL) {
620 params = arg;
621 plen = len;
622 }
623
624 if (vi->type == IOVT_VOID)
625 val_size = 0;
626 else if (vi->type == IOVT_BUFFER)
627 val_size = len;
628 else
629 /* all other types are integer sized */
630 val_size = sizeof(int);
631
632 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
633
634 bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size);
635
636exit:
637 return bcmerror;
638}
639
640int
641dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen)
642{
643 int bcmerror = 0;
644
645 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
646
647 if (!buf) {
648 return BCME_BADARG;
649 }
650
651 switch (ioc->cmd) {
652 case DHD_GET_MAGIC:
653 if (buflen < sizeof(int))
654 bcmerror = BCME_BUFTOOSHORT;
655 else
656 *(int*)buf = DHD_IOCTL_MAGIC;
657 break;
658
659 case DHD_GET_VERSION:
660 if (buflen < sizeof(int))
661 bcmerror = -BCME_BUFTOOSHORT;
662 else
663 *(int*)buf = DHD_IOCTL_VERSION;
664 break;
665
666 case DHD_GET_VAR:
667 case DHD_SET_VAR: {
668 char *arg;
669 uint arglen;
670
671 /* scan past the name to any arguments */
672 for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--)
673 ;
674
675 if (*arg) {
676 bcmerror = BCME_BUFTOOSHORT;
677 break;
678 }
679
680 /* account for the NUL terminator */
681 arg++, arglen--;
682
683 /* call with the appropriate arguments */
684 if (ioc->cmd == DHD_GET_VAR)
685 bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen,
686 buf, buflen, IOV_GET);
687 else
688 bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET);
689 if (bcmerror != BCME_UNSUPPORTED)
690 break;
691
692 /* not in generic table, try protocol module */
693 if (ioc->cmd == DHD_GET_VAR)
694 bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg,
695 arglen, buf, buflen, IOV_GET);
696 else
697 bcmerror = dhd_prot_iovar_op(dhd_pub, buf,
698 NULL, 0, arg, arglen, IOV_SET);
699 if (bcmerror != BCME_UNSUPPORTED)
700 break;
701
702 /* if still not found, try bus module */
703 if (ioc->cmd == DHD_GET_VAR) {
704 bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
705 arg, arglen, buf, buflen, IOV_GET);
706 } else {
707 bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
708 NULL, 0, arg, arglen, IOV_SET);
709 }
710
711 break;
712 }
713
714 default:
715 bcmerror = BCME_UNSUPPORTED;
716 }
717
718 return bcmerror;
719}
720
721#ifdef SHOW_EVENTS
722static void
723wl_show_host_event(wl_event_msg_t *event, void *event_data)
724{
725 uint i, status, reason;
726 bool group = FALSE, flush_txq = FALSE, link = FALSE;
727 const char *auth_str;
728 const char *event_name;
729 uchar *buf;
730 char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
731 uint event_type, flags, auth_type, datalen;
732
733 event_type = ntoh32(event->event_type);
734 flags = ntoh16(event->flags);
735 status = ntoh32(event->status);
736 reason = ntoh32(event->reason);
737 auth_type = ntoh32(event->auth_type);
738 datalen = ntoh32(event->datalen);
739
740 /* debug dump of event messages */
741 sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x",
742 (uchar)event->addr.octet[0]&0xff,
743 (uchar)event->addr.octet[1]&0xff,
744 (uchar)event->addr.octet[2]&0xff,
745 (uchar)event->addr.octet[3]&0xff,
746 (uchar)event->addr.octet[4]&0xff,
747 (uchar)event->addr.octet[5]&0xff);
748
749 event_name = "UNKNOWN";
750 for (i = 0; i < (uint)bcmevent_names_size; i++)
751 if (bcmevent_names[i].event == event_type)
752 event_name = bcmevent_names[i].name;
753
754 if (flags & WLC_EVENT_MSG_LINK)
755 link = TRUE;
756 if (flags & WLC_EVENT_MSG_GROUP)
757 group = TRUE;
758 if (flags & WLC_EVENT_MSG_FLUSHTXQ)
759 flush_txq = TRUE;
760
761 switch (event_type) {
762 case WLC_E_START:
763 case WLC_E_DEAUTH:
764 case WLC_E_DISASSOC:
765 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
766 break;
767
768 case WLC_E_ASSOC_IND:
769 case WLC_E_REASSOC_IND:
770
771 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
772 break;
773
774 case WLC_E_ASSOC:
775 case WLC_E_REASSOC:
776 if (status == WLC_E_STATUS_SUCCESS) {
777 DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf));
778 } else if (status == WLC_E_STATUS_TIMEOUT) {
779 DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf));
780 } else if (status == WLC_E_STATUS_FAIL) {
781 DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
782 event_name, eabuf, (int)reason));
783 } else {
784 DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n",
785 event_name, eabuf, (int)status));
786 }
787 break;
788
789 case WLC_E_DEAUTH_IND:
790 case WLC_E_DISASSOC_IND:
791 DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason));
792 break;
793
794 case WLC_E_AUTH:
795 case WLC_E_AUTH_IND:
796 if (auth_type == DOT11_OPEN_SYSTEM)
797 auth_str = "Open System";
798 else if (auth_type == DOT11_SHARED_KEY)
799 auth_str = "Shared Key";
800 else {
801 sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
802 auth_str = err_msg;
803 }
804 if (event_type == WLC_E_AUTH_IND) {
805 DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str));
806 } else if (status == WLC_E_STATUS_SUCCESS) {
807 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
808 event_name, eabuf, auth_str));
809 } else if (status == WLC_E_STATUS_TIMEOUT) {
810 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
811 event_name, eabuf, auth_str));
812 } else if (status == WLC_E_STATUS_FAIL) {
813 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
814 event_name, eabuf, auth_str, (int)reason));
815 }
816
817 break;
818
819 case WLC_E_JOIN:
820 case WLC_E_ROAM:
821 case WLC_E_SET_SSID:
822 if (status == WLC_E_STATUS_SUCCESS) {
823 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
824 } else if (status == WLC_E_STATUS_FAIL) {
825 DHD_EVENT(("MACEVENT: %s, failed\n", event_name));
826 } else if (status == WLC_E_STATUS_NO_NETWORKS) {
827 DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name));
828 } else {
829 DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
830 event_name, (int)status));
831 }
832 break;
833
834 case WLC_E_BEACON_RX:
835 if (status == WLC_E_STATUS_SUCCESS) {
836 DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
837 } else if (status == WLC_E_STATUS_FAIL) {
838 DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
839 } else {
840 DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status));
841 }
842 break;
843
844 case WLC_E_LINK:
845 DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN"));
846 break;
847
848 case WLC_E_MIC_ERROR:
849 DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
850 event_name, eabuf, group, flush_txq));
851 break;
852
853 case WLC_E_ICV_ERROR:
854 case WLC_E_UNICAST_DECODE_ERROR:
855 case WLC_E_MULTICAST_DECODE_ERROR:
856 DHD_EVENT(("MACEVENT: %s, MAC %s\n",
857 event_name, eabuf));
858 break;
859
860 case WLC_E_TXFAIL:
861 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf));
862 break;
863
864 case WLC_E_SCAN_COMPLETE:
865 case WLC_E_PMKID_CACHE:
866 DHD_EVENT(("MACEVENT: %s\n", event_name));
867 break;
868
869 case WLC_E_PFN_NET_FOUND:
870 case WLC_E_PFN_NET_LOST:
871 case WLC_E_PFN_SCAN_COMPLETE:
872 case WLC_E_PFN_SCAN_NONE:
873 case WLC_E_PFN_SCAN_ALLGONE:
874 DHD_EVENT(("PNOEVENT: %s\n", event_name));
875 break;
876
877 case WLC_E_PSK_SUP:
878 case WLC_E_PRUNE:
879 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
880 event_name, (int)status, (int)reason));
881 break;
882
883#ifdef WIFI_ACT_FRAME
884 case WLC_E_ACTION_FRAME:
885 DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf));
886 break;
887#endif /* WIFI_ACT_FRAME */
888
889 case WLC_E_TRACE: {
890 static uint32 seqnum_prev = 0;
891 msgtrace_hdr_t hdr;
892 uint32 nblost;
893 char *s, *p;
894
895 buf = (uchar *) event_data;
896 memcpy(&hdr, buf, MSGTRACE_HDRLEN);
897
898 if (hdr.version != MSGTRACE_VERSION) {
899 printf("\nMACEVENT: %s [unsupported version --> "
900 "dhd version:%d dongle version:%d]\n",
901 event_name, MSGTRACE_VERSION, hdr.version);
902 /* Reset datalen to avoid display below */
903 datalen = 0;
904 break;
905 }
906
907 /* There are 2 bytes available at the end of data */
908 buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0';
909
910 if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) {
911 printf("\nWLC_E_TRACE: [Discarded traces in dongle -->"
912 "discarded_bytes %d discarded_printf %d]\n",
913 ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf));
914 }
915
916 nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1;
917 if (nblost > 0) {
918 printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n",
919 ntoh32(hdr.seqnum), nblost);
920 }
921 seqnum_prev = ntoh32(hdr.seqnum);
922
923 /* Display the trace buffer. Advance from \n to \n to avoid display big
924 * printf (issue with Linux printk )
925 */
926 p = (char *)&buf[MSGTRACE_HDRLEN];
927 while ((s = strstr(p, "\n")) != NULL) {
928 *s = '\0';
929 printf("%s\n", p);
930 p = s+1;
931 }
932 printf("%s\n", p);
933
934 /* Reset datalen to avoid display below */
935 datalen = 0;
936 break;
937 }
938
939
940 case WLC_E_RSSI:
941 DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))));
942 break;
943
944 default:
945 DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
946 event_name, event_type, eabuf, (int)status, (int)reason,
947 (int)auth_type));
948 break;
949 }
950
951 /* show any appended data */
952 if (datalen) {
953 buf = (uchar *) event_data;
954 DHD_EVENT((" data (%d) : ", datalen));
955 for (i = 0; i < datalen; i++)
956 DHD_EVENT((" 0x%02x ", *buf++));
957 DHD_EVENT(("\n"));
958 }
959}
960#endif /* SHOW_EVENTS */
961
962int
963wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
964 wl_event_msg_t *event, void **data_ptr)
965{
966 /* check whether packet is a BRCM event pkt */
967 bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
968 uint8 *event_data;
969 uint32 type, status, reason, datalen;
970 uint16 flags;
971 int evlen;
972
973 if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
974 DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__));
975 return (BCME_ERROR);
976 }
977
978 /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
979 if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) {
980 DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__));
981 return (BCME_ERROR);
982 }
983
984 *data_ptr = &pvt_data[1];
985 event_data = *data_ptr;
986
987 /* memcpy since BRCM event pkt may be unaligned. */
988 memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
989
990 type = ntoh32_ua((void *)&event->event_type);
991 flags = ntoh16_ua((void *)&event->flags);
992 status = ntoh32_ua((void *)&event->status);
993 reason = ntoh32_ua((void *)&event->reason);
994 datalen = ntoh32_ua((void *)&event->datalen);
995 evlen = datalen + sizeof(bcm_event_t);
996
997 switch (type) {
998#ifdef PROP_TXSTATUS
999 case WLC_E_FIFO_CREDIT_MAP:
1000 dhd_wlfc_event(dhd_pub->info);
1001 dhd_wlfc_FIFOcreditmap_event(dhd_pub->info, event_data);
1002 WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): "
1003 "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1],
1004 event_data[2],
1005 event_data[3], event_data[4], event_data[5]));
1006 break;
1007#endif
1008
1009 case WLC_E_IF:
1010 {
1011 dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data;
1012#ifdef PROP_TXSTATUS
1013 {
1014 uint8* ea = pvt_data->eth.ether_dhost;
1015 WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, "
1016 "[%02x:%02x:%02x:%02x:%02x:%02x]\n",
1017 ifevent->ifidx,
1018 ((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"),
1019 ((ifevent->is_AP == 0) ? "STA":"AP "),
1020 ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]));
1021 (void)ea;
1022
1023 dhd_wlfc_interface_event(dhd_pub->info,
1024 ((ifevent->action == WLC_E_IF_ADD) ?
1025 eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL),
1026 ifevent->ifidx, ifevent->is_AP, ea);
1027
1028 /* dhd already has created an interface by default, for 0 */
1029 if (ifevent->ifidx == 0)
1030 break;
1031 }
1032#endif /* PROP_TXSTATUS */
1033
1034#ifdef WL_CFG80211
1035 if (wl_cfg80211_is_progress_ifchange()) {
1036 DHD_ERROR(("%s: ifidx %d for %s action %d\n",
1037 __FUNCTION__, ifevent->ifidx,
1038 event->ifname, ifevent->action));
1039 if (ifevent->action == WLC_E_IF_ADD)
1040 wl_cfg80211_notify_ifchange();
1041 return (BCME_OK);
1042 }
1043#endif /* WL_CFG80211 */
1044 if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) {
1045 if (ifevent->action == WLC_E_IF_ADD) {
1046 if (dhd_add_if(dhd_pub->info, ifevent->ifidx,
1047 NULL, event->ifname,
1048 event->addr.octet,
1049 ifevent->flags, ifevent->bssidx)) {
1050 DHD_ERROR(("%s: dhd_add_if failed!!"
1051 " ifidx: %d for %s\n",
1052 __FUNCTION__,
1053 ifevent->ifidx,
1054 event->ifname));
1055 return (BCME_ERROR);
1056 }
1057 }
1058 else
1059 dhd_del_if(dhd_pub->info, ifevent->ifidx);
1060 } else {
1061#ifndef PROP_TXSTATUS
1062 DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
1063 __FUNCTION__, ifevent->ifidx, event->ifname));
1064#endif /* !PROP_TXSTATUS */
1065 }
1066 }
1067 /* send up the if event: btamp user needs it */
1068 *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
1069 /* push up to external supp/auth */
1070 dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
1071 break;
1072
1073
1074#ifdef WLMEDIA_HTSF
1075 case WLC_E_HTSFSYNC:
1076 htsf_update(dhd_pub->info, event_data);
1077 break;
1078#endif /* WLMEDIA_HTSF */
1079 case WLC_E_NDIS_LINK: {
1080 uint32 temp = hton32(WLC_E_LINK);
1081
1082 memcpy((void *)(&pvt_data->event.event_type), &temp,
1083 sizeof(pvt_data->event.event_type));
1084 }
1085 /* These are what external supplicant/authenticator wants */
1086 /* fall through */
1087 case WLC_E_LINK:
1088 case WLC_E_DEAUTH:
1089 case WLC_E_DEAUTH_IND:
1090 case WLC_E_DISASSOC:
1091 case WLC_E_DISASSOC_IND:
1092 DHD_EVENT(("%s: Link event %d, flags %x, status %x\n",
1093 __FUNCTION__, type, flags, status));
1094 /* fall through */
1095 default:
1096 *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
1097 /* push up to external supp/auth */
1098 dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
1099 DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
1100 __FUNCTION__, type, flags, status));
1101
1102 /* put it back to WLC_E_NDIS_LINK */
1103 if (type == WLC_E_NDIS_LINK) {
1104 uint32 temp;
1105
1106 temp = ntoh32_ua((void *)&event->event_type);
1107 DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp));
1108
1109 temp = ntoh32(WLC_E_NDIS_LINK);
1110 memcpy((void *)(&pvt_data->event.event_type), &temp,
1111 sizeof(pvt_data->event.event_type));
1112 }
1113 break;
1114 }
1115
1116#ifdef SHOW_EVENTS
1117 wl_show_host_event(event, (void *)event_data);
1118#endif /* SHOW_EVENTS */
1119
1120 return (BCME_OK);
1121}
1122
1123void
1124wl_event_to_host_order(wl_event_msg_t * evt)
1125{
1126 /* Event struct members passed from dongle to host are stored in network
1127 * byte order. Convert all members to host-order.
1128 */
1129 evt->event_type = ntoh32(evt->event_type);
1130 evt->flags = ntoh16(evt->flags);
1131 evt->status = ntoh32(evt->status);
1132 evt->reason = ntoh32(evt->reason);
1133 evt->auth_type = ntoh32(evt->auth_type);
1134 evt->datalen = ntoh32(evt->datalen);
1135 evt->version = ntoh16(evt->version);
1136}
1137
1138void
1139dhd_print_buf(void *pbuf, int len, int bytes_per_line)
1140{
1141#ifdef DHD_DEBUG
1142 int i, j = 0;
1143 unsigned char *buf = pbuf;
1144
1145 if (bytes_per_line == 0) {
1146 bytes_per_line = len;
1147 }
1148
1149 for (i = 0; i < len; i++) {
1150 printf("%2.2x", *buf++);
1151 j++;
1152 if (j == bytes_per_line) {
1153 printf("\n");
1154 j = 0;
1155 } else {
1156 printf(":");
1157 }
1158 }
1159 printf("\n");
1160#endif /* DHD_DEBUG */
1161}
1162
1163#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
1164
1165/* Convert user's input in hex pattern to byte-size mask */
1166static int
1167wl_pattern_atoh(char *src, char *dst)
1168{
1169 int i;
1170 if (strncmp(src, "0x", 2) != 0 &&
1171 strncmp(src, "0X", 2) != 0) {
1172 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
1173 return -1;
1174 }
1175 src = src + 2; /* Skip past 0x */
1176 if (strlen(src) % 2 != 0) {
1177 DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
1178 return -1;
1179 }
1180 for (i = 0; *src != '\0'; i++) {
1181 char num[3];
1182 bcm_strncpy_s(num, sizeof(num), src, 2);
1183 num[2] = '\0';
1184 dst[i] = (uint8)strtoul(num, NULL, 16);
1185 src += 2;
1186 }
1187 return i;
1188}
1189
1190void
1191dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode)
1192{
1193 char *argv[8];
1194 int i = 0;
1195 const char *str;
1196 int buf_len;
1197 int str_len;
1198 char *arg_save = 0, *arg_org = 0;
1199 int rc;
1200 char buf[128];
1201 wl_pkt_filter_enable_t enable_parm;
1202 wl_pkt_filter_enable_t * pkt_filterp;
1203
1204 if (!arg)
1205 return;
1206
1207 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
1208 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1209 goto fail;
1210 }
1211 arg_org = arg_save;
1212 memcpy(arg_save, arg, strlen(arg) + 1);
1213
1214 argv[i] = bcmstrtok(&arg_save, " ", 0);
1215
1216 i = 0;
1217 if (argv[i] == NULL) {
1218 DHD_ERROR(("No args provided\n"));
1219 goto fail;
1220 }
1221
1222 str = "pkt_filter_enable";
1223 str_len = strlen(str);
1224 bcm_strncpy_s(buf, sizeof(buf), str, str_len);
1225 buf[str_len] = '\0';
1226 buf_len = str_len + 1;
1227
1228 pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1);
1229
1230 /* Parse packet filter id. */
1231 enable_parm.id = htod32(strtoul(argv[i], NULL, 0));
1232
1233 /* Parse enable/disable value. */
1234 enable_parm.enable = htod32(enable);
1235
1236 buf_len += sizeof(enable_parm);
1237 memcpy((char *)pkt_filterp,
1238 &enable_parm,
1239 sizeof(enable_parm));
1240
1241 /* Enable/disable the specified filter. */
1242 rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
1243 rc = rc >= 0 ? 0 : rc;
1244 if (rc)
1245 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1246 __FUNCTION__, arg, rc));
1247 else
1248 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1249 __FUNCTION__, arg));
1250
1251 /* Contorl the master mode */
1252 bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf));
1253 rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
1254 rc = rc >= 0 ? 0 : rc;
1255 if (rc)
1256 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1257 __FUNCTION__, arg, rc));
1258
1259fail:
1260 if (arg_org)
1261 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
1262}
1263
1264void
1265dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg)
1266{
1267 const char *str;
1268 wl_pkt_filter_t pkt_filter;
1269 wl_pkt_filter_t *pkt_filterp;
1270 int buf_len;
1271 int str_len;
1272 int rc;
1273 uint32 mask_size;
1274 uint32 pattern_size;
1275 char *argv[8], * buf = 0;
1276 int i = 0;
1277 char *arg_save = 0, *arg_org = 0;
1278#define BUF_SIZE 2048
1279
1280 if (!arg)
1281 return;
1282
1283 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
1284 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1285 goto fail;
1286 }
1287
1288 arg_org = arg_save;
1289
1290 if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
1291 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1292 goto fail;
1293 }
1294
1295 memcpy(arg_save, arg, strlen(arg) + 1);
1296
1297 if (strlen(arg) > BUF_SIZE) {
1298 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf)));
1299 goto fail;
1300 }
1301
1302 argv[i] = bcmstrtok(&arg_save, " ", 0);
1303 while (argv[i++])
1304 argv[i] = bcmstrtok(&arg_save, " ", 0);
1305
1306 i = 0;
1307 if (argv[i] == NULL) {
1308 DHD_ERROR(("No args provided\n"));
1309 goto fail;
1310 }
1311
1312 str = "pkt_filter_add";
1313 str_len = strlen(str);
1314 bcm_strncpy_s(buf, BUF_SIZE, str, str_len);
1315 buf[ str_len ] = '\0';
1316 buf_len = str_len + 1;
1317
1318 pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
1319
1320 /* Parse packet filter id. */
1321 pkt_filter.id = htod32(strtoul(argv[i], NULL, 0));
1322
1323 if (argv[++i] == NULL) {
1324 DHD_ERROR(("Polarity not provided\n"));
1325 goto fail;
1326 }
1327
1328 /* Parse filter polarity. */
1329 pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0));
1330
1331 if (argv[++i] == NULL) {
1332 DHD_ERROR(("Filter type not provided\n"));
1333 goto fail;
1334 }
1335
1336 /* Parse filter type. */
1337 pkt_filter.type = htod32(strtoul(argv[i], NULL, 0));
1338
1339 if (argv[++i] == NULL) {
1340 DHD_ERROR(("Offset not provided\n"));
1341 goto fail;
1342 }
1343
1344 /* Parse pattern filter offset. */
1345 pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0));
1346
1347 if (argv[++i] == NULL) {
1348 DHD_ERROR(("Bitmask not provided\n"));
1349 goto fail;
1350 }
1351
1352 /* Parse pattern filter mask. */
1353 mask_size =
1354 htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern));
1355
1356 if (argv[++i] == NULL) {
1357 DHD_ERROR(("Pattern not provided\n"));
1358 goto fail;
1359 }
1360
1361 /* Parse pattern filter pattern. */
1362 pattern_size =
1363 htod32(wl_pattern_atoh(argv[i],
1364 (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
1365
1366 if (mask_size != pattern_size) {
1367 DHD_ERROR(("Mask and pattern not the same size\n"));
1368 goto fail;
1369 }
1370
1371 pkt_filter.u.pattern.size_bytes = mask_size;
1372 buf_len += WL_PKT_FILTER_FIXED_LEN;
1373 buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
1374
1375 /* Keep-alive attributes are set in local variable (keep_alive_pkt), and
1376 ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
1377 ** guarantee that the buffer is properly aligned.
1378 */
1379 memcpy((char *)pkt_filterp,
1380 &pkt_filter,
1381 WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
1382
1383 rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
1384 rc = rc >= 0 ? 0 : rc;
1385
1386 if (rc)
1387 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1388 __FUNCTION__, arg, rc));
1389 else
1390 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1391 __FUNCTION__, arg));
1392
1393fail:
1394 if (arg_org)
1395 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
1396
1397 if (buf)
1398 MFREE(dhd->osh, buf, BUF_SIZE);
1399}
1400
1401/* ========================== */
1402/* ==== ARP OFFLOAD SUPPORT = */
1403/* ========================== */
1404#ifdef ARP_OFFLOAD_SUPPORT
1405void
1406dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode)
1407{
1408 char iovbuf[32];
1409 int retcode;
1410
1411 bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
1412 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1413 retcode = retcode >= 0 ? 0 : retcode;
1414 if (retcode)
1415 DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
1416 __FUNCTION__, arp_mode, retcode));
1417 else
1418 DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
1419 __FUNCTION__, arp_mode));
1420}
1421
1422void
1423dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable)
1424{
1425 char iovbuf[32];
1426 int retcode;
1427
1428 bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
1429 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1430 retcode = retcode >= 0 ? 0 : retcode;
1431 if (retcode)
1432 DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
1433 __FUNCTION__, arp_enable, retcode));
1434 else
1435 DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
1436 __FUNCTION__, arp_enable));
1437}
1438
1439void
1440dhd_aoe_arp_clr(dhd_pub_t *dhd)
1441{
1442 int ret = 0;
1443 int iov_len = 0;
1444 char iovbuf[128];
1445
1446 if (dhd == NULL) return;
1447
1448 iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf));
1449 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0) < 0))
1450 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1451}
1452
1453void
1454dhd_aoe_hostip_clr(dhd_pub_t *dhd)
1455{
1456 int ret = 0;
1457 int iov_len = 0;
1458 char iovbuf[128];
1459
1460 if (dhd == NULL) return;
1461
1462 iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf));
1463 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0)) < 0)
1464 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1465}
1466
1467void
1468dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr)
1469{
1470 int iov_len = 0;
1471 char iovbuf[32];
1472 int retcode;
1473
1474 iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, 4, iovbuf, sizeof(iovbuf));
1475 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0);
1476
1477 if (retcode)
1478 DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n",
1479 __FUNCTION__, retcode));
1480 else
1481 DHD_TRACE(("%s: sARP H ipaddr entry added \n",
1482 __FUNCTION__));
1483}
1484
1485int
1486dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen)
1487{
1488 int retcode, i;
1489 int iov_len = 0;
1490 uint32 *ptr32 = buf;
1491 bool clr_bottom = FALSE;
1492
1493 if (!buf)
1494 return -1;
1495
1496 iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen);
1497 retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, TRUE, 0);
1498
1499 if (retcode) {
1500 DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n",
1501 __FUNCTION__, retcode));
1502
1503 return -1;
1504 }
1505
1506 /* clean up the buf, ascii reminder */
1507 for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
1508 if (!clr_bottom) {
1509 if (*ptr32 == 0)
1510 clr_bottom = TRUE;
1511 } else {
1512 *ptr32 = 0;
1513 }
1514 ptr32++;
1515 }
1516
1517 return 0;
1518}
1519#endif /* ARP_OFFLOAD_SUPPORT */
1520
1521/* send up locally generated event */
1522void
1523dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
1524{
1525 switch (ntoh32(event->event_type)) {
1526 case WLC_E_BTA_HCI_EVENT:
1527 break;
1528 default:
1529 break;
1530 }
1531
1532 /* Call per-port handler. */
1533 dhd_sendup_event(dhdp, event, data);
1534}
1535
1536#ifdef SIMPLE_ISCAN
1537
1538uint iscan_thread_id = 0;
1539iscan_buf_t * iscan_chain = 0;
1540
1541iscan_buf_t *
1542dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf)
1543{
1544 iscan_buf_t *iscanbuf_alloc = 0;
1545 iscan_buf_t *iscanbuf_head;
1546
1547 DHD_ISCAN(("%s: Entered\n", __FUNCTION__));
1548 dhd_iscan_lock();
1549
1550 iscanbuf_alloc = (iscan_buf_t*)MALLOC(dhd->osh, sizeof(iscan_buf_t));
1551 if (iscanbuf_alloc == NULL)
1552 goto fail;
1553
1554 iscanbuf_alloc->next = NULL;
1555 iscanbuf_head = *iscanbuf;
1556
1557 DHD_ISCAN(("%s: addr of allocated node = 0x%X"
1558 "addr of iscanbuf_head = 0x%X dhd = 0x%X\n",
1559 __FUNCTION__, iscanbuf_alloc, iscanbuf_head, dhd));
1560
1561 if (iscanbuf_head == NULL) {
1562 *iscanbuf = iscanbuf_alloc;
1563 DHD_ISCAN(("%s: Head is allocated\n", __FUNCTION__));
1564 goto fail;
1565 }
1566
1567 while (iscanbuf_head->next)
1568 iscanbuf_head = iscanbuf_head->next;
1569
1570 iscanbuf_head->next = iscanbuf_alloc;
1571
1572fail:
1573 dhd_iscan_unlock();
1574 return iscanbuf_alloc;
1575}
1576
1577void
1578dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete)
1579{
1580 iscan_buf_t *iscanbuf_free = 0;
1581 iscan_buf_t *iscanbuf_prv = 0;
1582 iscan_buf_t *iscanbuf_cur;
1583 dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1584 DHD_ISCAN(("%s: Entered\n", __FUNCTION__));
1585
1586 dhd_iscan_lock();
1587
1588 iscanbuf_cur = iscan_chain;
1589
1590 /* If iscan_delete is null then delete the entire
1591 * chain or else delete specific one provided
1592 */
1593 if (!iscan_delete) {
1594 while (iscanbuf_cur) {
1595 iscanbuf_free = iscanbuf_cur;
1596 iscanbuf_cur = iscanbuf_cur->next;
1597 iscanbuf_free->next = 0;
1598 MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t));
1599 }
1600 iscan_chain = 0;
1601 } else {
1602 while (iscanbuf_cur) {
1603 if (iscanbuf_cur == iscan_delete)
1604 break;
1605 iscanbuf_prv = iscanbuf_cur;
1606 iscanbuf_cur = iscanbuf_cur->next;
1607 }
1608 if (iscanbuf_prv)
1609 iscanbuf_prv->next = iscan_delete->next;
1610
1611 iscan_delete->next = 0;
1612 MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t));
1613
1614 if (!iscanbuf_prv)
1615 iscan_chain = 0;
1616 }
1617 dhd_iscan_unlock();
1618}
1619
1620iscan_buf_t *
1621dhd_iscan_result_buf(void)
1622{
1623 return iscan_chain;
1624}
1625
1626int
1627dhd_iscan_issue_request(void * dhdp, wl_iscan_params_t *pParams, uint32 size)
1628{
1629 int rc = -1;
1630 dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1631 char *buf;
1632 char iovar[] = "iscan";
1633 uint32 allocSize = 0;
1634 wl_ioctl_t ioctl;
1635
1636 if (pParams) {
1637 allocSize = (size + strlen(iovar) + 1);
1638 if ((allocSize < size) || (allocSize < strlen(iovar)))
1639 {
1640 DHD_ERROR(("%s: overflow - allocation size too large %d < %d + %d!\n",
1641 __FUNCTION__, allocSize, size, strlen(iovar)));
1642 goto cleanUp;
1643 }
1644 buf = MALLOC(dhd->osh, allocSize);
1645
1646 if (buf == NULL)
1647 {
1648 DHD_ERROR(("%s: malloc of size %d failed!\n", __FUNCTION__, allocSize));
1649 goto cleanUp;
1650 }
1651 ioctl.cmd = WLC_SET_VAR;
1652 bcm_mkiovar(iovar, (char *)pParams, size, buf, allocSize);
1653 rc = dhd_wl_ioctl(dhd, 0, &ioctl, buf, allocSize);
1654 }
1655
1656cleanUp:
1657 if (buf) {
1658 MFREE(dhd->osh, buf, allocSize);
1659 }
1660
1661 return rc;
1662}
1663
1664static int
1665dhd_iscan_get_partial_result(void *dhdp, uint *scan_count)
1666{
1667 wl_iscan_results_t *list_buf;
1668 wl_iscan_results_t list;
1669 wl_scan_results_t *results;
1670 iscan_buf_t *iscan_cur;
1671 int status = -1;
1672 dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1673 int rc;
1674 wl_ioctl_t ioctl;
1675
1676 DHD_ISCAN(("%s: Enter\n", __FUNCTION__));
1677
1678 iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain);
1679 if (!iscan_cur) {
1680 DHD_ERROR(("%s: Failed to allocate node\n", __FUNCTION__));
1681 dhd_iscan_free_buf(dhdp, 0);
1682 dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT);
1683 dhd_ind_scan_confirm(dhdp, FALSE);
1684 goto fail;
1685 }
1686
1687 dhd_iscan_lock();
1688
1689 memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
1690 list_buf = (wl_iscan_results_t*)iscan_cur->iscan_buf;
1691 results = &list_buf->results;
1692 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
1693 results->version = 0;
1694 results->count = 0;
1695
1696 memset(&list, 0, sizeof(list));
1697 list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
1698 bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE,
1699 iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1700 ioctl.cmd = WLC_GET_VAR;
1701 ioctl.set = FALSE;
1702 rc = dhd_wl_ioctl(dhd, 0, &ioctl, iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1703
1704 results->buflen = dtoh32(results->buflen);
1705 results->version = dtoh32(results->version);
1706 *scan_count = results->count = dtoh32(results->count);
1707 status = dtoh32(list_buf->status);
1708 DHD_ISCAN(("%s: Got %d resuls status = (%x)\n", __FUNCTION__, results->count, status));
1709
1710 dhd_iscan_unlock();
1711
1712 if (!(*scan_count)) {
1713 /* TODO: race condition when FLUSH already called */
1714 dhd_iscan_free_buf(dhdp, 0);
1715 }
1716fail:
1717 return status;
1718}
1719
1720#endif /* SIMPLE_ISCAN */
1721
1722/*
1723 * returns = TRUE if associated, FALSE if not associated
1724 */
1725bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf)
1726{
1727 char bssid[6], zbuf[6];
1728 int ret = -1;
1729
1730 bzero(bssid, 6);
1731 bzero(zbuf, 6);
1732
1733 ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0);
1734 DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret));
1735
1736 if (ret == BCME_NOTASSOCIATED) {
1737 DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret));
1738 }
1739
1740 if (ret < 0)
1741 return FALSE;
1742
1743 if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) {
1744 /* STA is assocoated BSSID is non zero */
1745
1746 if (bss_buf) {
1747 /* return bss if caller provided buf */
1748 memcpy(bss_buf, bssid, ETHER_ADDR_LEN);
1749 }
1750 return TRUE;
1751 } else {
1752 DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__));
1753 return FALSE;
1754 }
1755}
1756
1757
1758/* Function to estimate possible DTIM_SKIP value */
1759int
1760dhd_get_dtim_skip(dhd_pub_t *dhd)
1761{
1762 int bcn_li_dtim;
1763 int ret = -1;
1764 int dtim_assoc = 0;
1765
1766 if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1))
1767 bcn_li_dtim = 3;
1768 else
1769 bcn_li_dtim = dhd->dtim_skip;
1770
1771 /* Check if associated */
1772 if (dhd_is_associated(dhd, NULL) == FALSE) {
1773 DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret));
1774 goto exit;
1775 }
1776
1777 /* if assoc grab ap's dtim value */
1778 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD,
1779 &dtim_assoc, sizeof(dtim_assoc), FALSE, 0)) < 0) {
1780 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1781 goto exit;
1782 }
1783
1784 DHD_ERROR(("%s bcn_li_dtim=%d DTIM=%d Listen=%d\n",
1785 __FUNCTION__, bcn_li_dtim, dtim_assoc, LISTEN_INTERVAL));
1786
1787 /* if not assocated just eixt */
1788 if (dtim_assoc == 0) {
1789 goto exit;
1790 }
1791
1792 /* check if sta listen interval fits into AP dtim */
1793 if (dtim_assoc > LISTEN_INTERVAL) {
1794 /* AP DTIM to big for our Listen Interval : no dtim skiping */
1795 bcn_li_dtim = 1;
1796 DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n",
1797 __FUNCTION__, dtim_assoc, LISTEN_INTERVAL));
1798 goto exit;
1799 }
1800
1801 if ((bcn_li_dtim * dtim_assoc) > LISTEN_INTERVAL) {
1802 /* Round up dtim_skip to fit into STAs Listen Interval */
1803 bcn_li_dtim = (int)(LISTEN_INTERVAL / dtim_assoc);
1804 DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim));
1805 }
1806
1807exit:
1808 return bcn_li_dtim;
1809}
1810
1811/* Check if HostAPD or WFD mode setup */
1812bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd)
1813{
1814#ifdef WL_CFG80211
1815 if (((dhd->op_mode & HOSTAPD_MASK) == HOSTAPD_MASK) ||
1816 ((dhd->op_mode & WFD_MASK) == WFD_MASK))
1817 return TRUE;
1818 else
1819#endif /* WL_CFG80211 */
1820 return FALSE;
1821}
1822
1823#ifdef PNO_SUPPORT
1824int
1825dhd_pno_clean(dhd_pub_t *dhd)
1826{
1827 char iovbuf[128];
1828 int pfn_enabled = 0;
1829 int iov_len = 0;
1830 int ret;
1831
1832 /* Disable pfn */
1833 iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf));
1834 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) >= 0) {
1835 /* clear pfn */
1836 iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf));
1837 if (iov_len) {
1838 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
1839 iov_len, TRUE, 0)) < 0) {
1840 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1841 }
1842 }
1843 else {
1844 ret = -1;
1845 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len));
1846 }
1847 }
1848 else
1849 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1850
1851 return ret;
1852}
1853
1854int
1855dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
1856{
1857 char iovbuf[128];
1858 int ret = -1;
1859
1860 if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) {
1861 DHD_ERROR(("%s error exit\n", __FUNCTION__));
1862 return ret;
1863 }
1864
1865 if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
1866 return (ret);
1867
1868 memset(iovbuf, 0, sizeof(iovbuf));
1869
1870 if ((pfn_enabled) && (dhd_is_associated(dhd, NULL) == TRUE)) {
1871 DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__));
1872 return ret;
1873 }
1874
1875 /* Enable/disable PNO */
1876 if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) {
1877 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
1878 iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
1879 DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret));
1880 return ret;
1881 }
1882 else {
1883 dhd->pno_enable = pfn_enabled;
1884 DHD_TRACE(("%s set pno as %s\n",
1885 __FUNCTION__, dhd->pno_enable ? "Enable" : "Disable"));
1886 }
1887 }
1888 else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret));
1889
1890 return ret;
1891}
1892
1893/* Function to execute combined scan */
1894int
1895dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
1896 int pno_repeat, int pno_freq_expo_max)
1897{
1898 int err = -1;
1899 char iovbuf[128];
1900 int k, i;
1901 wl_pfn_param_t pfn_param;
1902 wl_pfn_t pfn_element;
1903 uint len = 0;
1904
1905 DHD_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr));
1906
1907 if ((!dhd) && (!ssids_local)) {
1908 DHD_ERROR(("%s error exit\n", __FUNCTION__));
1909 err = -1;
1910 }
1911
1912 if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
1913 return (err);
1914
1915 /* Check for broadcast ssid */
1916 for (k = 0; k < nssid; k++) {
1917 if (!ssids_local[k].SSID_len) {
1918 DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k));
1919 return err;
1920 }
1921 }
1922/* #define PNO_DUMP 1 */
1923#ifdef PNO_DUMP
1924 {
1925 int j;
1926 for (j = 0; j < nssid; j++) {
1927 DHD_ERROR(("%d: scan for %s size =%d\n", j,
1928 ssids_local[j].SSID, ssids_local[j].SSID_len));
1929 }
1930 }
1931#endif /* PNO_DUMP */
1932
1933 /* clean up everything */
1934 if ((err = dhd_pno_clean(dhd)) < 0) {
1935 DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err));
1936 return err;
1937 }
1938 memset(iovbuf, 0, sizeof(iovbuf));
1939 memset(&pfn_param, 0, sizeof(pfn_param));
1940 memset(&pfn_element, 0, sizeof(pfn_element));
1941
1942 /* set pfn parameters */
1943 pfn_param.version = htod32(PFN_VERSION);
1944 pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT));
1945
1946 /* check and set extra pno params */
1947 if ((pno_repeat != 0) || (pno_freq_expo_max != 0)) {
1948 pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT);
1949 pfn_param.repeat = (uchar) (pno_repeat);
1950 pfn_param.exp = (uchar) (pno_freq_expo_max);
1951 }
1952 /* set up pno scan fr */
1953 if (scan_fr != 0)
1954 pfn_param.scan_freq = htod32(scan_fr);
1955
1956 if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) {
1957 DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC));
1958 return err;
1959 }
1960 if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) {
1961 DHD_ERROR(("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC));
1962 return err;
1963 }
1964
1965 len = bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf));
1966 if ((err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) {
1967 DHD_ERROR(("%s pfn_set failed for error=%d\n",
1968 __FUNCTION__, err));
1969 return err;
1970 }
1971
1972 /* set all pfn ssid */
1973 for (i = 0; i < nssid; i++) {
1974
1975 pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE);
1976 pfn_element.auth = (DOT11_OPEN_SYSTEM);
1977 pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY);
1978 pfn_element.wsec = htod32(0);
1979 pfn_element.infra = htod32(1);
1980 pfn_element.flags = htod32(ENABLE << WL_PFN_HIDDEN_BIT);
1981 memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len);
1982 pfn_element.ssid.SSID_len = ssids_local[i].SSID_len;
1983
1984 if ((len =
1985 bcm_mkiovar("pfn_add", (char *)&pfn_element,
1986 sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) {
1987 if ((err =
1988 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) {
1989 DHD_ERROR(("%s failed for i=%d error=%d\n",
1990 __FUNCTION__, i, err));
1991 return err;
1992 }
1993 else
1994 DHD_TRACE(("%s set OK with PNO time=%d repeat=%d max_adjust=%d\n",
1995 __FUNCTION__, pfn_param.scan_freq,
1996 pfn_param.repeat, pfn_param.exp));
1997 }
1998 else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, err));
1999 }
2000
2001 /* Enable PNO */
2002 /* dhd_pno_enable(dhd, 1); */
2003 return err;
2004}
2005
2006int
2007dhd_pno_get_status(dhd_pub_t *dhd)
2008{
2009 int ret = -1;
2010
2011 if (!dhd)
2012 return ret;
2013 else
2014 return (dhd->pno_enable);
2015}
2016
2017#endif /* PNO_SUPPORT */
2018
2019#if defined(KEEP_ALIVE)
2020int dhd_keep_alive_onoff(dhd_pub_t *dhd)
2021{
2022 char buf[256];
2023 const char *str;
2024 wl_mkeep_alive_pkt_t mkeep_alive_pkt;
2025 wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
2026 int buf_len;
2027 int str_len;
2028 int res = -1;
2029
2030 if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
2031 return (res);
2032
2033 DHD_TRACE(("%s execution\n", __FUNCTION__));
2034
2035 str = "mkeep_alive";
2036 str_len = strlen(str);
2037 strncpy(buf, str, str_len);
2038 buf[ str_len ] = '\0';
2039 mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
2040 mkeep_alive_pkt.period_msec = KEEP_ALIVE_PERIOD;
2041 buf_len = str_len + 1;
2042 mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
2043 mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
2044 /* Setup keep alive zero for null packet generation */
2045 mkeep_alive_pkt.keep_alive_id = 0;
2046 mkeep_alive_pkt.len_bytes = 0;
2047 buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
2048 /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and
2049 * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
2050 * guarantee that the buffer is properly aligned.
2051 */
2052 memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
2053
2054 res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
2055
2056 return res;
2057}
2058#endif /* defined(KEEP_ALIVE) */
2059/* Android ComboSCAN support */
2060
2061/*
2062 * data parsing from ComboScan tlv list
2063*/
2064int
2065wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token,
2066 int input_size, int *bytes_left)
2067{
2068 char* str = *list_str;
2069 uint16 short_temp;
2070 uint32 int_temp;
2071
2072 if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) {
2073 DHD_ERROR(("%s error paramters\n", __FUNCTION__));
2074 return -1;
2075 }
2076
2077 /* Clean all dest bytes */
2078 memset(dst, 0, dst_size);
2079 while (*bytes_left > 0) {
2080
2081 if (str[0] != token) {
2082 DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n",
2083 __FUNCTION__, token, str[0], *bytes_left));
2084 return -1;
2085 }
2086
2087 *bytes_left -= 1;
2088 str += 1;
2089
2090 if (input_size == 1) {
2091 memcpy(dst, str, input_size);
2092 }
2093 else if (input_size == 2) {
2094 memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)),
2095 input_size);
2096 }
2097 else if (input_size == 4) {
2098 memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)),
2099 input_size);
2100 }
2101
2102 *bytes_left -= input_size;
2103 str += input_size;
2104 *list_str = str;
2105 return 1;
2106 }
2107 return 1;
2108}
2109
2110/*
2111 * channel list parsing from cscan tlv list
2112*/
2113int
2114wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list,
2115 int channel_num, int *bytes_left)
2116{
2117 char* str = *list_str;
2118 int idx = 0;
2119
2120 if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) {
2121 DHD_ERROR(("%s error paramters\n", __FUNCTION__));
2122 return -1;
2123 }
2124
2125 while (*bytes_left > 0) {
2126
2127 if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) {
2128 *list_str = str;
2129 DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
2130 return idx;
2131 }
2132 /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */
2133 *bytes_left -= 1;
2134 str += 1;
2135
2136 if (str[0] == 0) {
2137 /* All channels */
2138 channel_list[idx] = 0x0;
2139 }
2140 else {
2141 channel_list[idx] = (uint16)str[0];
2142 DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx]));
2143 }
2144 *bytes_left -= 1;
2145 str += 1;
2146
2147 if (idx++ > 255) {
2148 DHD_ERROR(("%s Too many channels \n", __FUNCTION__));
2149 return -1;
2150 }
2151 }
2152
2153 *list_str = str;
2154 return idx;
2155}
2156
2157/*
2158 * SSIDs list parsing from cscan tlv list
2159 */
2160int
2161wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left)
2162{
2163 char* str = *list_str;
2164 int idx = 0;
2165
2166 if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) {
2167 DHD_ERROR(("%s error paramters\n", __FUNCTION__));
2168 return -1;
2169 }
2170
2171 while (*bytes_left > 0) {
2172
2173 if (str[0] != CSCAN_TLV_TYPE_SSID_IE) {
2174 *list_str = str;
2175 DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
2176 return idx;
2177 }
2178
2179 /* Get proper CSCAN_TLV_TYPE_SSID_IE */
2180 *bytes_left -= 1;
2181 str += 1;
2182
2183 if (str[0] == 0) {
2184 /* Broadcast SSID */
2185 ssid[idx].SSID_len = 0;
2186 memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN);
2187 *bytes_left -= 1;
2188 str += 1;
2189
2190 DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left));
2191 }
2192 else if (str[0] <= DOT11_MAX_SSID_LEN) {
2193 /* Get proper SSID size */
2194 ssid[idx].SSID_len = str[0];
2195 *bytes_left -= 1;
2196 str += 1;
2197
2198 /* Get SSID */
2199 if (ssid[idx].SSID_len > *bytes_left) {
2200 DHD_ERROR(("%s out of memory range len=%d but left=%d\n",
2201 __FUNCTION__, ssid[idx].SSID_len, *bytes_left));
2202 return -1;
2203 }
2204
2205 memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len);
2206
2207 *bytes_left -= ssid[idx].SSID_len;
2208 str += ssid[idx].SSID_len;
2209
2210 DHD_TRACE(("%s :size=%d left=%d\n",
2211 (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left));
2212 }
2213 else {
2214 DHD_ERROR(("### SSID size more that %d\n", str[0]));
2215 return -1;
2216 }
2217
2218 if (idx++ > max) {
2219 DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx));
2220 return -1;
2221 }
2222 }
2223
2224 *list_str = str;
2225 return idx;
2226}
2227
2228/* Parse a comma-separated list from list_str into ssid array, starting
2229 * at index idx. Max specifies size of the ssid array. Parses ssids
2230 * and returns updated idx; if idx >= max not all fit, the excess have
2231 * not been copied. Returns -1 on empty string, or on ssid too long.
2232 */
2233int
2234wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max)
2235{
2236 char* str, *ptr;
2237
2238 if ((list_str == NULL) || (*list_str == NULL))
2239 return -1;
2240
2241 for (str = *list_str; str != NULL; str = ptr) {
2242
2243 /* check for next TAG */
2244 if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) {
2245 *list_str = str + strlen(GET_CHANNEL);
2246 return idx;
2247 }
2248
2249 if ((ptr = strchr(str, ',')) != NULL) {
2250 *ptr++ = '\0';
2251 }
2252
2253 if (strlen(str) > DOT11_MAX_SSID_LEN) {
2254 DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN));
2255 return -1;
2256 }
2257
2258 if (strlen(str) == 0)
2259 ssid[idx].SSID_len = 0;
2260
2261 if (idx < max) {
2262 bcm_strcpy_s((char*)ssid[idx].SSID, sizeof(ssid[idx].SSID), str);
2263 ssid[idx].SSID_len = strlen(str);
2264 }
2265 idx++;
2266 }
2267 return idx;
2268}
2269
2270/*
2271 * Parse channel list from iwpriv CSCAN
2272 */
2273int
2274wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num)
2275{
2276 int num;
2277 int val;
2278 char* str;
2279 char* endptr = NULL;
2280
2281 if ((list_str == NULL)||(*list_str == NULL))
2282 return -1;
2283
2284 str = *list_str;
2285 num = 0;
2286 while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) {
2287 val = (int)strtoul(str, &endptr, 0);
2288 if (endptr == str) {
2289 printf("could not parse channel number starting at"
2290 " substring \"%s\" in list:\n%s\n",
2291 str, *list_str);
2292 return -1;
2293 }
2294 str = endptr + strspn(endptr, " ,");
2295
2296 if (num == channel_num) {
2297 DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n",
2298 channel_num, *list_str));
2299 return -1;
2300 }
2301
2302 channel_list[num++] = (uint16)val;
2303 }
2304 *list_str = str;
2305 return num;
2306}
diff --git a/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c
new file mode 100644
index 00000000000..9750eeb23bc
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_custom_gpio.c
@@ -0,0 +1,293 @@
1/*
2* Customer code to add GPIO control during WLAN start/stop
3* Copyright (C) 1999-2011, Broadcom Corporation
4*
5* Unless you and Broadcom execute a separate written software license
6* agreement governing use of this software, this software is licensed to you
7* under the terms of the GNU General Public License version 2 (the "GPL"),
8* available at http://www.broadcom.com/licenses/GPLv2.php, with the
9* following added to such license:
10*
11* As a special exception, the copyright holders of this software give you
12* permission to link this software with independent modules, and to copy and
13* distribute the resulting executable under terms of your choice, provided that
14* you also meet, for each linked independent module, the terms and conditions of
15* the license of that module. An independent module is a module which is not
16* derived from this software. The special exception does not apply to any
17* modifications of the software.
18*
19* Notwithstanding the above, under no circumstances may you combine this
20* software in any way with any other Broadcom software provided under a license
21* other than the GPL, without Broadcom's express prior written consent.
22*
23* $Id: dhd_custom_gpio.c,v 1.2.42.1 2010-10-19 00:41:09 Exp $
24*/
25
26#include <typedefs.h>
27#include <linuxver.h>
28#include <osl.h>
29#include <bcmutils.h>
30
31#include <dngl_stats.h>
32#include <dhd.h>
33
34#include <wlioctl.h>
35#include <wl_iw.h>
36
37#define WL_ERROR(x) printf x
38#define WL_TRACE(x)
39
40#ifdef CUSTOMER_HW
41extern void bcm_wlan_power_off(int);
42extern void bcm_wlan_power_on(int);
43#endif /* CUSTOMER_HW */
44#if defined(CUSTOMER_HW2)
45#ifdef CONFIG_WIFI_CONTROL_FUNC
46int wifi_set_power(int on, unsigned long msec);
47int wifi_get_irq_number(unsigned long *irq_flags_ptr);
48int wifi_get_mac_addr(unsigned char *buf);
49void *wifi_get_country_code(char *ccode);
50#else
51int wifi_set_power(int on, unsigned long msec) { return -1; }
52int wifi_get_irq_number(unsigned long *irq_flags_ptr) { return -1; }
53int wifi_get_mac_addr(unsigned char *buf) { return -1; }
54void *wifi_get_country_code(char *ccode) { return NULL; }
55#endif /* CONFIG_WIFI_CONTROL_FUNC */
56#endif /* CUSTOMER_HW2 */
57
58#if defined(OOB_INTR_ONLY)
59
60#if defined(BCMLXSDMMC)
61extern int sdioh_mmc_irq(int irq);
62#endif /* (BCMLXSDMMC) */
63
64#ifdef CUSTOMER_HW3
65#include <mach/gpio.h>
66#endif
67
68/* Customer specific Host GPIO defintion */
69static int dhd_oob_gpio_num = -1;
70
71module_param(dhd_oob_gpio_num, int, 0644);
72MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number");
73
74/* This function will return:
75 * 1) return : Host gpio interrupt number per customer platform
76 * 2) irq_flags_ptr : Type of Host interrupt as Level or Edge
77 *
78 * NOTE :
79 * Customer should check his platform definitions
80 * and his Host Interrupt spec
81 * to figure out the proper setting for his platform.
82 * Broadcom provides just reference settings as example.
83 *
84 */
85int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr)
86{
87 int host_oob_irq = 0;
88
89#ifdef CUSTOMER_HW2
90 host_oob_irq = wifi_get_irq_number(irq_flags_ptr);
91
92#else
93#if defined(CUSTOM_OOB_GPIO_NUM)
94 if (dhd_oob_gpio_num < 0) {
95 dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM;
96 }
97#endif /* CUSTOMER_HW2 */
98
99 if (dhd_oob_gpio_num < 0) {
100 WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n",
101 __FUNCTION__));
102 return (dhd_oob_gpio_num);
103 }
104
105 WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n",
106 __FUNCTION__, dhd_oob_gpio_num));
107
108#if defined CUSTOMER_HW
109 host_oob_irq = MSM_GPIO_TO_INT(dhd_oob_gpio_num);
110#elif defined CUSTOMER_HW3
111 gpio_request(dhd_oob_gpio_num, "oob irq");
112 host_oob_irq = gpio_to_irq(dhd_oob_gpio_num);
113 gpio_direction_input(dhd_oob_gpio_num);
114#endif /* CUSTOMER_HW */
115#endif /* CUSTOMER_HW2 */
116
117 return (host_oob_irq);
118}
119#endif /* defined(OOB_INTR_ONLY) */
120
121/* Customer function to control hw specific wlan gpios */
122void
123dhd_customer_gpio_wlan_ctrl(int onoff)
124{
125 switch (onoff) {
126 case WLAN_RESET_OFF:
127 WL_TRACE(("%s: call customer specific GPIO to insert WLAN RESET\n",
128 __FUNCTION__));
129#ifdef CUSTOMER_HW
130 bcm_wlan_power_off(2);
131#endif /* CUSTOMER_HW */
132#ifdef CUSTOMER_HW2
133 wifi_set_power(0, 0);
134#endif
135 WL_ERROR(("=========== WLAN placed in RESET ========\n"));
136 break;
137
138 case WLAN_RESET_ON:
139 WL_TRACE(("%s: callc customer specific GPIO to remove WLAN RESET\n",
140 __FUNCTION__));
141#ifdef CUSTOMER_HW
142 bcm_wlan_power_on(2);
143#endif /* CUSTOMER_HW */
144#ifdef CUSTOMER_HW2
145 wifi_set_power(1, 0);
146#endif
147 WL_ERROR(("=========== WLAN going back to live ========\n"));
148 break;
149
150 case WLAN_POWER_OFF:
151 WL_TRACE(("%s: call customer specific GPIO to turn off WL_REG_ON\n",
152 __FUNCTION__));
153#ifdef CUSTOMER_HW
154 bcm_wlan_power_off(1);
155#endif /* CUSTOMER_HW */
156 break;
157
158 case WLAN_POWER_ON:
159 WL_TRACE(("%s: call customer specific GPIO to turn on WL_REG_ON\n",
160 __FUNCTION__));
161#ifdef CUSTOMER_HW
162 bcm_wlan_power_on(1);
163 /* Lets customer power to get stable */
164 OSL_DELAY(200);
165#endif /* CUSTOMER_HW */
166 break;
167 }
168}
169
170#ifdef GET_CUSTOM_MAC_ENABLE
171/* Function to get custom MAC address */
172int
173dhd_custom_get_mac_address(unsigned char *buf)
174{
175 int ret = 0;
176
177 WL_TRACE(("%s Enter\n", __FUNCTION__));
178 if (!buf)
179 return -EINVAL;
180
181 /* Customer access to MAC address stored outside of DHD driver */
182#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
183 ret = wifi_get_mac_addr(buf);
184#endif
185
186#ifdef EXAMPLE_GET_MAC
187 /* EXAMPLE code */
188 {
189 struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}};
190 bcopy((char *)&ea_example, buf, sizeof(struct ether_addr));
191 }
192#endif /* EXAMPLE_GET_MAC */
193
194 return ret;
195}
196#endif /* GET_CUSTOM_MAC_ENABLE */
197
198/* Customized Locale table : OPTIONAL feature */
199const struct cntry_locales_custom translate_custom_table[] = {
200/* Table should be filled out based on custom platform regulatory requirement */
201#ifdef EXAMPLE_TABLE
202 {"", "XY", 4}, /* Universal if Country code is unknown or empty */
203 {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */
204 {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */
205 {"EU", "EU", 5}, /* European union countries to : EU regrev 05 */
206 {"AT", "EU", 5},
207 {"BE", "EU", 5},
208 {"BG", "EU", 5},
209 {"CY", "EU", 5},
210 {"CZ", "EU", 5},
211 {"DK", "EU", 5},
212 {"EE", "EU", 5},
213 {"FI", "EU", 5},
214 {"FR", "EU", 5},
215 {"DE", "EU", 5},
216 {"GR", "EU", 5},
217 {"HU", "EU", 5},
218 {"IE", "EU", 5},
219 {"IT", "EU", 5},
220 {"LV", "EU", 5},
221 {"LI", "EU", 5},
222 {"LT", "EU", 5},
223 {"LU", "EU", 5},
224 {"MT", "EU", 5},
225 {"NL", "EU", 5},
226 {"PL", "EU", 5},
227 {"PT", "EU", 5},
228 {"RO", "EU", 5},
229 {"SK", "EU", 5},
230 {"SI", "EU", 5},
231 {"ES", "EU", 5},
232 {"SE", "EU", 5},
233 {"GB", "EU", 5},
234 {"KR", "XY", 3},
235 {"AU", "XY", 3},
236 {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */
237 {"TW", "XY", 3},
238 {"AR", "XY", 3},
239 {"MX", "XY", 3},
240 {"IL", "IL", 0},
241 {"CH", "CH", 0},
242 {"TR", "TR", 0},
243 {"NO", "NO", 0},
244#endif /* EXMAPLE_TABLE */
245};
246
247
248/* Customized Locale convertor
249* input : ISO 3166-1 country abbreviation
250* output: customized cspec
251*/
252void get_customized_country_code(char *country_iso_code, wl_country_t *cspec)
253{
254#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
255
256 struct cntry_locales_custom *cloc_ptr;
257
258 if (!cspec)
259 return;
260
261 cloc_ptr = wifi_get_country_code(country_iso_code);
262 if (cloc_ptr) {
263 strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ);
264 cspec->rev = cloc_ptr->custom_locale_rev;
265 }
266 return;
267#else
268 int size, i;
269
270 size = ARRAYSIZE(translate_custom_table);
271
272 if (cspec == 0)
273 return;
274
275 if (size == 0)
276 return;
277
278 for (i = 0; i < size; i++) {
279 if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) {
280 memcpy(cspec->ccode,
281 translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ);
282 cspec->rev = translate_custom_table[i].custom_locale_rev;
283 return;
284 }
285 }
286#ifdef EXAMPLE_TABLE
287 /* if no country code matched return first universal code from translate_custom_table */
288 memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ);
289 cspec->rev = translate_custom_table[0].custom_locale_rev;
290#endif /* EXMAPLE_TABLE */
291 return;
292#endif /* defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
293}
diff --git a/drivers/net/wireless/bcmdhd/dhd_dbg.h b/drivers/net/wireless/bcmdhd/dhd_dbg.h
new file mode 100644
index 00000000000..a195cbe88e5
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_dbg.h
@@ -0,0 +1,105 @@
1/*
2 * Debug/trace/assert driver definitions for Dongle Host Driver.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: dhd_dbg.h 285933 2011-09-23 21:45:31Z $
25 */
26
27#ifndef _dhd_dbg_
28#define _dhd_dbg_
29
30#if defined(DHD_DEBUG)
31
32#define DHD_ERROR(args) do {if ((dhd_msg_level & DHD_ERROR_VAL) && (net_ratelimit())) \
33 printf args;} while (0)
34#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0)
35#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0)
36#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0)
37#define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) printf args;} while (0)
38#define DHD_TIMER(args) do {if (dhd_msg_level & DHD_TIMER_VAL) printf args;} while (0)
39#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) printf args;} while (0)
40#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) printf args;} while (0)
41#define DHD_INTR(args) do {if (dhd_msg_level & DHD_INTR_VAL) printf args;} while (0)
42#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0)
43#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0)
44#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0)
45#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0)
46#define DHD_ARPOE(args) do {if (dhd_msg_level & DHD_ARPOE_VAL) printf args;} while (0)
47
48#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL)
49#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL)
50#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL)
51#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL)
52#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL)
53#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL)
54#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL)
55#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL)
56#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL)
57#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL)
58#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL)
59#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL)
60#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL)
61#define DHD_ARPOE_ON() (dhd_msg_level & DHD_ARPOE_VAL)
62
63#else /* defined(BCMDBG) || defined(DHD_DEBUG) */
64
65#define DHD_ERROR(args) do {if (net_ratelimit()) printf args;} while (0)
66#define DHD_TRACE(args)
67#define DHD_INFO(args)
68#define DHD_DATA(args)
69#define DHD_CTL(args)
70#define DHD_TIMER(args)
71#define DHD_HDRS(args)
72#define DHD_BYTES(args)
73#define DHD_INTR(args)
74#define DHD_GLOM(args)
75#define DHD_EVENT(args)
76#define DHD_BTA(args)
77#define DHD_ISCAN(args)
78#define DHD_ARPOE(args)
79
80#define DHD_ERROR_ON() 0
81#define DHD_TRACE_ON() 0
82#define DHD_INFO_ON() 0
83#define DHD_DATA_ON() 0
84#define DHD_CTL_ON() 0
85#define DHD_TIMER_ON() 0
86#define DHD_HDRS_ON() 0
87#define DHD_BYTES_ON() 0
88#define DHD_INTR_ON() 0
89#define DHD_GLOM_ON() 0
90#define DHD_EVENT_ON() 0
91#define DHD_BTA_ON() 0
92#define DHD_ISCAN_ON() 0
93#define DHD_ARPOE_ON() 0
94#endif
95
96#define DHD_LOG(args)
97
98#define DHD_BLOG(cp, size)
99#define DHD_NONE(args)
100extern int dhd_msg_level;
101
102/* Defines msg bits */
103#include <dhdioctl.h>
104
105#endif /* _dhd_dbg_ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
new file mode 100644
index 00000000000..80a75699e27
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
@@ -0,0 +1,5080 @@
1/*
2 * Broadcom Dongle Host Driver (DHD), Linux-specific network interface
3 * Basically selected code segments from usb-cdc.c and usb-rndis.c
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: dhd_linux.c 291449 2011-10-22 12:16:26Z $
26 */
27
28#include <typedefs.h>
29#include <linuxver.h>
30#include <osl.h>
31
32#include <linux/init.h>
33#include <linux/kernel.h>
34#include <linux/slab.h>
35#include <linux/skbuff.h>
36#include <linux/netdevice.h>
37#include <linux/inetdevice.h>
38#include <linux/rtnetlink.h>
39#include <linux/etherdevice.h>
40#include <linux/random.h>
41#include <linux/spinlock.h>
42#include <linux/ethtool.h>
43#include <linux/fcntl.h>
44#include <linux/fs.h>
45#include <linux/device.h>
46
47#include <asm/uaccess.h>
48#include <asm/unaligned.h>
49
50#include <epivers.h>
51#include <bcmutils.h>
52#include <bcmendian.h>
53
54#include <proto/ethernet.h>
55#include <dngl_stats.h>
56#include <dhd.h>
57#include <dhd_bus.h>
58#include <dhd_proto.h>
59#include <dhd_dbg.h>
60#ifdef CONFIG_HAS_WAKELOCK
61#include <linux/wakelock.h>
62#endif
63#ifdef WL_CFG80211
64#include <wl_cfg80211.h>
65#endif
66
67#include <proto/802.11_bta.h>
68#include <proto/bt_amp_hci.h>
69#include <dhd_bta.h>
70
71#ifdef WLMEDIA_HTSF
72#include <linux/time.h>
73#include <htsf.h>
74
75#define HTSF_MINLEN 200 /* min. packet length to timestamp */
76#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */
77#define TSMAX 1000 /* max no. of timing record kept */
78#define NUMBIN 34
79
80static uint32 tsidx = 0;
81static uint32 htsf_seqnum = 0;
82uint32 tsfsync;
83struct timeval tsync;
84static uint32 tsport = 5010;
85
86typedef struct histo_ {
87 uint32 bin[NUMBIN];
88} histo_t;
89
90#if !ISPOWEROF2(DHD_SDALIGN)
91#error DHD_SDALIGN is not a power of 2!
92#endif
93
94static histo_t vi_d1, vi_d2, vi_d3, vi_d4;
95#endif /* WLMEDIA_HTSF */
96
97#if defined(SOFTAP)
98extern bool ap_cfg_running;
99extern bool ap_fw_loaded;
100#endif
101
102/* enable HOSTIP cache update from the host side when an eth0:N is up */
103#define AOE_IP_ALIAS_SUPPORT 1
104
105#ifdef PROP_TXSTATUS
106#include <wlfc_proto.h>
107#include <dhd_wlfc.h>
108#endif
109
110#include <wl_android.h>
111
112#ifdef ARP_OFFLOAD_SUPPORT
113static int dhd_device_event(struct notifier_block *this,
114 unsigned long event,
115 void *ptr);
116
117static struct notifier_block dhd_notifier = {
118 .notifier_call = dhd_device_event
119};
120#endif /* ARP_OFFLOAD_SUPPORT */
121
122#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
123#include <linux/suspend.h>
124volatile bool dhd_mmc_suspend = FALSE;
125DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
126#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
127
128#if defined(OOB_INTR_ONLY)
129extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
130#endif /* defined(OOB_INTR_ONLY) */
131#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
132MODULE_LICENSE("GPL v2");
133#endif /* LinuxVer */
134
135#include <dhd_bus.h>
136
137#ifndef PROP_TXSTATUS
138#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen)
139#else
140#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128)
141#endif
142
143#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
144const char *
145print_tainted()
146{
147 return "";
148}
149#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */
150
151/* Linux wireless extension support */
152#if defined(CONFIG_BCMDHD_WEXT)
153#include <wl_iw.h>
154extern wl_iw_extra_params_t g_wl_iw_params;
155#endif /* defined(CONFIG_BCMDHD_WEXT) */
156
157#if defined(CONFIG_HAS_EARLYSUSPEND)
158#include <linux/earlysuspend.h>
159extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
160extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
161#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
162
163#ifdef PKT_FILTER_SUPPORT
164extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
165extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
166#endif
167
168/* Interface control information */
169typedef struct dhd_if {
170 struct dhd_info *info; /* back pointer to dhd_info */
171 /* OS/stack specifics */
172 struct net_device *net;
173 struct net_device_stats stats;
174 int idx; /* iface idx in dongle */
175 dhd_if_state_t state; /* interface state */
176 uint subunit; /* subunit */
177 uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */
178 bool attached; /* Delayed attachment when unset */
179 bool txflowcontrol; /* Per interface flow control indicator */
180 char name[IFNAMSIZ+1]; /* linux interface name */
181 uint8 bssidx; /* bsscfg index for the interface */
182 bool set_multicast;
183} dhd_if_t;
184
185#ifdef WLMEDIA_HTSF
186typedef struct {
187 uint32 low;
188 uint32 high;
189} tsf_t;
190
191typedef struct {
192 uint32 last_cycle;
193 uint32 last_sec;
194 uint32 last_tsf;
195 uint32 coef; /* scaling factor */
196 uint32 coefdec1; /* first decimal */
197 uint32 coefdec2; /* second decimal */
198} htsf_t;
199
200typedef struct {
201 uint32 t1;
202 uint32 t2;
203 uint32 t3;
204 uint32 t4;
205} tstamp_t;
206
207static tstamp_t ts[TSMAX];
208static tstamp_t maxdelayts;
209static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0;
210
211#endif /* WLMEDIA_HTSF */
212
213/* Local private structure (extension of pub) */
214typedef struct dhd_info {
215#if defined(CONFIG_BCMDHD_WEXT)
216 wl_iw_t iw; /* wireless extensions state (must be first) */
217#endif /* defined(CONFIG_BCMDHD_WEXT) */
218
219 dhd_pub_t pub;
220
221 /* For supporting multiple interfaces */
222 dhd_if_t *iflist[DHD_MAX_IFS];
223
224 struct semaphore proto_sem;
225#ifdef PROP_TXSTATUS
226 spinlock_t wlfc_spinlock;
227#endif /* PROP_TXSTATUS */
228#ifdef WLMEDIA_HTSF
229 htsf_t htsf;
230#endif
231 wait_queue_head_t ioctl_resp_wait;
232 struct timer_list timer;
233 bool wd_timer_valid;
234 struct tasklet_struct tasklet;
235 spinlock_t sdlock;
236 spinlock_t txqlock;
237 spinlock_t dhd_lock;
238#ifdef DHDTHREAD
239 /* Thread based operation */
240 bool threads_only;
241 struct semaphore sdsem;
242
243 tsk_ctl_t thr_dpc_ctl;
244 tsk_ctl_t thr_wdt_ctl;
245
246#else
247 bool dhd_tasklet_create;
248#endif /* DHDTHREAD */
249 tsk_ctl_t thr_sysioc_ctl;
250
251 /* Wakelocks */
252#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
253 struct wake_lock wl_wifi; /* Wifi wakelock */
254 struct wake_lock wl_rxwake; /* Wifi rx wakelock */
255#endif
256
257#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
258 /* net_device interface lock, prevent race conditions among net_dev interface
259 * calls and wifi_on or wifi_off
260 */
261 struct mutex dhd_net_if_mutex;
262#endif
263 spinlock_t wakelock_spinlock;
264 int wakelock_counter;
265 int wakelock_timeout_enable;
266
267 /* Thread to issue ioctl for multicast */
268 bool set_macaddress;
269 struct ether_addr macvalue;
270 wait_queue_head_t ctrl_wait;
271 atomic_t pend_8021x_cnt;
272 dhd_attach_states_t dhd_state;
273
274#ifdef CONFIG_HAS_EARLYSUSPEND
275 struct early_suspend early_suspend;
276#endif /* CONFIG_HAS_EARLYSUSPEND */
277} dhd_info_t;
278
279/* Definitions to provide path to the firmware and nvram
280 * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt"
281 */
282char firmware_path[MOD_PARAM_PATHLEN];
283char nvram_path[MOD_PARAM_PATHLEN];
284
285extern int wl_control_wl_start(struct net_device *dev);
286extern int net_os_send_hang_message(struct net_device *dev);
287#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
288struct semaphore dhd_registration_sem;
289#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */
290#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
291
292/* Spawn a thread for system ioctls (set mac, set mcast) */
293uint dhd_sysioc = TRUE;
294module_param(dhd_sysioc, uint, 0);
295
296/* Error bits */
297module_param(dhd_msg_level, int, 0);
298
299/* load firmware and/or nvram values from the filesystem */
300module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660);
301module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0);
302
303/* Watchdog interval */
304uint dhd_watchdog_ms = 10;
305module_param(dhd_watchdog_ms, uint, 0);
306
307#if defined(DHD_DEBUG)
308/* Console poll interval */
309uint dhd_console_ms = 0;
310module_param(dhd_console_ms, uint, 0644);
311#endif /* defined(DHD_DEBUG) */
312
313/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
314uint dhd_arp_mode = 0xb;
315module_param(dhd_arp_mode, uint, 0);
316
317/* ARP offload enable */
318uint dhd_arp_enable = TRUE;
319module_param(dhd_arp_enable, uint, 0);
320
321/* Global Pkt filter enable control */
322uint dhd_pkt_filter_enable = TRUE;
323module_param(dhd_pkt_filter_enable, uint, 0);
324
325/* Pkt filter init setup */
326uint dhd_pkt_filter_init = 0;
327module_param(dhd_pkt_filter_init, uint, 0);
328
329/* Pkt filter mode control */
330uint dhd_master_mode = TRUE;
331module_param(dhd_master_mode, uint, 0);
332
333#ifdef DHDTHREAD
334/* Watchdog thread priority, -1 to use kernel timer */
335int dhd_watchdog_prio = 97;
336module_param(dhd_watchdog_prio, int, 0);
337
338/* DPC thread priority, -1 to use tasklet */
339int dhd_dpc_prio = 98;
340module_param(dhd_dpc_prio, int, 0);
341
342/* DPC thread priority, -1 to use tasklet */
343extern int dhd_dongle_memsize;
344module_param(dhd_dongle_memsize, int, 0);
345#endif /* DHDTHREAD */
346/* Control fw roaming */
347uint dhd_roam_disable = 0;
348
349/* Control radio state */
350uint dhd_radio_up = 1;
351
352/* Network inteface name */
353char iface_name[IFNAMSIZ] = {'\0'};
354module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
355
356#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
357#define DAEMONIZE(a) daemonize(a); \
358 allow_signal(SIGKILL); \
359 allow_signal(SIGTERM);
360#else /* Linux 2.4 (w/o preemption patch) */
361#define RAISE_RX_SOFTIRQ() \
362 cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
363#define DAEMONIZE(a) daemonize(); \
364 do { if (a) \
365 strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
366 } while (0);
367#endif /* LINUX_VERSION_CODE */
368
369#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
370#define BLOCKABLE() (!in_atomic())
371#else
372#define BLOCKABLE() (!in_interrupt())
373#endif
374
375/* The following are specific to the SDIO dongle */
376
377/* IOCTL response timeout */
378int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT;
379
380/* Idle timeout for backplane clock */
381int dhd_idletime = DHD_IDLETIME_TICKS;
382module_param(dhd_idletime, int, 0);
383
384/* Use polling */
385uint dhd_poll = FALSE;
386module_param(dhd_poll, uint, 0);
387
388/* Use interrupts */
389uint dhd_intr = TRUE;
390module_param(dhd_intr, uint, 0);
391
392/* SDIO Drive Strength (in milliamps) */
393uint dhd_sdiod_drive_strength = 6;
394module_param(dhd_sdiod_drive_strength, uint, 0);
395
396/* Tx/Rx bounds */
397extern uint dhd_txbound;
398extern uint dhd_rxbound;
399module_param(dhd_txbound, uint, 0);
400module_param(dhd_rxbound, uint, 0);
401
402/* Deferred transmits */
403extern uint dhd_deferred_tx;
404module_param(dhd_deferred_tx, uint, 0);
405
406#ifdef BCMDBGFS
407extern void dhd_dbg_init(dhd_pub_t *dhdp);
408extern void dhd_dbg_remove(void);
409#endif /* BCMDBGFS */
410
411
412
413#ifdef SDTEST
414/* Echo packet generator (pkts/s) */
415uint dhd_pktgen = 0;
416module_param(dhd_pktgen, uint, 0);
417
418/* Echo packet len (0 => sawtooth, max 2040) */
419uint dhd_pktgen_len = 0;
420module_param(dhd_pktgen_len, uint, 0);
421#endif /* SDTEST */
422
423/* Version string to report */
424#ifdef DHD_DEBUG
425#ifndef SRCBASE
426#define SRCBASE "drivers/net/wireless/bcmdhd"
427#endif
428#define DHD_COMPILED "\nCompiled in " SRCBASE
429#else
430#define DHD_COMPILED
431#endif /* DHD_DEBUG */
432
433static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
434#ifdef DHD_DEBUG
435"\nCompiled in " SRCBASE " on " __DATE__ " at " __TIME__
436#endif
437;
438static void dhd_net_if_lock_local(dhd_info_t *dhd);
439static void dhd_net_if_unlock_local(dhd_info_t *dhd);
440
441#ifdef WLMEDIA_HTSF
442void htsf_update(dhd_info_t *dhd, void *data);
443tsf_t prev_tsf, cur_tsf;
444
445uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx);
446static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx);
447static void dhd_dump_latency(void);
448static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf);
449static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf);
450static void dhd_dump_htsfhisto(histo_t *his, char *s);
451#endif /* WLMEDIA_HTSF */
452
453/* Monitor interface */
454int dhd_monitor_init(void *dhd_pub);
455int dhd_monitor_uninit(void);
456
457
458#if defined(CONFIG_BCMDHD_WEXT)
459struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
460#endif /* defined(CONFIG_BCMDHD_WEXT) */
461
462static void dhd_dpc(ulong data);
463/* forward decl */
464extern int dhd_wait_pend8021x(struct net_device *dev);
465
466#ifdef TOE
467#ifndef BDC
468#error TOE requires BDC
469#endif /* !BDC */
470static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol);
471static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol);
472#endif /* TOE */
473
474static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
475 wl_event_msg_t *event_ptr, void **data_ptr);
476
477#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
478static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
479{
480 int ret = NOTIFY_DONE;
481
482#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39))
483 switch (action) {
484 case PM_HIBERNATION_PREPARE:
485 case PM_SUSPEND_PREPARE:
486 dhd_mmc_suspend = TRUE;
487 ret = NOTIFY_OK;
488 break;
489 case PM_POST_HIBERNATION:
490 case PM_POST_SUSPEND:
491 dhd_mmc_suspend = FALSE;
492 ret = NOTIFY_OK;
493 break;
494 }
495 smp_mb();
496#endif
497 return ret;
498}
499
500static struct notifier_block dhd_sleep_pm_notifier = {
501 .notifier_call = dhd_sleep_pm_callback,
502 .priority = 0
503};
504extern int register_pm_notifier(struct notifier_block *nb);
505extern int unregister_pm_notifier(struct notifier_block *nb);
506#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
507
508static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
509{
510#ifdef PKT_FILTER_SUPPORT
511 DHD_TRACE(("%s: %d\n", __FUNCTION__, value));
512 /* 1 - Enable packet filter, only allow unicast packet to send up */
513 /* 0 - Disable packet filter */
514 if (dhd_pkt_filter_enable) {
515 int i;
516
517 for (i = 0; i < dhd->pktfilter_count; i++) {
518 dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
519 dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
520 value, dhd_master_mode);
521 }
522 }
523#endif
524}
525
526#if defined(CONFIG_HAS_EARLYSUSPEND)
527static int dhd_set_suspend(int value, dhd_pub_t *dhd)
528{
529 int power_mode = PM_MAX;
530 /* wl_pkt_filter_enable_t enable_parm; */
531 char iovbuf[32];
532 int bcn_li_dtim = 3;
533 uint roamvar = 1;
534
535 DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n",
536 __FUNCTION__, value, dhd->in_suspend));
537
538 if (dhd && dhd->up) {
539 if (value && dhd->in_suspend) {
540
541 /* Kernel suspended */
542 DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__));
543
544 dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
545 sizeof(power_mode), TRUE, 0);
546
547 /* Enable packet filter, only allow unicast packet to send up */
548 dhd_set_packet_filter(1, dhd);
549
550 /* If DTIM skip is set up as default, force it to wake
551 * each third DTIM for better power savings. Note that
552 * one side effect is a chance to miss BC/MC packet.
553 */
554 bcn_li_dtim = dhd_get_dtim_skip(dhd);
555 bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
556 4, iovbuf, sizeof(iovbuf));
557 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
558
559 /* Disable firmware roaming during suspend */
560 bcm_mkiovar("roam_off", (char *)&roamvar, 4,
561 iovbuf, sizeof(iovbuf));
562 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
563 } else {
564
565 /* Kernel resumed */
566 DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__));
567
568 power_mode = PM_FAST;
569 dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode,
570 sizeof(power_mode), TRUE, 0);
571
572 /* disable pkt filter */
573 dhd_set_packet_filter(0, dhd);
574
575 /* restore pre-suspend setting for dtim_skip */
576 bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip,
577 4, iovbuf, sizeof(iovbuf));
578
579 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
580 roamvar = dhd_roam_disable;
581 bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf,
582 sizeof(iovbuf));
583 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
584 }
585 }
586
587 return 0;
588}
589
590static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val)
591{
592 dhd_pub_t *dhdp = &dhd->pub;
593
594 DHD_OS_WAKE_LOCK(dhdp);
595 /* Set flag when early suspend was called */
596 dhdp->in_suspend = val;
597 if ((!dhdp->suspend_disable_flag) && (dhd_check_ap_wfd_mode_set(dhdp) == FALSE))
598 dhd_set_suspend(val, dhdp);
599 DHD_OS_WAKE_UNLOCK(dhdp);
600}
601
602static void dhd_early_suspend(struct early_suspend *h)
603{
604 struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
605
606 DHD_TRACE(("%s: enter\n", __FUNCTION__));
607
608 if (dhd)
609 dhd_suspend_resume_helper(dhd, 1);
610}
611
612static void dhd_late_resume(struct early_suspend *h)
613{
614 struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
615
616 DHD_TRACE(("%s: enter\n", __FUNCTION__));
617
618 if (dhd)
619 dhd_suspend_resume_helper(dhd, 0);
620}
621#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
622
623/*
624 * Generalized timeout mechanism. Uses spin sleep with exponential back-off until
625 * the sleep time reaches one jiffy, then switches over to task delay. Usage:
626 *
627 * dhd_timeout_start(&tmo, usec);
628 * while (!dhd_timeout_expired(&tmo))
629 * if (poll_something())
630 * break;
631 * if (dhd_timeout_expired(&tmo))
632 * fatal();
633 */
634
635void
636dhd_timeout_start(dhd_timeout_t *tmo, uint usec)
637{
638 tmo->limit = usec;
639 tmo->increment = 0;
640 tmo->elapsed = 0;
641 tmo->tick = 1000000 / HZ;
642}
643
644int
645dhd_timeout_expired(dhd_timeout_t *tmo)
646{
647 /* Does nothing the first call */
648 if (tmo->increment == 0) {
649 tmo->increment = 1;
650 return 0;
651 }
652
653 if (tmo->elapsed >= tmo->limit)
654 return 1;
655
656 /* Add the delay that's about to take place */
657 tmo->elapsed += tmo->increment;
658
659 if (tmo->increment < tmo->tick) {
660 OSL_DELAY(tmo->increment);
661 tmo->increment *= 2;
662 if (tmo->increment > tmo->tick)
663 tmo->increment = tmo->tick;
664 } else {
665 wait_queue_head_t delay_wait;
666 DECLARE_WAITQUEUE(wait, current);
667 int pending;
668 init_waitqueue_head(&delay_wait);
669 add_wait_queue(&delay_wait, &wait);
670 set_current_state(TASK_INTERRUPTIBLE);
671 schedule_timeout(1);
672 pending = signal_pending(current);
673 remove_wait_queue(&delay_wait, &wait);
674 set_current_state(TASK_RUNNING);
675 if (pending)
676 return 1; /* Interrupted */
677 }
678
679 return 0;
680}
681
682int
683dhd_net2idx(dhd_info_t *dhd, struct net_device *net)
684{
685 int i = 0;
686
687 ASSERT(dhd);
688 while (i < DHD_MAX_IFS) {
689 if (dhd->iflist[i] && (dhd->iflist[i]->net == net))
690 return i;
691 i++;
692 }
693
694 return DHD_BAD_IF;
695}
696
697struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx)
698{
699 struct dhd_info *dhd_info;
700
701 if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS)
702 return NULL;
703 dhd_info = dhd_pub->info;
704 if (dhd_info && dhd_info->iflist[ifidx])
705 return dhd_info->iflist[ifidx]->net;
706 return NULL;
707}
708
709int
710dhd_ifname2idx(dhd_info_t *dhd, char *name)
711{
712 int i = DHD_MAX_IFS;
713
714 ASSERT(dhd);
715
716 if (name == NULL || *name == '\0')
717 return 0;
718
719 while (--i > 0)
720 if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ))
721 break;
722
723 DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name));
724
725 return i; /* default - the primary interface */
726}
727
728char *
729dhd_ifname(dhd_pub_t *dhdp, int ifidx)
730{
731 dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
732
733 ASSERT(dhd);
734
735 if (ifidx < 0 || ifidx >= DHD_MAX_IFS) {
736 DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx));
737 return "<if_bad>";
738 }
739
740 if (dhd->iflist[ifidx] == NULL) {
741 DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx));
742 return "<if_null>";
743 }
744
745 if (dhd->iflist[ifidx]->net)
746 return dhd->iflist[ifidx]->net->name;
747
748 return "<if_none>";
749}
750
751uint8 *
752dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx)
753{
754 int i;
755 dhd_info_t *dhd = (dhd_info_t *)dhdp;
756
757 ASSERT(dhd);
758 for (i = 0; i < DHD_MAX_IFS; i++)
759 if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx)
760 return dhd->iflist[i]->mac_addr;
761
762 return NULL;
763}
764
765
766static void
767_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
768{
769 struct net_device *dev;
770#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
771 struct netdev_hw_addr *ha;
772#else
773 struct dev_mc_list *mclist;
774#endif
775 uint32 allmulti, cnt;
776
777 wl_ioctl_t ioc;
778 char *buf, *bufp;
779 uint buflen;
780 int ret;
781
782 ASSERT(dhd && dhd->iflist[ifidx]);
783 dev = dhd->iflist[ifidx]->net;
784#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
785 netif_addr_lock_bh(dev);
786#endif
787#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
788 cnt = netdev_mc_count(dev);
789#else
790 cnt = dev->mc_count;
791#endif
792#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
793 netif_addr_unlock_bh(dev);
794#endif
795
796 /* Determine initial value of allmulti flag */
797 allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE;
798
799 /* Send down the multicast list first. */
800
801
802 buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN);
803 if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) {
804 DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
805 dhd_ifname(&dhd->pub, ifidx), cnt));
806 return;
807 }
808
809 strcpy(bufp, "mcast_list");
810 bufp += strlen("mcast_list") + 1;
811
812 cnt = htol32(cnt);
813 memcpy(bufp, &cnt, sizeof(cnt));
814 bufp += sizeof(cnt);
815
816#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
817 netif_addr_lock_bh(dev);
818#endif
819#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
820 netdev_for_each_mc_addr(ha, dev) {
821 if (!cnt)
822 break;
823 memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
824 bufp += ETHER_ADDR_LEN;
825 cnt--;
826 }
827#else
828 for (mclist = dev->mc_list; (mclist && (cnt > 0)); cnt--, mclist = mclist->next) {
829 memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN);
830 bufp += ETHER_ADDR_LEN;
831 }
832#endif
833#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
834 netif_addr_unlock_bh(dev);
835#endif
836
837 memset(&ioc, 0, sizeof(ioc));
838 ioc.cmd = WLC_SET_VAR;
839 ioc.buf = buf;
840 ioc.len = buflen;
841 ioc.set = TRUE;
842
843 ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
844 if (ret < 0) {
845 DHD_ERROR(("%s: set mcast_list failed, cnt %d\n",
846 dhd_ifname(&dhd->pub, ifidx), cnt));
847 allmulti = cnt ? TRUE : allmulti;
848 }
849
850 MFREE(dhd->pub.osh, buf, buflen);
851
852 /* Now send the allmulti setting. This is based on the setting in the
853 * net_device flags, but might be modified above to be turned on if we
854 * were trying to set some addresses and dongle rejected it...
855 */
856
857 buflen = sizeof("allmulti") + sizeof(allmulti);
858 if (!(buf = MALLOC(dhd->pub.osh, buflen))) {
859 DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)));
860 return;
861 }
862 allmulti = htol32(allmulti);
863
864 if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) {
865 DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
866 dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen));
867 MFREE(dhd->pub.osh, buf, buflen);
868 return;
869 }
870
871
872 memset(&ioc, 0, sizeof(ioc));
873 ioc.cmd = WLC_SET_VAR;
874 ioc.buf = buf;
875 ioc.len = buflen;
876 ioc.set = TRUE;
877
878 ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
879 if (ret < 0) {
880 DHD_ERROR(("%s: set allmulti %d failed\n",
881 dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
882 }
883
884 MFREE(dhd->pub.osh, buf, buflen);
885
886 /* Finally, pick up the PROMISC flag as well, like the NIC driver does */
887
888 allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE;
889 allmulti = htol32(allmulti);
890
891 memset(&ioc, 0, sizeof(ioc));
892 ioc.cmd = WLC_SET_PROMISC;
893 ioc.buf = &allmulti;
894 ioc.len = sizeof(allmulti);
895 ioc.set = TRUE;
896
897 ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
898 if (ret < 0) {
899 DHD_ERROR(("%s: set promisc %d failed\n",
900 dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
901 }
902}
903
904static int
905_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr)
906{
907 char buf[32];
908 wl_ioctl_t ioc;
909 int ret;
910
911 if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) {
912 DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)));
913 return -1;
914 }
915 memset(&ioc, 0, sizeof(ioc));
916 ioc.cmd = WLC_SET_VAR;
917 ioc.buf = buf;
918 ioc.len = 32;
919 ioc.set = TRUE;
920
921 ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
922 if (ret < 0) {
923 DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
924 } else {
925 memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
926 }
927
928 return ret;
929}
930
931#ifdef SOFTAP
932extern struct net_device *ap_net_dev;
933extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */
934#endif
935
936static void
937dhd_op_if(dhd_if_t *ifp)
938{
939 dhd_info_t *dhd;
940 int ret = 0, err = 0;
941#ifdef SOFTAP
942 unsigned long flags;
943#endif
944
945 ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */
946
947 dhd = ifp->info;
948
949 DHD_TRACE(("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state));
950
951#ifdef WL_CFG80211
952 if (wl_cfg80211_is_progress_ifchange())
953 return;
954
955#endif
956 switch (ifp->state) {
957 case DHD_IF_ADD:
958 /*
959 * Delete the existing interface before overwriting it
960 * in case we missed the WLC_E_IF_DEL event.
961 */
962 if (ifp->net != NULL) {
963 DHD_ERROR(("%s: ERROR: netdev:%s already exists, try free & unregister \n",
964 __FUNCTION__, ifp->net->name));
965 netif_stop_queue(ifp->net);
966 unregister_netdev(ifp->net);
967 free_netdev(ifp->net);
968 }
969 /* Allocate etherdev, including space for private structure */
970 if (!(ifp->net = alloc_etherdev(sizeof(dhd)))) {
971 DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
972 ret = -ENOMEM;
973 }
974 if (ret == 0) {
975 strncpy(ifp->net->name, ifp->name, IFNAMSIZ);
976 ifp->net->name[IFNAMSIZ - 1] = '\0';
977 memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd));
978#ifdef WL_CFG80211
979 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)
980 if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx,
981 dhd_net_attach)) {
982 ifp->state = DHD_IF_NONE;
983 return;
984 }
985#endif
986 if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) {
987 DHD_ERROR(("%s: dhd_net_attach failed, err %d\n",
988 __FUNCTION__, err));
989 ret = -EOPNOTSUPP;
990 } else {
991#if defined(SOFTAP)
992 if (ap_fw_loaded && !(dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
993 /* semaphore that the soft AP CODE waits on */
994 flags = dhd_os_spin_lock(&dhd->pub);
995
996 /* save ptr to wl0.1 netdev for use in wl_iw.c */
997 ap_net_dev = ifp->net;
998 /* signal to the SOFTAP 'sleeper' thread, wl0.1 is ready */
999 up(&ap_eth_ctl.sema);
1000 dhd_os_spin_unlock(&dhd->pub, flags);
1001 }
1002#endif
1003 DHD_TRACE(("\n ==== pid:%x, net_device for if:%s created ===\n\n",
1004 current->pid, ifp->net->name));
1005 ifp->state = DHD_IF_NONE;
1006 }
1007 }
1008 break;
1009 case DHD_IF_DEL:
1010 /* Make sure that we don't enter again here if .. */
1011 /* dhd_op_if is called again from some other context */
1012 ifp->state = DHD_IF_DELETING;
1013 if (ifp->net != NULL) {
1014 DHD_TRACE(("\n%s: got 'DHD_IF_DEL' state\n", __FUNCTION__));
1015#ifdef WL_CFG80211
1016 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
1017 wl_cfg80211_notify_ifdel(ifp->net);
1018 }
1019#endif
1020 netif_stop_queue(ifp->net);
1021 unregister_netdev(ifp->net);
1022 ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */
1023 }
1024 break;
1025 case DHD_IF_DELETING:
1026 break;
1027 default:
1028 DHD_ERROR(("%s: bad op %d\n", __FUNCTION__, ifp->state));
1029 ASSERT(!ifp->state);
1030 break;
1031 }
1032
1033 if (ret < 0) {
1034 ifp->set_multicast = FALSE;
1035 if (ifp->net) {
1036 free_netdev(ifp->net);
1037 }
1038 dhd->iflist[ifp->idx] = NULL;
1039#ifdef SOFTAP
1040 flags = dhd_os_spin_lock(&dhd->pub);
1041 if (ifp->net == ap_net_dev)
1042 ap_net_dev = NULL; /* NULL SOFTAP global wl0.1 as well */
1043 dhd_os_spin_unlock(&dhd->pub, flags);
1044#endif /* SOFTAP */
1045 MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
1046 }
1047}
1048
1049static int
1050_dhd_sysioc_thread(void *data)
1051{
1052 tsk_ctl_t *tsk = (tsk_ctl_t *)data;
1053 dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
1054
1055
1056 int i;
1057#ifdef SOFTAP
1058 bool in_ap = FALSE;
1059 unsigned long flags;
1060#endif
1061
1062 DAEMONIZE("dhd_sysioc");
1063
1064 complete(&tsk->completed);
1065
1066 while (down_interruptible(&tsk->sema) == 0) {
1067
1068 SMP_RD_BARRIER_DEPENDS();
1069 if (tsk->terminated) {
1070 break;
1071 }
1072
1073 dhd_net_if_lock_local(dhd);
1074 DHD_OS_WAKE_LOCK(&dhd->pub);
1075
1076 for (i = 0; i < DHD_MAX_IFS; i++) {
1077 if (dhd->iflist[i]) {
1078 DHD_TRACE(("%s: interface %d\n", __FUNCTION__, i));
1079#ifdef SOFTAP
1080 flags = dhd_os_spin_lock(&dhd->pub);
1081 in_ap = (ap_net_dev != NULL);
1082 dhd_os_spin_unlock(&dhd->pub, flags);
1083#endif /* SOFTAP */
1084 if (dhd->iflist[i] && dhd->iflist[i]->state)
1085 dhd_op_if(dhd->iflist[i]);
1086
1087 if (dhd->iflist[i] == NULL) {
1088 DHD_TRACE(("\n\n %s: interface %d just been removed,"
1089 "!\n\n", __FUNCTION__, i));
1090 continue;
1091 }
1092#ifdef SOFTAP
1093 if (in_ap && dhd->set_macaddress) {
1094 DHD_TRACE(("attempt to set MAC for %s in AP Mode,"
1095 "blocked. \n", dhd->iflist[i]->net->name));
1096 dhd->set_macaddress = FALSE;
1097 continue;
1098 }
1099
1100 if (in_ap && dhd->iflist[i]->set_multicast) {
1101 DHD_TRACE(("attempt to set MULTICAST list for %s"
1102 "in AP Mode, blocked. \n", dhd->iflist[i]->net->name));
1103 dhd->iflist[i]->set_multicast = FALSE;
1104 continue;
1105 }
1106#endif /* SOFTAP */
1107 if (dhd->iflist[i]->set_multicast) {
1108 dhd->iflist[i]->set_multicast = FALSE;
1109 _dhd_set_multicast_list(dhd, i);
1110 }
1111 if (dhd->set_macaddress) {
1112 dhd->set_macaddress = FALSE;
1113 _dhd_set_mac_address(dhd, i, &dhd->macvalue);
1114 }
1115 }
1116 }
1117
1118 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1119 dhd_net_if_unlock_local(dhd);
1120 }
1121 DHD_TRACE(("%s: stopped\n", __FUNCTION__));
1122 complete_and_exit(&tsk->completed, 0);
1123}
1124
1125static int
1126dhd_set_mac_address(struct net_device *dev, void *addr)
1127{
1128 int ret = 0;
1129
1130 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
1131 struct sockaddr *sa = (struct sockaddr *)addr;
1132 int ifidx;
1133
1134 ifidx = dhd_net2idx(dhd, dev);
1135 if (ifidx == DHD_BAD_IF)
1136 return -1;
1137
1138 ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
1139 memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN);
1140 dhd->set_macaddress = TRUE;
1141 up(&dhd->thr_sysioc_ctl.sema);
1142
1143 return ret;
1144}
1145
1146static void
1147dhd_set_multicast_list(struct net_device *dev)
1148{
1149 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
1150 int ifidx;
1151
1152 ifidx = dhd_net2idx(dhd, dev);
1153 if (ifidx == DHD_BAD_IF)
1154 return;
1155
1156 ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
1157 dhd->iflist[ifidx]->set_multicast = TRUE;
1158 up(&dhd->thr_sysioc_ctl.sema);
1159}
1160
1161#ifdef PROP_TXSTATUS
1162int
1163dhd_os_wlfc_block(dhd_pub_t *pub)
1164{
1165 dhd_info_t *di = (dhd_info_t *)(pub->info);
1166 ASSERT(di != NULL);
1167 spin_lock_bh(&di->wlfc_spinlock);
1168 return 1;
1169}
1170
1171int
1172dhd_os_wlfc_unblock(dhd_pub_t *pub)
1173{
1174 dhd_info_t *di = (dhd_info_t *)(pub->info);
1175 ASSERT(di != NULL);
1176 spin_unlock_bh(&di->wlfc_spinlock);
1177 return 1;
1178}
1179
1180const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 };
1181uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
1182#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]]
1183
1184#endif /* PROP_TXSTATUS */
1185int
1186dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
1187{
1188 int ret;
1189 dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
1190 struct ether_header *eh = NULL;
1191
1192 /* Reject if down */
1193 if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) {
1194 /* free the packet here since the caller won't */
1195 PKTFREE(dhdp->osh, pktbuf, TRUE);
1196 return -ENODEV;
1197 }
1198
1199 /* Update multicast statistic */
1200 if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_ADDR_LEN) {
1201 uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
1202 eh = (struct ether_header *)pktdata;
1203
1204 if (ETHER_ISMULTI(eh->ether_dhost))
1205 dhdp->tx_multicast++;
1206 if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
1207 atomic_inc(&dhd->pend_8021x_cnt);
1208 }
1209
1210 /* Look into the packet and update the packet priority */
1211 if (PKTPRIO(pktbuf) == 0)
1212 pktsetprio(pktbuf, FALSE);
1213
1214#ifdef PROP_TXSTATUS
1215 if (dhdp->wlfc_state) {
1216 /* store the interface ID */
1217 DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx);
1218
1219 /* store destination MAC in the tag as well */
1220 DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost);
1221
1222 /* decide which FIFO this packet belongs to */
1223 if (ETHER_ISMULTI(eh->ether_dhost))
1224 /* one additional queue index (highest AC + 1) is used for bc/mc queue */
1225 DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT);
1226 else
1227 DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf)));
1228 } else
1229#endif /* PROP_TXSTATUS */
1230 /* If the protocol uses a data header, apply it */
1231 dhd_prot_hdrpush(dhdp, ifidx, pktbuf);
1232
1233 /* Use bus module to send data frame */
1234#ifdef WLMEDIA_HTSF
1235 dhd_htsf_addtxts(dhdp, pktbuf);
1236#endif
1237#ifdef PROP_TXSTATUS
1238 if (dhdp->wlfc_state && ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode
1239 != WLFC_FCMODE_NONE) {
1240 dhd_os_wlfc_block(dhdp);
1241 ret = dhd_wlfc_enque_sendq(dhdp->wlfc_state, DHD_PKTTAG_FIFO(PKTTAG(pktbuf)),
1242 pktbuf);
1243 dhd_wlfc_commit_packets(dhdp->wlfc_state, (f_commitpkt_t)dhd_bus_txdata,
1244 dhdp->bus);
1245 if (((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if) {
1246 ((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if = 0;
1247 }
1248 dhd_os_wlfc_unblock(dhdp);
1249 }
1250 else
1251 /* non-proptxstatus way */
1252 ret = dhd_bus_txdata(dhdp->bus, pktbuf);
1253#else
1254 ret = dhd_bus_txdata(dhdp->bus, pktbuf);
1255#endif /* PROP_TXSTATUS */
1256
1257
1258 return ret;
1259}
1260
1261int
1262dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
1263{
1264 int ret;
1265 void *pktbuf;
1266 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
1267 int ifidx;
1268#ifdef WLMEDIA_HTSF
1269 uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz;
1270#else
1271 uint8 htsfdlystat_sz = 0;
1272#endif
1273
1274 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1275
1276 DHD_OS_WAKE_LOCK(&dhd->pub);
1277
1278 /* Reject if down */
1279 if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) {
1280 DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n",
1281 __FUNCTION__, dhd->pub.up, dhd->pub.busstate));
1282 netif_stop_queue(net);
1283 /* Send Event when bus down detected during data session */
1284 if (dhd->pub.busstate == DHD_BUS_DOWN) {
1285 DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__));
1286 net_os_send_hang_message(net);
1287 }
1288 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1289 return -ENODEV;
1290 }
1291
1292 ifidx = dhd_net2idx(dhd, net);
1293 if (ifidx == DHD_BAD_IF) {
1294 DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx));
1295 netif_stop_queue(net);
1296 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1297 return -ENODEV;
1298 }
1299
1300 /* Make sure there's enough room for any header */
1301
1302 if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) {
1303 struct sk_buff *skb2;
1304
1305 DHD_INFO(("%s: insufficient headroom\n",
1306 dhd_ifname(&dhd->pub, ifidx)));
1307 dhd->pub.tx_realloc++;
1308
1309 skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz);
1310
1311 dev_kfree_skb(skb);
1312 if ((skb = skb2) == NULL) {
1313 DHD_ERROR(("%s: skb_realloc_headroom failed\n",
1314 dhd_ifname(&dhd->pub, ifidx)));
1315 ret = -ENOMEM;
1316 goto done;
1317 }
1318 }
1319
1320 /* Convert to packet */
1321 if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) {
1322 DHD_ERROR(("%s: PKTFRMNATIVE failed\n",
1323 dhd_ifname(&dhd->pub, ifidx)));
1324 dev_kfree_skb_any(skb);
1325 ret = -ENOMEM;
1326 goto done;
1327 }
1328#ifdef WLMEDIA_HTSF
1329 if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) {
1330 uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf);
1331 struct ether_header *eh = (struct ether_header *)pktdata;
1332
1333 if (!ETHER_ISMULTI(eh->ether_dhost) &&
1334 (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) {
1335 eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS);
1336 }
1337 }
1338#endif
1339
1340 ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
1341
1342
1343done:
1344 if (ret)
1345 dhd->pub.dstats.tx_dropped++;
1346 else
1347 dhd->pub.tx_packets++;
1348
1349 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1350
1351 /* Return ok: we always eat the packet */
1352 return 0;
1353}
1354
1355void
1356dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state)
1357{
1358 struct net_device *net;
1359 dhd_info_t *dhd = dhdp->info;
1360 int i;
1361
1362 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1363
1364 dhdp->txoff = state;
1365 ASSERT(dhd);
1366
1367 if (ifidx == ALL_INTERFACES) {
1368 /* Flow control on all active interfaces */
1369 for (i = 0; i < DHD_MAX_IFS; i++) {
1370 if (dhd->iflist[i]) {
1371 net = dhd->iflist[i]->net;
1372 if (state == ON)
1373 netif_stop_queue(net);
1374 else
1375 netif_wake_queue(net);
1376 }
1377 }
1378 }
1379 else {
1380 if (dhd->iflist[ifidx]) {
1381 net = dhd->iflist[ifidx]->net;
1382 if (state == ON)
1383 netif_stop_queue(net);
1384 else
1385 netif_wake_queue(net);
1386 }
1387 }
1388}
1389
1390void
1391dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan)
1392{
1393 dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
1394 struct sk_buff *skb;
1395 uchar *eth;
1396 uint len;
1397 void *data, *pnext = NULL, *save_pktbuf;
1398 int i;
1399 dhd_if_t *ifp;
1400 wl_event_msg_t event;
1401 int tout = DHD_PACKET_TIMEOUT;
1402
1403 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1404
1405 save_pktbuf = pktbuf;
1406
1407 for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) {
1408 struct ether_header *eh;
1409 struct dot11_llc_snap_header *lsh;
1410
1411 ifp = dhd->iflist[ifidx];
1412 if (ifp == NULL) {
1413 DHD_ERROR(("%s: ifp is NULL. drop packet\n",
1414 __FUNCTION__));
1415 PKTFREE(dhdp->osh, pktbuf, TRUE);
1416 continue;
1417 }
1418
1419 /* Dropping packets before registering net device to avoid kernel panic */
1420 if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED ||
1421 !dhd->pub.up) {
1422 DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n",
1423 __FUNCTION__));
1424 PKTFREE(dhdp->osh, pktbuf, TRUE);
1425 continue;
1426 }
1427
1428 pnext = PKTNEXT(dhdp->osh, pktbuf);
1429 PKTSETNEXT(wl->sh.osh, pktbuf, NULL);
1430
1431 eh = (struct ether_header *)PKTDATA(wl->sh.osh, pktbuf);
1432 lsh = (struct dot11_llc_snap_header *)&eh[1];
1433
1434 if ((ntoh16(eh->ether_type) < ETHER_TYPE_MIN) &&
1435 (PKTLEN(wl->sh.osh, pktbuf) >= RFC1042_HDR_LEN) &&
1436 bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
1437 lsh->type == HTON16(BTA_PROT_L2CAP)) {
1438 amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)
1439 ((uint8 *)eh + RFC1042_HDR_LEN);
1440 ACL_data = NULL;
1441 }
1442
1443#ifdef PROP_TXSTATUS
1444 if (dhdp->wlfc_state && PKTLEN(wl->sh.osh, pktbuf) == 0) {
1445 /* WLFC may send header only packet when
1446 there is an urgent message but no packet to
1447 piggy-back on
1448 */
1449 ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++;
1450 PKTFREE(dhdp->osh, pktbuf, TRUE);
1451 continue;
1452 }
1453#endif
1454
1455 skb = PKTTONATIVE(dhdp->osh, pktbuf);
1456
1457 /* Get the protocol, maintain skb around eth_type_trans()
1458 * The main reason for this hack is for the limitation of
1459 * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len'
1460 * to perform skb_pull inside vs ETH_HLEN. Since to avoid
1461 * coping of the packet coming from the network stack to add
1462 * BDC, Hardware header etc, during network interface registration
1463 * we set the 'net->hard_header_len' to ETH_HLEN + extra space required
1464 * for BDC, Hardware header etc. and not just the ETH_HLEN
1465 */
1466 eth = skb->data;
1467 len = skb->len;
1468
1469 ifp = dhd->iflist[ifidx];
1470 if (ifp == NULL)
1471 ifp = dhd->iflist[0];
1472
1473 ASSERT(ifp);
1474 skb->dev = ifp->net;
1475 skb->protocol = eth_type_trans(skb, skb->dev);
1476
1477 if (skb->pkt_type == PACKET_MULTICAST) {
1478 dhd->pub.rx_multicast++;
1479 }
1480
1481 skb->data = eth;
1482 skb->len = len;
1483
1484#ifdef WLMEDIA_HTSF
1485 dhd_htsf_addrxts(dhdp, pktbuf);
1486#endif
1487 /* Strip header, count, deliver upward */
1488 skb_pull(skb, ETH_HLEN);
1489
1490 /* Process special event packets and then discard them */
1491 if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) {
1492 dhd_wl_host_event(dhd, &ifidx,
1493#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
1494 skb->mac_header,
1495#else
1496 skb->mac.raw,
1497#endif
1498 &event,
1499 &data);
1500
1501 wl_event_to_host_order(&event);
1502 if (event.event_type == WLC_E_BTA_HCI_EVENT) {
1503 dhd_bta_doevt(dhdp, data, event.datalen);
1504 }
1505 tout = DHD_EVENT_TIMEOUT;
1506 }
1507
1508 ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
1509 if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state)
1510 ifp = dhd->iflist[ifidx];
1511
1512 if (ifp->net)
1513 ifp->net->last_rx = jiffies;
1514
1515 dhdp->dstats.rx_bytes += skb->len;
1516 dhdp->rx_packets++; /* Local count */
1517
1518 if (in_interrupt()) {
1519 netif_rx(skb);
1520 } else {
1521 /* If the receive is not processed inside an ISR,
1522 * the softirqd must be woken explicitly to service
1523 * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled
1524 * by netif_rx_ni(), but in earlier kernels, we need
1525 * to do it manually.
1526 */
1527#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1528 netif_rx_ni(skb);
1529#else
1530 ulong flags;
1531 netif_rx(skb);
1532 local_irq_save(flags);
1533 RAISE_RX_SOFTIRQ();
1534 local_irq_restore(flags);
1535#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
1536 }
1537 }
1538 DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(dhdp, tout);
1539}
1540
1541void
1542dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx)
1543{
1544 /* Linux version has nothing to do */
1545 return;
1546}
1547
1548void
1549dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
1550{
1551 uint ifidx;
1552 dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
1553 struct ether_header *eh;
1554 uint16 type;
1555 uint len;
1556
1557 dhd_prot_hdrpull(dhdp, &ifidx, txp);
1558
1559 eh = (struct ether_header *)PKTDATA(dhdp->osh, txp);
1560 type = ntoh16(eh->ether_type);
1561
1562 if (type == ETHER_TYPE_802_1X)
1563 atomic_dec(&dhd->pend_8021x_cnt);
1564
1565 /* Crack open the packet and check to see if it is BT HCI ACL data packet.
1566 * If yes generate packet completion event.
1567 */
1568 len = PKTLEN(dhdp->osh, txp);
1569
1570 /* Generate ACL data tx completion event locally to avoid SDIO bus transaction */
1571 if ((type < ETHER_TYPE_MIN) && (len >= RFC1042_HDR_LEN)) {
1572 struct dot11_llc_snap_header *lsh = (struct dot11_llc_snap_header *)&eh[1];
1573
1574 if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 &&
1575 ntoh16(lsh->type) == BTA_PROT_L2CAP) {
1576
1577 dhd_bta_tx_hcidata_complete(dhdp, txp, success);
1578 }
1579 }
1580}
1581
1582static struct net_device_stats *
1583dhd_get_stats(struct net_device *net)
1584{
1585 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
1586 dhd_if_t *ifp;
1587 int ifidx;
1588
1589 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1590
1591 ifidx = dhd_net2idx(dhd, net);
1592 if (ifidx == DHD_BAD_IF)
1593 return NULL;
1594
1595 ifp = dhd->iflist[ifidx];
1596 ASSERT(dhd && ifp);
1597
1598 if (dhd->pub.up) {
1599 /* Use the protocol to get dongle stats */
1600 dhd_prot_dstats(&dhd->pub);
1601 }
1602
1603 /* Copy dongle stats to net device stats */
1604 ifp->stats.rx_packets = dhd->pub.dstats.rx_packets;
1605 ifp->stats.tx_packets = dhd->pub.dstats.tx_packets;
1606 ifp->stats.rx_bytes = dhd->pub.dstats.rx_bytes;
1607 ifp->stats.tx_bytes = dhd->pub.dstats.tx_bytes;
1608 ifp->stats.rx_errors = dhd->pub.dstats.rx_errors;
1609 ifp->stats.tx_errors = dhd->pub.dstats.tx_errors;
1610 ifp->stats.rx_dropped = dhd->pub.dstats.rx_dropped;
1611 ifp->stats.tx_dropped = dhd->pub.dstats.tx_dropped;
1612 ifp->stats.multicast = dhd->pub.dstats.multicast;
1613
1614 return &ifp->stats;
1615}
1616
1617#ifdef DHDTHREAD
1618static int
1619dhd_watchdog_thread(void *data)
1620{
1621 tsk_ctl_t *tsk = (tsk_ctl_t *)data;
1622 dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
1623 /* This thread doesn't need any user-level access,
1624 * so get rid of all our resources
1625 */
1626 if (dhd_watchdog_prio > 0) {
1627 struct sched_param param;
1628 param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)?
1629 dhd_watchdog_prio:(MAX_RT_PRIO-1);
1630 setScheduler(current, SCHED_FIFO, &param);
1631 }
1632
1633 DAEMONIZE("dhd_watchdog");
1634
1635 /* Run until signal received */
1636 complete(&tsk->completed);
1637
1638 while (1)
1639 if (down_interruptible (&tsk->sema) == 0) {
1640 unsigned long flags;
1641
1642 SMP_RD_BARRIER_DEPENDS();
1643 if (tsk->terminated) {
1644 break;
1645 }
1646
1647 dhd_os_sdlock(&dhd->pub);
1648 if (dhd->pub.dongle_reset == FALSE) {
1649 DHD_TIMER(("%s:\n", __FUNCTION__));
1650
1651 /* Call the bus module watchdog */
1652 dhd_bus_watchdog(&dhd->pub);
1653
1654 flags = dhd_os_spin_lock(&dhd->pub);
1655 /* Count the tick for reference */
1656 dhd->pub.tickcnt++;
1657 /* Reschedule the watchdog */
1658 if (dhd->wd_timer_valid)
1659 mod_timer(&dhd->timer,
1660 jiffies + dhd_watchdog_ms * HZ / 1000);
1661 dhd_os_spin_unlock(&dhd->pub, flags);
1662 }
1663 dhd_os_sdunlock(&dhd->pub);
1664 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1665 } else {
1666 break;
1667 }
1668
1669 complete_and_exit(&tsk->completed, 0);
1670}
1671#endif /* DHDTHREAD */
1672
1673static void dhd_watchdog(ulong data)
1674{
1675 dhd_info_t *dhd = (dhd_info_t *)data;
1676 unsigned long flags;
1677
1678 DHD_OS_WAKE_LOCK(&dhd->pub);
1679 if (dhd->pub.dongle_reset) {
1680 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1681 return;
1682 }
1683
1684#ifdef DHDTHREAD
1685 if (dhd->thr_wdt_ctl.thr_pid >= 0) {
1686 up(&dhd->thr_wdt_ctl.sema);
1687 return;
1688 }
1689#endif /* DHDTHREAD */
1690
1691 dhd_os_sdlock(&dhd->pub);
1692 /* Call the bus module watchdog */
1693 dhd_bus_watchdog(&dhd->pub);
1694
1695 flags = dhd_os_spin_lock(&dhd->pub);
1696 /* Count the tick for reference */
1697 dhd->pub.tickcnt++;
1698
1699 /* Reschedule the watchdog */
1700 if (dhd->wd_timer_valid)
1701 mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
1702 dhd_os_spin_unlock(&dhd->pub, flags);
1703 dhd_os_sdunlock(&dhd->pub);
1704 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1705}
1706
1707#ifdef DHDTHREAD
1708static int
1709dhd_dpc_thread(void *data)
1710{
1711 tsk_ctl_t *tsk = (tsk_ctl_t *)data;
1712 dhd_info_t *dhd = (dhd_info_t *)tsk->parent;
1713
1714 /* This thread doesn't need any user-level access,
1715 * so get rid of all our resources
1716 */
1717 if (dhd_dpc_prio > 0)
1718 {
1719 struct sched_param param;
1720 param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1);
1721 setScheduler(current, SCHED_FIFO, &param);
1722 }
1723
1724 DAEMONIZE("dhd_dpc");
1725 /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */
1726
1727 /* signal: thread has started */
1728 complete(&tsk->completed);
1729
1730 /* Run until signal received */
1731 while (1) {
1732 if (down_interruptible(&tsk->sema) == 0) {
1733
1734 SMP_RD_BARRIER_DEPENDS();
1735 if (tsk->terminated) {
1736 break;
1737 }
1738
1739 /* Call bus dpc unless it indicated down (then clean stop) */
1740 if (dhd->pub.busstate != DHD_BUS_DOWN) {
1741 if (dhd_bus_dpc(dhd->pub.bus)) {
1742 up(&tsk->sema);
1743 }
1744 else {
1745 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1746 }
1747 } else {
1748 if (dhd->pub.up)
1749 dhd_bus_stop(dhd->pub.bus, TRUE);
1750 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1751 }
1752 }
1753 else
1754 break;
1755 }
1756
1757 complete_and_exit(&tsk->completed, 0);
1758}
1759#endif /* DHDTHREAD */
1760
1761static void
1762dhd_dpc(ulong data)
1763{
1764 dhd_info_t *dhd;
1765
1766 dhd = (dhd_info_t *)data;
1767
1768 /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c]
1769 * down below , wake lock is set,
1770 * the tasklet is initialized in dhd_attach()
1771 */
1772 /* Call bus dpc unless it indicated down (then clean stop) */
1773 if (dhd->pub.busstate != DHD_BUS_DOWN) {
1774 if (dhd_bus_dpc(dhd->pub.bus))
1775 tasklet_schedule(&dhd->tasklet);
1776 else
1777 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1778 } else {
1779 dhd_bus_stop(dhd->pub.bus, TRUE);
1780 DHD_OS_WAKE_UNLOCK(&dhd->pub);
1781 }
1782}
1783
1784void
1785dhd_sched_dpc(dhd_pub_t *dhdp)
1786{
1787 dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
1788
1789 DHD_OS_WAKE_LOCK(dhdp);
1790#ifdef DHDTHREAD
1791 if (dhd->thr_dpc_ctl.thr_pid >= 0) {
1792 up(&dhd->thr_dpc_ctl.sema);
1793 return;
1794 }
1795#endif /* DHDTHREAD */
1796
1797 tasklet_schedule(&dhd->tasklet);
1798}
1799
1800#ifdef TOE
1801/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */
1802static int
1803dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol)
1804{
1805 wl_ioctl_t ioc;
1806 char buf[32];
1807 int ret;
1808
1809 memset(&ioc, 0, sizeof(ioc));
1810
1811 ioc.cmd = WLC_GET_VAR;
1812 ioc.buf = buf;
1813 ioc.len = (uint)sizeof(buf);
1814 ioc.set = FALSE;
1815
1816 strcpy(buf, "toe_ol");
1817 if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
1818 /* Check for older dongle image that doesn't support toe_ol */
1819 if (ret == -EIO) {
1820 DHD_ERROR(("%s: toe not supported by device\n",
1821 dhd_ifname(&dhd->pub, ifidx)));
1822 return -EOPNOTSUPP;
1823 }
1824
1825 DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
1826 return ret;
1827 }
1828
1829 memcpy(toe_ol, buf, sizeof(uint32));
1830 return 0;
1831}
1832
1833/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */
1834static int
1835dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol)
1836{
1837 wl_ioctl_t ioc;
1838 char buf[32];
1839 int toe, ret;
1840
1841 memset(&ioc, 0, sizeof(ioc));
1842
1843 ioc.cmd = WLC_SET_VAR;
1844 ioc.buf = buf;
1845 ioc.len = (uint)sizeof(buf);
1846 ioc.set = TRUE;
1847
1848 /* Set toe_ol as requested */
1849
1850 strcpy(buf, "toe_ol");
1851 memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32));
1852
1853 if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
1854 DHD_ERROR(("%s: could not set toe_ol: ret=%d\n",
1855 dhd_ifname(&dhd->pub, ifidx), ret));
1856 return ret;
1857 }
1858
1859 /* Enable toe globally only if any components are enabled. */
1860
1861 toe = (toe_ol != 0);
1862
1863 strcpy(buf, "toe");
1864 memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32));
1865
1866 if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
1867 DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
1868 return ret;
1869 }
1870
1871 return 0;
1872}
1873#endif /* TOE */
1874
1875#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1876static void
1877dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
1878{
1879 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
1880
1881 sprintf(info->driver, "wl");
1882 sprintf(info->version, "%lu", dhd->pub.drv_version);
1883}
1884
1885struct ethtool_ops dhd_ethtool_ops = {
1886 .get_drvinfo = dhd_ethtool_get_drvinfo
1887};
1888#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
1889
1890
1891#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
1892static int
1893dhd_ethtool(dhd_info_t *dhd, void *uaddr)
1894{
1895 struct ethtool_drvinfo info;
1896 char drvname[sizeof(info.driver)];
1897 uint32 cmd;
1898#ifdef TOE
1899 struct ethtool_value edata;
1900 uint32 toe_cmpnt, csum_dir;
1901 int ret;
1902#endif
1903
1904 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1905
1906 /* all ethtool calls start with a cmd word */
1907 if (copy_from_user(&cmd, uaddr, sizeof (uint32)))
1908 return -EFAULT;
1909
1910 switch (cmd) {
1911 case ETHTOOL_GDRVINFO:
1912 /* Copy out any request driver name */
1913 if (copy_from_user(&info, uaddr, sizeof(info)))
1914 return -EFAULT;
1915 strncpy(drvname, info.driver, sizeof(info.driver));
1916 drvname[sizeof(info.driver)-1] = '\0';
1917
1918 /* clear struct for return */
1919 memset(&info, 0, sizeof(info));
1920 info.cmd = cmd;
1921
1922 /* if dhd requested, identify ourselves */
1923 if (strcmp(drvname, "?dhd") == 0) {
1924 sprintf(info.driver, "dhd");
1925 strcpy(info.version, EPI_VERSION_STR);
1926 }
1927
1928 /* otherwise, require dongle to be up */
1929 else if (!dhd->pub.up) {
1930 DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__));
1931 return -ENODEV;
1932 }
1933
1934 /* finally, report dongle driver type */
1935 else if (dhd->pub.iswl)
1936 sprintf(info.driver, "wl");
1937 else
1938 sprintf(info.driver, "xx");
1939
1940 sprintf(info.version, "%lu", dhd->pub.drv_version);
1941 if (copy_to_user(uaddr, &info, sizeof(info)))
1942 return -EFAULT;
1943 DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__,
1944 (int)sizeof(drvname), drvname, info.driver));
1945 break;
1946
1947#ifdef TOE
1948 /* Get toe offload components from dongle */
1949 case ETHTOOL_GRXCSUM:
1950 case ETHTOOL_GTXCSUM:
1951 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
1952 return ret;
1953
1954 csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
1955
1956 edata.cmd = cmd;
1957 edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
1958
1959 if (copy_to_user(uaddr, &edata, sizeof(edata)))
1960 return -EFAULT;
1961 break;
1962
1963 /* Set toe offload components in dongle */
1964 case ETHTOOL_SRXCSUM:
1965 case ETHTOOL_STXCSUM:
1966 if (copy_from_user(&edata, uaddr, sizeof(edata)))
1967 return -EFAULT;
1968
1969 /* Read the current settings, update and write back */
1970 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
1971 return ret;
1972
1973 csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
1974
1975 if (edata.data != 0)
1976 toe_cmpnt |= csum_dir;
1977 else
1978 toe_cmpnt &= ~csum_dir;
1979
1980 if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0)
1981 return ret;
1982
1983 /* If setting TX checksum mode, tell Linux the new mode */
1984 if (cmd == ETHTOOL_STXCSUM) {
1985 if (edata.data)
1986 dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM;
1987 else
1988 dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM;
1989 }
1990
1991 break;
1992#endif /* TOE */
1993
1994 default:
1995 return -EOPNOTSUPP;
1996 }
1997
1998 return 0;
1999}
2000#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
2001
2002static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error)
2003{
2004 if (!dhdp)
2005 return FALSE;
2006 if ((error == -ETIMEDOUT) || ((dhdp->busstate == DHD_BUS_DOWN) &&
2007 (!dhdp->dongle_reset))) {
2008 DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__,
2009 dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate));
2010 net_os_send_hang_message(net);
2011 return TRUE;
2012 }
2013 return FALSE;
2014}
2015
2016static int
2017dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
2018{
2019 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
2020 dhd_ioctl_t ioc;
2021 int bcmerror = 0;
2022 int buflen = 0;
2023 void *buf = NULL;
2024 uint driver = 0;
2025 int ifidx;
2026 int ret;
2027
2028 DHD_OS_WAKE_LOCK(&dhd->pub);
2029
2030 /* send to dongle only if we are not waiting for reload already */
2031 if (dhd->pub.hang_was_sent) {
2032 DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
2033 DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT);
2034 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2035 return OSL_ERROR(BCME_DONGLE_DOWN);
2036 }
2037
2038 ifidx = dhd_net2idx(dhd, net);
2039 DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
2040
2041 if (ifidx == DHD_BAD_IF) {
2042 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2043 return -1;
2044 }
2045
2046#if defined(CONFIG_BCMDHD_WEXT)
2047 /* linux wireless extensions */
2048 if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
2049 /* may recurse, do NOT lock */
2050 ret = wl_iw_ioctl(net, ifr, cmd);
2051 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2052 return ret;
2053 }
2054#endif /* defined(CONFIG_BCMDHD_WEXT) */
2055
2056#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
2057 if (cmd == SIOCETHTOOL) {
2058 ret = dhd_ethtool(dhd, (void*)ifr->ifr_data);
2059 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2060 return ret;
2061 }
2062#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
2063
2064 if (cmd == SIOCDEVPRIVATE+1) {
2065 ret = wl_android_priv_cmd(net, ifr, cmd);
2066 dhd_check_hang(net, &dhd->pub, ret);
2067 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2068 return ret;
2069 }
2070
2071 if (cmd != SIOCDEVPRIVATE) {
2072 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2073 return -EOPNOTSUPP;
2074 }
2075
2076 memset(&ioc, 0, sizeof(ioc));
2077
2078 /* Copy the ioc control structure part of ioctl request */
2079 if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {
2080 bcmerror = -BCME_BADADDR;
2081 goto done;
2082 }
2083
2084 /* Copy out any buffer passed */
2085 if (ioc.buf) {
2086 buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN);
2087 /* optimization for direct ioctl calls from kernel */
2088 /*
2089 if (segment_eq(get_fs(), KERNEL_DS)) {
2090 buf = ioc.buf;
2091 } else {
2092 */
2093 {
2094 if (!(buf = (char*)MALLOC(dhd->pub.osh, buflen))) {
2095 bcmerror = -BCME_NOMEM;
2096 goto done;
2097 }
2098 if (copy_from_user(buf, ioc.buf, buflen)) {
2099 bcmerror = -BCME_BADADDR;
2100 goto done;
2101 }
2102 }
2103 }
2104
2105 /* To differentiate between wl and dhd read 4 more byes */
2106 if ((copy_from_user(&driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t),
2107 sizeof(uint)) != 0)) {
2108 bcmerror = -BCME_BADADDR;
2109 goto done;
2110 }
2111
2112 if (!capable(CAP_NET_ADMIN)) {
2113 bcmerror = -BCME_EPERM;
2114 goto done;
2115 }
2116
2117 /* check for local dhd ioctl and handle it */
2118 if (driver == DHD_IOCTL_MAGIC) {
2119 bcmerror = dhd_ioctl((void *)&dhd->pub, &ioc, buf, buflen);
2120 if (bcmerror)
2121 dhd->pub.bcmerror = bcmerror;
2122 goto done;
2123 }
2124
2125 /* send to dongle (must be up, and wl). */
2126 if (dhd->pub.busstate != DHD_BUS_DATA) {
2127 bcmerror = BCME_DONGLE_DOWN;
2128 goto done;
2129 }
2130
2131 if (!dhd->pub.iswl) {
2132 bcmerror = BCME_DONGLE_DOWN;
2133 goto done;
2134 }
2135
2136 /*
2137 * Flush the TX queue if required for proper message serialization:
2138 * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to
2139 * prevent M4 encryption and
2140 * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to
2141 * prevent disassoc frame being sent before WPS-DONE frame.
2142 */
2143 if (ioc.cmd == WLC_SET_KEY ||
2144 (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL &&
2145 strncmp("wsec_key", ioc.buf, 9) == 0) ||
2146 (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL &&
2147 strncmp("bsscfg:wsec_key", ioc.buf, 15) == 0) ||
2148 ioc.cmd == WLC_DISASSOC)
2149 dhd_wait_pend8021x(net);
2150
2151#ifdef WLMEDIA_HTSF
2152 if (ioc.buf) {
2153 /* short cut wl ioctl calls here */
2154 if (strcmp("htsf", ioc.buf) == 0) {
2155 dhd_ioctl_htsf_get(dhd, 0);
2156 return BCME_OK;
2157 }
2158
2159 if (strcmp("htsflate", ioc.buf) == 0) {
2160 if (ioc.set) {
2161 memset(ts, 0, sizeof(tstamp_t)*TSMAX);
2162 memset(&maxdelayts, 0, sizeof(tstamp_t));
2163 maxdelay = 0;
2164 tspktcnt = 0;
2165 maxdelaypktno = 0;
2166 memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
2167 memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
2168 memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
2169 memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
2170 } else {
2171 dhd_dump_latency();
2172 }
2173 return BCME_OK;
2174 }
2175 if (strcmp("htsfclear", ioc.buf) == 0) {
2176 memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN);
2177 memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN);
2178 memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN);
2179 memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN);
2180 htsf_seqnum = 0;
2181 return BCME_OK;
2182 }
2183 if (strcmp("htsfhis", ioc.buf) == 0) {
2184 dhd_dump_htsfhisto(&vi_d1, "H to D");
2185 dhd_dump_htsfhisto(&vi_d2, "D to D");
2186 dhd_dump_htsfhisto(&vi_d3, "D to H");
2187 dhd_dump_htsfhisto(&vi_d4, "H to H");
2188 return BCME_OK;
2189 }
2190 if (strcmp("tsport", ioc.buf) == 0) {
2191 if (ioc.set) {
2192 memcpy(&tsport, ioc.buf + 7, 4);
2193 } else {
2194 DHD_ERROR(("current timestamp port: %d \n", tsport));
2195 }
2196 return BCME_OK;
2197 }
2198 }
2199#endif /* WLMEDIA_HTSF */
2200
2201 bcmerror = dhd_wl_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen);
2202
2203done:
2204 dhd_check_hang(net, &dhd->pub, bcmerror);
2205
2206 if (!bcmerror && buf && ioc.buf) {
2207 if (copy_to_user(ioc.buf, buf, buflen))
2208 bcmerror = -EFAULT;
2209 }
2210
2211 if (buf)
2212 MFREE(dhd->pub.osh, buf, buflen);
2213
2214 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2215
2216 return OSL_ERROR(bcmerror);
2217}
2218
2219#ifdef WL_CFG80211
2220static int
2221dhd_cleanup_virt_ifaces(dhd_info_t *dhd)
2222{
2223 int i = 1; /* Leave ifidx 0 [Primary Interface] */
2224#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
2225 int rollback_lock = FALSE;
2226#endif
2227
2228 DHD_TRACE(("%s: Enter \n", __func__));
2229
2230#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
2231 /* release lock for unregister_netdev */
2232 if (rtnl_is_locked()) {
2233 rtnl_unlock();
2234 rollback_lock = TRUE;
2235 }
2236#endif
2237
2238 for (i = 1; i < DHD_MAX_IFS; i++) {
2239 if (dhd->iflist[i]) {
2240 DHD_TRACE(("Deleting IF: %d \n", i));
2241 if ((dhd->iflist[i]->state != DHD_IF_DEL) &&
2242 (dhd->iflist[i]->state != DHD_IF_DELETING)) {
2243 dhd->iflist[i]->state = DHD_IF_DEL;
2244 dhd->iflist[i]->idx = i;
2245 dhd_op_if(dhd->iflist[i]);
2246 }
2247 }
2248 }
2249
2250#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
2251 if (rollback_lock)
2252 rtnl_lock();
2253#endif
2254
2255 return 0;
2256}
2257#endif /* WL_CFG80211 */
2258
2259static int
2260dhd_stop(struct net_device *net)
2261{
2262 int ifidx;
2263 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
2264 DHD_OS_WAKE_LOCK(&dhd->pub);
2265 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2266 if (dhd->pub.up == 0) {
2267 goto exit;
2268 }
2269 ifidx = dhd_net2idx(dhd, net);
2270
2271#ifdef WL_CFG80211
2272 if (ifidx == 0) {
2273 wl_cfg80211_down();
2274
2275 /*
2276 * For CFG80211: Clean up all the left over virtual interfaces
2277 * when the primary Interface is brought down. [ifconfig wlan0 down]
2278 */
2279 if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) &&
2280 (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) {
2281 dhd_cleanup_virt_ifaces(dhd);
2282 }
2283 }
2284#endif
2285
2286#ifdef PROP_TXSTATUS
2287 dhd_wlfc_cleanup(&dhd->pub);
2288#endif
2289 /* Set state and stop OS transmissions */
2290 dhd->pub.up = 0;
2291 netif_stop_queue(net);
2292
2293 /* Stop the protocol module */
2294 dhd_prot_stop(&dhd->pub);
2295
2296#if defined(WL_CFG80211)
2297 if (ifidx == 0 && !dhd_download_fw_on_driverload)
2298 wl_android_wifi_off(net);
2299#endif
2300 dhd->pub.hang_was_sent = 0;
2301 dhd->pub.rxcnt_timeout = 0;
2302 dhd->pub.txcnt_timeout = 0;
2303 OLD_MOD_DEC_USE_COUNT;
2304exit:
2305 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2306 return 0;
2307}
2308
2309static int
2310dhd_open(struct net_device *net)
2311{
2312 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
2313
2314#ifdef TOE
2315 uint32 toe_ol;
2316#endif
2317 int ifidx;
2318 int32 ret = 0;
2319
2320 DHD_OS_WAKE_LOCK(&dhd->pub);
2321 /* Update FW path if it was changed */
2322 if ((firmware_path != NULL) && (firmware_path[0] != '\0')) {
2323 if (firmware_path[strlen(firmware_path)-1] == '\n')
2324 firmware_path[strlen(firmware_path)-1] = '\0';
2325 strcpy(fw_path, firmware_path);
2326 firmware_path[0] = '\0';
2327 }
2328
2329#if !defined(WL_CFG80211)
2330 /*
2331 * Force start if ifconfig_up gets called before START command
2332 * We keep WEXT's wl_control_wl_start to provide backward compatibility
2333 * This should be removed in the future
2334 */
2335 wl_control_wl_start(net);
2336#endif
2337
2338 ifidx = dhd_net2idx(dhd, net);
2339 DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
2340
2341 if (ifidx < 0) {
2342 DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__));
2343 ret = -1;
2344 goto exit;
2345 }
2346
2347 if (!dhd->iflist[ifidx] || dhd->iflist[ifidx]->state == DHD_IF_DEL) {
2348 DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
2349 ret = -1;
2350 goto exit;
2351 }
2352
2353 if (ifidx == 0) {
2354 atomic_set(&dhd->pend_8021x_cnt, 0);
2355#if defined(WL_CFG80211)
2356 DHD_ERROR(("\n%s\n", dhd_version));
2357 if (!dhd_download_fw_on_driverload)
2358 wl_android_wifi_on(net);
2359#endif /* defined(WL_CFG80211) */
2360
2361 if (dhd->pub.busstate != DHD_BUS_DATA) {
2362 int ret;
2363
2364 /* try to bring up bus */
2365 if ((ret = dhd_bus_start(&dhd->pub)) != 0) {
2366 DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret));
2367 ret = -1;
2368 goto exit;
2369 }
2370
2371 }
2372
2373 /* dhd_prot_init has been called in dhd_bus_start or wl_android_wifi_on */
2374 memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
2375
2376#ifdef TOE
2377 /* Get current TOE mode from dongle */
2378 if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0)
2379 dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM;
2380 else
2381 dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM;
2382#endif /* TOE */
2383
2384#if defined(WL_CFG80211)
2385 if (unlikely(wl_cfg80211_up())) {
2386 DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__));
2387 ret = -1;
2388 goto exit;
2389 }
2390#endif /* WL_CFG80211 */
2391 }
2392
2393 /* Allow transmit calls */
2394 netif_start_queue(net);
2395 dhd->pub.up = 1;
2396
2397#ifdef BCMDBGFS
2398 dhd_dbg_init(&dhd->pub);
2399#endif
2400
2401 OLD_MOD_INC_USE_COUNT;
2402exit:
2403 DHD_OS_WAKE_UNLOCK(&dhd->pub);
2404 return ret;
2405}
2406
2407osl_t *
2408dhd_osl_attach(void *pdev, uint bustype)
2409{
2410 return osl_attach(pdev, bustype, TRUE);
2411}
2412
2413void
2414dhd_osl_detach(osl_t *osh)
2415{
2416 if (MALLOCED(osh)) {
2417 DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)));
2418 }
2419 osl_detach(osh);
2420#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
2421 up(&dhd_registration_sem);
2422#endif
2423}
2424
2425int
2426dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name,
2427 uint8 *mac_addr, uint32 flags, uint8 bssidx)
2428{
2429 dhd_if_t *ifp;
2430
2431 DHD_TRACE(("%s: idx %d, handle->%p\n", __FUNCTION__, ifidx, handle));
2432
2433 ASSERT(dhd && (ifidx < DHD_MAX_IFS));
2434
2435 ifp = dhd->iflist[ifidx];
2436 if (ifp != NULL) {
2437 if (ifp->net != NULL) {
2438 netif_stop_queue(ifp->net);
2439 unregister_netdev(ifp->net);
2440 free_netdev(ifp->net);
2441 }
2442 } else
2443 if ((ifp = MALLOC(dhd->pub.osh, sizeof(dhd_if_t))) == NULL) {
2444 DHD_ERROR(("%s: OOM - dhd_if_t\n", __FUNCTION__));
2445 return -ENOMEM;
2446 }
2447
2448 memset(ifp, 0, sizeof(dhd_if_t));
2449 ifp->info = dhd;
2450 dhd->iflist[ifidx] = ifp;
2451 strncpy(ifp->name, name, IFNAMSIZ);
2452 ifp->name[IFNAMSIZ] = '\0';
2453 if (mac_addr != NULL)
2454 memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN);
2455
2456 if (handle == NULL) {
2457 ifp->state = DHD_IF_ADD;
2458 ifp->idx = ifidx;
2459 ifp->bssidx = bssidx;
2460 ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
2461 up(&dhd->thr_sysioc_ctl.sema);
2462 } else
2463 ifp->net = (struct net_device *)handle;
2464
2465 return 0;
2466}
2467
2468void
2469dhd_del_if(dhd_info_t *dhd, int ifidx)
2470{
2471 dhd_if_t *ifp;
2472
2473 DHD_TRACE(("%s: idx %d\n", __FUNCTION__, ifidx));
2474
2475 ASSERT(dhd && ifidx && (ifidx < DHD_MAX_IFS));
2476 ifp = dhd->iflist[ifidx];
2477 if (!ifp) {
2478 DHD_ERROR(("%s: Null interface\n", __FUNCTION__));
2479 return;
2480 }
2481
2482 ifp->state = DHD_IF_DEL;
2483 ifp->idx = ifidx;
2484 ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0);
2485 up(&dhd->thr_sysioc_ctl.sema);
2486}
2487
2488dhd_pub_t *
2489dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
2490{
2491 dhd_info_t *dhd = NULL;
2492 struct net_device *net = NULL;
2493
2494 dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT;
2495 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2496
2497 /* updates firmware nvram path if it was provided as module parameters */
2498 if ((firmware_path != NULL) && (firmware_path[0] != '\0'))
2499 strcpy(fw_path, firmware_path);
2500 if ((nvram_path != NULL) && (nvram_path[0] != '\0'))
2501 strcpy(nv_path, nvram_path);
2502
2503 /* Allocate etherdev, including space for private structure */
2504 if (!(net = alloc_etherdev(sizeof(dhd)))) {
2505 DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
2506 goto fail;
2507 }
2508 dhd_state |= DHD_ATTACH_STATE_NET_ALLOC;
2509
2510 SET_NETDEV_DEV(net, (struct device *)dev);
2511 /* Allocate primary dhd_info */
2512 if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) {
2513 DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__));
2514 goto fail;
2515 }
2516 memset(dhd, 0, sizeof(dhd_info_t));
2517
2518#ifdef DHDTHREAD
2519 dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID;
2520 dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID;
2521#else
2522 dhd->dhd_tasklet_create = FALSE;
2523#endif /* DHDTHREAD */
2524 dhd->thr_sysioc_ctl.thr_pid = DHD_PID_KT_INVALID;
2525 dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC;
2526
2527 /*
2528 * Save the dhd_info into the priv
2529 */
2530 memcpy((void *)netdev_priv(net), &dhd, sizeof(dhd));
2531 dhd->pub.osh = osh;
2532
2533 /* Link to info module */
2534 dhd->pub.info = dhd;
2535 /* Link to bus module */
2536 dhd->pub.bus = bus;
2537 dhd->pub.hdrlen = bus_hdrlen;
2538
2539 /* Set network interface name if it was provided as module parameter */
2540 if (iface_name[0]) {
2541 int len;
2542 char ch;
2543 strncpy(net->name, iface_name, IFNAMSIZ);
2544 net->name[IFNAMSIZ - 1] = 0;
2545 len = strlen(net->name);
2546 ch = net->name[len - 1];
2547 if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
2548 strcat(net->name, "%d");
2549 }
2550
2551 if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF)
2552 goto fail;
2553 dhd_state |= DHD_ATTACH_STATE_ADD_IF;
2554
2555#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
2556 net->open = NULL;
2557#else
2558 net->netdev_ops = NULL;
2559#endif
2560
2561 sema_init(&dhd->proto_sem, 1);
2562
2563#ifdef PROP_TXSTATUS
2564 spin_lock_init(&dhd->wlfc_spinlock);
2565 dhd->pub.wlfc_enabled = TRUE;
2566#endif /* PROP_TXSTATUS */
2567
2568 /* Initialize other structure content */
2569 init_waitqueue_head(&dhd->ioctl_resp_wait);
2570 init_waitqueue_head(&dhd->ctrl_wait);
2571
2572 /* Initialize the spinlocks */
2573 spin_lock_init(&dhd->sdlock);
2574 spin_lock_init(&dhd->txqlock);
2575 spin_lock_init(&dhd->dhd_lock);
2576
2577 /* Initialize Wakelock stuff */
2578 spin_lock_init(&dhd->wakelock_spinlock);
2579 dhd->wakelock_counter = 0;
2580 dhd->wakelock_timeout_enable = 0;
2581#ifdef CONFIG_HAS_WAKELOCK
2582 wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
2583 wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
2584#endif
2585#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
2586 mutex_init(&dhd->dhd_net_if_mutex);
2587#endif
2588 dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT;
2589
2590 /* Attach and link in the protocol */
2591 if (dhd_prot_attach(&dhd->pub) != 0) {
2592 DHD_ERROR(("dhd_prot_attach failed\n"));
2593 goto fail;
2594 }
2595 dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH;
2596
2597#ifdef WL_CFG80211
2598 /* Attach and link in the cfg80211 */
2599 if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) {
2600 DHD_ERROR(("wl_cfg80211_attach failed\n"));
2601 goto fail;
2602 }
2603
2604 dhd_monitor_init(&dhd->pub);
2605 dhd_state |= DHD_ATTACH_STATE_CFG80211;
2606#endif
2607#if defined(CONFIG_BCMDHD_WEXT)
2608 /* Attach and link in the iw */
2609 if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) {
2610 if (wl_iw_attach(net, (void *)&dhd->pub) != 0) {
2611 DHD_ERROR(("wl_iw_attach failed\n"));
2612 goto fail;
2613 }
2614 dhd_state |= DHD_ATTACH_STATE_WL_ATTACH;
2615 }
2616#endif /* defined(CONFIG_BCMDHD_WEXT) */
2617
2618
2619 /* Set up the watchdog timer */
2620 init_timer(&dhd->timer);
2621 dhd->timer.data = (ulong)dhd;
2622 dhd->timer.function = dhd_watchdog;
2623
2624#ifdef DHDTHREAD
2625 /* Initialize thread based operation and lock */
2626 sema_init(&dhd->sdsem, 1);
2627 if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0)) {
2628 dhd->threads_only = TRUE;
2629 }
2630 else {
2631 dhd->threads_only = FALSE;
2632 }
2633
2634 if (dhd_dpc_prio >= 0) {
2635 /* Initialize watchdog thread */
2636 PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0);
2637 } else {
2638 dhd->thr_wdt_ctl.thr_pid = -1;
2639 }
2640
2641 /* Set up the bottom half handler */
2642 if (dhd_dpc_prio >= 0) {
2643 /* Initialize DPC thread */
2644 PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0);
2645 } else {
2646 /* use tasklet for dpc */
2647 tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
2648 dhd->thr_dpc_ctl.thr_pid = -1;
2649 }
2650#else
2651 /* Set up the bottom half handler */
2652 tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
2653 dhd->dhd_tasklet_create = TRUE;
2654#endif /* DHDTHREAD */
2655
2656 if (dhd_sysioc) {
2657 PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0);
2658 } else {
2659 dhd->thr_sysioc_ctl.thr_pid = -1;
2660 }
2661 dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED;
2662
2663 /*
2664 * Save the dhd_info into the priv
2665 */
2666 memcpy(netdev_priv(net), &dhd, sizeof(dhd));
2667
2668#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
2669 register_pm_notifier(&dhd_sleep_pm_notifier);
2670#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
2671
2672#ifdef CONFIG_HAS_EARLYSUSPEND
2673 dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
2674 dhd->early_suspend.suspend = dhd_early_suspend;
2675 dhd->early_suspend.resume = dhd_late_resume;
2676 register_early_suspend(&dhd->early_suspend);
2677 dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE;
2678#endif
2679
2680#ifdef ARP_OFFLOAD_SUPPORT
2681 register_inetaddr_notifier(&dhd_notifier);
2682#endif /* ARP_OFFLOAD_SUPPORT */
2683
2684 dhd_state |= DHD_ATTACH_STATE_DONE;
2685 dhd->dhd_state = dhd_state;
2686 return &dhd->pub;
2687
2688fail:
2689 if (dhd_state < DHD_ATTACH_STATE_DHD_ALLOC) {
2690 if (net) free_netdev(net);
2691 } else {
2692 DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n",
2693 __FUNCTION__, dhd_state, &dhd->pub));
2694 dhd->dhd_state = dhd_state;
2695 dhd_detach(&dhd->pub);
2696 dhd_free(&dhd->pub);
2697 }
2698
2699 return NULL;
2700}
2701
2702int
2703dhd_bus_start(dhd_pub_t *dhdp)
2704{
2705 int ret = -1;
2706 dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
2707 unsigned long flags;
2708
2709 ASSERT(dhd);
2710
2711 DHD_TRACE(("Enter %s:\n", __FUNCTION__));
2712
2713#ifdef DHDTHREAD
2714 dhd_os_sdlock(dhdp);
2715#endif /* DHDTHREAD */
2716
2717 /* try to download image and nvram to the dongle */
2718 if ((dhd->pub.busstate == DHD_BUS_DOWN) &&
2719 (fw_path != NULL) && (fw_path[0] != '\0') &&
2720 (nv_path != NULL) && (nv_path[0] != '\0')) {
2721 /* wake lock moved to dhdsdio_download_firmware */
2722 if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh,
2723 fw_path, nv_path))) {
2724 DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n",
2725 __FUNCTION__, fw_path, nv_path));
2726#ifdef DHDTHREAD
2727 dhd_os_sdunlock(dhdp);
2728#endif /* DHDTHREAD */
2729 return -1;
2730 }
2731 }
2732 if (dhd->pub.busstate != DHD_BUS_LOAD) {
2733#ifdef DHDTHREAD
2734 dhd_os_sdunlock(dhdp);
2735#endif /* DHDTHREAD */
2736 return -ENETDOWN;
2737 }
2738
2739 /* Start the watchdog timer */
2740 dhd->pub.tickcnt = 0;
2741 dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
2742
2743 /* Bring up the bus */
2744 if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) {
2745
2746 DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
2747#ifdef DHDTHREAD
2748 dhd_os_sdunlock(dhdp);
2749#endif /* DHDTHREAD */
2750 return ret;
2751 }
2752#if defined(OOB_INTR_ONLY)
2753 /* Host registration for OOB interrupt */
2754 if (bcmsdh_register_oob_intr(dhdp)) {
2755 /* deactivate timer and wait for the handler to finish */
2756
2757 flags = dhd_os_spin_lock(&dhd->pub);
2758 dhd->wd_timer_valid = FALSE;
2759 dhd_os_spin_unlock(&dhd->pub, flags);
2760 del_timer_sync(&dhd->timer);
2761
2762 DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__));
2763#ifdef DHDTHREAD
2764 dhd_os_sdunlock(dhdp);
2765#endif /* DHDTHREAD */
2766 return -ENODEV;
2767 }
2768
2769 /* Enable oob at firmware */
2770 dhd_enable_oob_intr(dhd->pub.bus, TRUE);
2771#endif /* defined(OOB_INTR_ONLY) */
2772
2773 /* If bus is not ready, can't come up */
2774 if (dhd->pub.busstate != DHD_BUS_DATA) {
2775 flags = dhd_os_spin_lock(&dhd->pub);
2776 dhd->wd_timer_valid = FALSE;
2777 dhd_os_spin_unlock(&dhd->pub, flags);
2778 del_timer_sync(&dhd->timer);
2779 DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
2780#ifdef DHDTHREAD
2781 dhd_os_sdunlock(dhdp);
2782#endif /* DHDTHREAD */
2783 return -ENODEV;
2784 }
2785
2786#ifdef DHDTHREAD
2787 dhd_os_sdunlock(dhdp);
2788#endif /* DHDTHREAD */
2789
2790#ifdef READ_MACADDR
2791 dhd_read_macaddr(dhd);
2792#endif
2793
2794 /* Bus is ready, do any protocol initialization */
2795 if ((ret = dhd_prot_init(&dhd->pub)) < 0)
2796 return ret;
2797
2798#ifdef WRITE_MACADDR
2799 dhd_write_macaddr(dhd->pub.mac.octet);
2800#endif
2801
2802 return 0;
2803}
2804
2805int
2806dhd_preinit_ioctls(dhd_pub_t *dhd)
2807{
2808 int ret = 0;
2809 char eventmask[WL_EVENTING_MASK_LEN];
2810 char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
2811
2812 uint up = 0;
2813 uint power_mode = PM_FAST;
2814 uint32 dongle_align = DHD_SDALIGN;
2815 uint32 glom = 0;
2816 uint bcn_timeout = 4;
2817 uint retry_max = 3;
2818#if defined(ARP_OFFLOAD_SUPPORT)
2819 int arpoe = 1;
2820#endif
2821 int scan_assoc_time = 40;
2822 int scan_unassoc_time = 40;
2823 int scan_passive_time = 130;
2824 char buf[WLC_IOCTL_SMLEN];
2825 char *ptr;
2826 uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
2827#if defined(SOFTAP)
2828 uint dtim = 1;
2829#endif
2830#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211))
2831 uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */
2832#endif
2833
2834#if defined(AP) || defined(WLP2P)
2835 uint32 apsta = 1; /* Enable APSTA mode */
2836#endif /* defined(AP) || defined(WLP2P) */
2837#ifdef GET_CUSTOM_MAC_ENABLE
2838 struct ether_addr ea_addr;
2839#endif /* GET_CUSTOM_MAC_ENABLE */
2840
2841 DHD_TRACE(("Enter %s\n", __FUNCTION__));
2842 dhd->op_mode = 0;
2843#ifdef GET_CUSTOM_MAC_ENABLE
2844 ret = dhd_custom_get_mac_address(ea_addr.octet);
2845 if (!ret) {
2846 memset(buf, 0, sizeof(buf));
2847 bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
2848 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
2849 if (ret < 0) {
2850 DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
2851 return BCME_NOTUP;
2852 }
2853 } else {
2854#endif /* GET_CUSTOM_MAC_ENABLE */
2855 /* Get the default device MAC address directly from firmware */
2856 memset(buf, 0, sizeof(buf));
2857 bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf));
2858 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf),
2859 FALSE, 0)) < 0) {
2860 DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret));
2861 return BCME_NOTUP;
2862 }
2863 /* Update public MAC address after reading from Firmware */
2864 memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
2865#ifdef GET_CUSTOM_MAC_ENABLE
2866 }
2867#endif /* GET_CUSTOM_MAC_ENABLE */
2868
2869#ifdef SET_RANDOM_MAC_SOFTAP
2870 if (strstr(fw_path, "_apsta") != NULL) {
2871 uint rand_mac;
2872
2873 srandom32((uint)jiffies);
2874 rand_mac = random32();
2875 iovbuf[0] = 0x02; /* locally administered bit */
2876 iovbuf[1] = 0x1A;
2877 iovbuf[2] = 0x11;
2878 iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
2879 iovbuf[4] = (unsigned char)(rand_mac >> 8);
2880 iovbuf[5] = (unsigned char)(rand_mac >> 16);
2881
2882 bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
2883 ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
2884 if (ret < 0) {
2885 DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
2886 } else
2887 memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
2888 }
2889#endif /* SET_RANDOM_MAC_SOFTAP */
2890
2891 DHD_TRACE(("Firmware = %s\n", fw_path));
2892#if !defined(AP) && defined(WLP2P)
2893 /* Check if firmware with WFD support used */
2894 if (strstr(fw_path, "_p2p") != NULL) {
2895 bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
2896 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
2897 iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
2898 DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret));
2899 } else {
2900 dhd->op_mode |= WFD_MASK;
2901#if defined(ARP_OFFLOAD_SUPPORT)
2902 arpoe = 0;
2903#endif /* (ARP_OFFLOAD_SUPPORT) */
2904 dhd_pkt_filter_enable = FALSE;
2905 }
2906 }
2907#endif
2908
2909#if !defined(AP) && defined(WL_CFG80211)
2910 /* Check if firmware with HostAPD support used */
2911 if (strstr(fw_path, "_apsta") != NULL) {
2912 /* Turn off MPC in AP mode */
2913 bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
2914 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
2915 sizeof(iovbuf), TRUE, 0)) < 0) {
2916 DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret));
2917 } else {
2918 dhd->op_mode |= HOSTAPD_MASK;
2919#if defined(ARP_OFFLOAD_SUPPORT)
2920 arpoe = 0;
2921#endif /* (ARP_OFFLOAD_SUPPORT) */
2922 dhd_pkt_filter_enable = FALSE;
2923 }
2924 }
2925#endif
2926
2927 if ((dhd->op_mode != WFD_MASK) && (dhd->op_mode != HOSTAPD_MASK)) {
2928 /* STA only operation mode */
2929 dhd->op_mode |= STA_MASK;
2930 dhd_pkt_filter_enable = TRUE;
2931 }
2932
2933 DHD_ERROR(("Firmware up: fw_path=%s op_mode=%d, "
2934 "Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
2935 fw_path,
2936 dhd->op_mode,
2937 dhd->mac.octet[0], dhd->mac.octet[1], dhd->mac.octet[2],
2938 dhd->mac.octet[3], dhd->mac.octet[4], dhd->mac.octet[5]));
2939
2940 /* Set Country code */
2941 if (dhd->dhd_cspec.ccode[0] != 0) {
2942 bcm_mkiovar("country", (char *)&dhd->dhd_cspec,
2943 sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
2944 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
2945 DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
2946 }
2947
2948 /* Set Listen Interval */
2949 bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
2950 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0)
2951 DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret));
2952
2953 /* Set PowerSave mode */
2954 dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0);
2955
2956 /* Match Host and Dongle rx alignment */
2957 bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
2958 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
2959
2960 /* disable glom option per default */
2961 bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
2962 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
2963
2964 /* Setup timeout if Beacons are lost and roam is off to report link down */
2965 bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
2966 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
2967 /* Setup assoc_retry_max count to reconnect target AP in dongle */
2968 bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf));
2969 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
2970#if defined(AP) && !defined(WLP2P)
2971 /* Turn off MPC in AP mode */
2972 bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf));
2973 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
2974 bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf));
2975 dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
2976#endif /* defined(AP) && !defined(WLP2P) */
2977
2978#if defined(SOFTAP)
2979 if (ap_fw_loaded == TRUE) {
2980 dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0);
2981 }
2982#endif
2983
2984#if defined(KEEP_ALIVE)
2985 {
2986 /* Set Keep Alive : be sure to use FW with -keepalive */
2987 int res;
2988
2989#if defined(SOFTAP)
2990 if (ap_fw_loaded == FALSE)
2991#endif
2992 if ((res = dhd_keep_alive_onoff(dhd)) < 0)
2993 DHD_ERROR(("%s set keeplive failed %d\n",
2994 __FUNCTION__, res));
2995 }
2996#endif /* defined(KEEP_ALIVE) */
2997
2998 /* Read event_msgs mask */
2999 bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
3000 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) {
3001 DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret));
3002 goto done;
3003 }
3004 bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
3005
3006 /* Setup event_msgs */
3007 setbit(eventmask, WLC_E_SET_SSID);
3008 setbit(eventmask, WLC_E_PRUNE);
3009 setbit(eventmask, WLC_E_AUTH);
3010 setbit(eventmask, WLC_E_REASSOC);
3011 setbit(eventmask, WLC_E_REASSOC_IND);
3012 setbit(eventmask, WLC_E_DEAUTH);
3013 setbit(eventmask, WLC_E_DEAUTH_IND);
3014 setbit(eventmask, WLC_E_DISASSOC_IND);
3015 setbit(eventmask, WLC_E_DISASSOC);
3016 setbit(eventmask, WLC_E_JOIN);
3017 setbit(eventmask, WLC_E_ASSOC_IND);
3018 setbit(eventmask, WLC_E_PSK_SUP);
3019 setbit(eventmask, WLC_E_LINK);
3020 setbit(eventmask, WLC_E_NDIS_LINK);
3021 setbit(eventmask, WLC_E_MIC_ERROR);
3022 setbit(eventmask, WLC_E_PMKID_CACHE);
3023 setbit(eventmask, WLC_E_JOIN_START);
3024 setbit(eventmask, WLC_E_SCAN_COMPLETE);
3025#ifdef WLMEDIA_HTSF
3026 setbit(eventmask, WLC_E_HTSFSYNC);
3027#endif /* WLMEDIA_HTSF */
3028#ifdef PNO_SUPPORT
3029 setbit(eventmask, WLC_E_PFN_NET_FOUND);
3030#endif /* PNO_SUPPORT */
3031 /* enable dongle roaming event */
3032 setbit(eventmask, WLC_E_ROAM);
3033#ifdef WL_CFG80211
3034 setbit(eventmask, WLC_E_ESCAN_RESULT);
3035 if ((dhd->op_mode & WFD_MASK) == WFD_MASK) {
3036 setbit(eventmask, WLC_E_ACTION_FRAME_RX);
3037 setbit(eventmask, WLC_E_ACTION_FRAME_COMPLETE);
3038 setbit(eventmask, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE);
3039 setbit(eventmask, WLC_E_P2P_PROBREQ_MSG);
3040 setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE);
3041 }
3042#endif /* WL_CFG80211 */
3043
3044 /* Write updated Event mask */
3045 bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
3046 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
3047 DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret));
3048 goto done;
3049 }
3050
3051 dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
3052 sizeof(scan_assoc_time), TRUE, 0);
3053 dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
3054 sizeof(scan_unassoc_time), TRUE, 0);
3055 dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time,
3056 sizeof(scan_passive_time), TRUE, 0);
3057
3058#ifdef ARP_OFFLOAD_SUPPORT
3059 /* Set and enable ARP offload feature for STA only */
3060#if defined(SOFTAP)
3061 if (arpoe && !ap_fw_loaded) {
3062#else
3063 if (arpoe) {
3064#endif
3065 dhd_arp_offload_set(dhd, dhd_arp_mode);
3066 dhd_arp_offload_enable(dhd, arpoe);
3067 } else {
3068 dhd_arp_offload_set(dhd, 0);
3069 dhd_arp_offload_enable(dhd, FALSE);
3070 }
3071#endif /* ARP_OFFLOAD_SUPPORT */
3072
3073#ifdef PKT_FILTER_SUPPORT
3074 /* Setup defintions for pktfilter , enable in suspend */
3075 dhd->pktfilter_count = 4;
3076 /* Setup filter to allow only unicast */
3077 dhd->pktfilter[0] = "100 0 0 0 0x01 0x00";
3078 dhd->pktfilter[1] = NULL;
3079 dhd->pktfilter[2] = NULL;
3080 dhd->pktfilter[3] = NULL;
3081#if defined(SOFTAP)
3082 if (ap_fw_loaded) {
3083 int i;
3084 for (i = 0; i < dhd->pktfilter_count; i++) {
3085 dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
3086 0, dhd_master_mode);
3087 }
3088 }
3089#endif /* defined(SOFTAP) */
3090#endif /* PKT_FILTER_SUPPORT */
3091
3092 /* Force STA UP */
3093 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0) {
3094 DHD_ERROR(("%s Setting WL UP failed %d\n", __FUNCTION__, ret));
3095 goto done;
3096 }
3097
3098 /* query for 'ver' to get version info from firmware */
3099 memset(buf, 0, sizeof(buf));
3100 ptr = buf;
3101 bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf));
3102 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0)
3103 DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret));
3104 else {
3105 bcmstrtok(&ptr, "\n", 0);
3106 /* Print fw version info */
3107 DHD_ERROR(("Firmware version = %s\n", buf));
3108 DHD_BLOG(buf, strlen(buf) + 1);
3109 DHD_BLOG(dhd_version, strlen(dhd_version) + 1);
3110 }
3111
3112done:
3113 return ret;
3114}
3115
3116
3117int
3118dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
3119{
3120 char buf[strlen(name) + 1 + cmd_len];
3121 int len = sizeof(buf);
3122 wl_ioctl_t ioc;
3123 int ret;
3124
3125 len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len);
3126
3127 memset(&ioc, 0, sizeof(ioc));
3128
3129 ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR;
3130 ioc.buf = buf;
3131 ioc.len = len;
3132 ioc.set = TRUE;
3133
3134 ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len);
3135 if (!set && ret >= 0)
3136 memcpy(cmd_buf, buf, cmd_len);
3137
3138 return ret;
3139}
3140
3141#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
3142static struct net_device_ops dhd_ops_pri = {
3143 .ndo_open = dhd_open,
3144 .ndo_stop = dhd_stop,
3145 .ndo_get_stats = dhd_get_stats,
3146 .ndo_do_ioctl = dhd_ioctl_entry,
3147 .ndo_start_xmit = dhd_start_xmit,
3148 .ndo_set_mac_address = dhd_set_mac_address,
3149 .ndo_set_multicast_list = dhd_set_multicast_list,
3150};
3151
3152static struct net_device_ops dhd_ops_virt = {
3153 .ndo_get_stats = dhd_get_stats,
3154 .ndo_do_ioctl = dhd_ioctl_entry,
3155 .ndo_start_xmit = dhd_start_xmit,
3156 .ndo_set_mac_address = dhd_set_mac_address,
3157 .ndo_set_multicast_list = dhd_set_multicast_list,
3158};
3159#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */
3160
3161int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx)
3162{
3163 struct dhd_info *dhd = dhdp->info;
3164 struct net_device *dev = NULL;
3165
3166 ASSERT(dhd && dhd->iflist[ifidx]);
3167 dev = dhd->iflist[ifidx]->net;
3168 ASSERT(dev);
3169
3170 if (netif_running(dev)) {
3171 DHD_ERROR(("%s: Must be down to change its MTU", dev->name));
3172 return BCME_NOTDOWN;
3173 }
3174
3175#define DHD_MIN_MTU 1500
3176#define DHD_MAX_MTU 1752
3177
3178 if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) {
3179 DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu));
3180 return BCME_BADARG;
3181 }
3182
3183 dev->mtu = new_mtu;
3184 return 0;
3185}
3186
3187#ifdef ARP_OFFLOAD_SUPPORT
3188/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */
3189void
3190aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add)
3191{
3192 u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */
3193 int i;
3194 int ret;
3195
3196 bzero(ipv4_buf, sizeof(ipv4_buf));
3197
3198 /* display what we've got */
3199 ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf));
3200 DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__));
3201#ifdef AOE_DBG
3202 dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
3203#endif
3204 /* now we saved hoste_ip table, clr it in the dongle AOE */
3205 dhd_aoe_hostip_clr(dhd_pub);
3206
3207 if (ret) {
3208 DHD_ERROR(("%s failed\n", __FUNCTION__));
3209 return;
3210 }
3211
3212 for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
3213 if (add && (ipv4_buf[i] == 0)) {
3214 ipv4_buf[i] = ipa;
3215 add = FALSE; /* added ipa to local table */
3216 DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n",
3217 __FUNCTION__, i));
3218 } else if (ipv4_buf[i] == ipa) {
3219 ipv4_buf[i] = 0;
3220 DHD_ARPOE(("%s: removed IP:%x from temp table %d\n",
3221 __FUNCTION__, ipa, i));
3222 }
3223
3224 if (ipv4_buf[i] != 0) {
3225 /* add back host_ip entries from our local cache */
3226 dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i]);
3227 DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n",
3228 __FUNCTION__, ipv4_buf[i], i));
3229 }
3230 }
3231#ifdef AOE_DBG
3232 /* see the resulting hostip table */
3233 dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf));
3234 DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__));
3235 dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */
3236#endif
3237}
3238
3239static int dhd_device_event(struct notifier_block *this,
3240 unsigned long event,
3241 void *ptr)
3242{
3243 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
3244
3245 dhd_info_t *dhd;
3246 dhd_pub_t *dhd_pub;
3247
3248 if (!ifa)
3249 return NOTIFY_DONE;
3250
3251 dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev);
3252 dhd_pub = &dhd->pub;
3253
3254#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
3255 if (ifa->ifa_dev->dev->netdev_ops == &dhd_ops_pri) {
3256#else
3257 if (ifa->ifa_dev->dev) {
3258#endif
3259 switch (event) {
3260 case NETDEV_UP:
3261 DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n",
3262 __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
3263
3264 /* firmware not downloaded, do nothing */
3265 if (dhd->pub.busstate == DHD_BUS_DOWN) {
3266 DHD_ERROR(("%s: bus is down, exit\n", __FUNCTION__));
3267 break;
3268 }
3269
3270#ifdef AOE_IP_ALIAS_SUPPORT
3271 if (ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a) {
3272 DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n",
3273 __FUNCTION__));
3274 aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE);
3275 }
3276 else
3277 aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE);
3278#endif
3279 break;
3280
3281 case NETDEV_DOWN:
3282 DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n",
3283 __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
3284
3285#ifdef AOE_IP_ALIAS_SUPPORT
3286 if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) {
3287 DHD_ARPOE(("%s: primary interface is down, AOE clr all\n",
3288 __FUNCTION__));
3289 dhd_aoe_hostip_clr(&dhd->pub);
3290 dhd_aoe_arp_clr(&dhd->pub);
3291 } else
3292 aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE);
3293#else
3294 dhd_aoe_hostip_clr(&dhd->pub);
3295 dhd_aoe_arp_clr(&dhd->pub);
3296#endif
3297 break;
3298
3299 default:
3300 DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n",
3301 __func__, ifa->ifa_label, event));
3302 break;
3303 }
3304 }
3305 return NOTIFY_DONE;
3306}
3307#endif /* ARP_OFFLOAD_SUPPORT */
3308
3309int
3310dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
3311{
3312 dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
3313 struct net_device *net = NULL;
3314 int err = 0;
3315 uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 };
3316
3317 DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
3318
3319 ASSERT(dhd && dhd->iflist[ifidx]);
3320
3321 net = dhd->iflist[ifidx]->net;
3322 ASSERT(net);
3323
3324#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
3325 ASSERT(!net->open);
3326 net->get_stats = dhd_get_stats;
3327 net->do_ioctl = dhd_ioctl_entry;
3328 net->hard_start_xmit = dhd_start_xmit;
3329 net->set_mac_address = dhd_set_mac_address;
3330 net->set_multicast_list = dhd_set_multicast_list;
3331 net->open = net->stop = NULL;
3332#else
3333 ASSERT(!net->netdev_ops);
3334 net->netdev_ops = &dhd_ops_virt;
3335#endif
3336
3337 /* Ok, link into the network layer... */
3338 if (ifidx == 0) {
3339 /*
3340 * device functions for the primary interface only
3341 */
3342#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
3343 net->open = dhd_open;
3344 net->stop = dhd_stop;
3345#else
3346 net->netdev_ops = &dhd_ops_pri;
3347#endif
3348 } else {
3349 /*
3350 * We have to use the primary MAC for virtual interfaces
3351 */
3352 memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN);
3353 /*
3354 * Android sets the locally administered bit to indicate that this is a
3355 * portable hotspot. This will not work in simultaneous AP/STA mode,
3356 * nor with P2P. Need to set the Donlge's MAC address, and then use that.
3357 */
3358 if (ifidx > 0) {
3359 DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n",
3360 __func__, net->name));
3361 temp_addr[0] |= 0x02;
3362 }
3363 }
3364
3365 net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen;
3366#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
3367 net->ethtool_ops = &dhd_ethtool_ops;
3368#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
3369
3370#if defined(CONFIG_BCMDHD_WEXT)
3371#if WIRELESS_EXT < 19
3372 net->get_wireless_stats = dhd_get_wireless_stats;
3373#endif /* WIRELESS_EXT < 19 */
3374#if WIRELESS_EXT > 12
3375 net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
3376#endif /* WIRELESS_EXT > 12 */
3377#endif /* defined(CONFIG_BCMDHD_WEXT) */
3378
3379 dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net);
3380
3381 memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
3382
3383 if ((err = register_netdev(net)) != 0) {
3384 DHD_ERROR(("couldn't register the net device, err %d\n", err));
3385 goto fail;
3386 }
3387 printf("Broadcom Dongle Host Driver: register interface [%s]"
3388 " MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
3389 net->name,
3390 net->dev_addr[0], net->dev_addr[1], net->dev_addr[2],
3391 net->dev_addr[3], net->dev_addr[4], net->dev_addr[5]);
3392
3393#if defined(SOFTAP) && defined(CONFIG_BCMDHD_WEXT) && !defined(WL_CFG80211)
3394 wl_iw_iscan_set_scan_broadcast_prep(net, 1);
3395#endif
3396
3397
3398#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3399 if (ifidx == 0) {
3400 up(&dhd_registration_sem);
3401 }
3402#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
3403 return 0;
3404
3405fail:
3406#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
3407 net->open = NULL;
3408#else
3409 net->netdev_ops = NULL;
3410#endif
3411 return err;
3412}
3413
3414void
3415dhd_bus_detach(dhd_pub_t *dhdp)
3416{
3417 dhd_info_t *dhd;
3418
3419 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3420
3421 if (dhdp) {
3422 dhd = (dhd_info_t *)dhdp->info;
3423 if (dhd) {
3424
3425 /*
3426 * In case of Android cfg80211 driver, the bus is down in dhd_stop,
3427 * calling stop again will cuase SD read/write errors.
3428 */
3429 if (dhd->pub.busstate != DHD_BUS_DOWN) {
3430 /* Stop the protocol module */
3431 dhd_prot_stop(&dhd->pub);
3432
3433 /* Stop the bus module */
3434 dhd_bus_stop(dhd->pub.bus, TRUE);
3435 }
3436
3437#if defined(OOB_INTR_ONLY)
3438 bcmsdh_unregister_oob_intr();
3439#endif /* defined(OOB_INTR_ONLY) */
3440 }
3441 }
3442}
3443
3444
3445void dhd_detach(dhd_pub_t *dhdp)
3446{
3447 dhd_info_t *dhd;
3448 unsigned long flags;
3449 int timer_valid = FALSE;
3450
3451 if (!dhdp)
3452 return;
3453
3454 dhd = (dhd_info_t *)dhdp->info;
3455 if (!dhd)
3456 return;
3457
3458 DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state));
3459
3460 if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) {
3461 /* Give sufficient time for threads to start running in case
3462 * dhd_attach() has failed
3463 */
3464 osl_delay(1000*100);
3465 }
3466
3467#ifdef ARP_OFFLOAD_SUPPORT
3468 unregister_inetaddr_notifier(&dhd_notifier);
3469#endif /* ARP_OFFLOAD_SUPPORT */
3470
3471#if defined(CONFIG_HAS_EARLYSUSPEND)
3472 if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) {
3473 if (dhd->early_suspend.suspend)
3474 unregister_early_suspend(&dhd->early_suspend);
3475 }
3476#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
3477
3478#if defined(CONFIG_BCMDHD_WEXT)
3479 if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) {
3480 /* Detatch and unlink in the iw */
3481 wl_iw_detach();
3482 }
3483#endif /* defined(CONFIG_BCMDHD_WEXT) */
3484
3485 if (&dhd->thr_sysioc_ctl.thr_pid >= 0) {
3486 PROC_STOP(&dhd->thr_sysioc_ctl);
3487 }
3488
3489 /* delete all interfaces, start with virtual */
3490 if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) {
3491 int i = 1;
3492 dhd_if_t *ifp;
3493
3494 /* Cleanup virtual interfaces */
3495 for (i = 1; i < DHD_MAX_IFS; i++)
3496 if (dhd->iflist[i]) {
3497 dhd->iflist[i]->state = DHD_IF_DEL;
3498 dhd->iflist[i]->idx = i;
3499 dhd_op_if(dhd->iflist[i]);
3500 }
3501
3502 /* delete primary interface 0 */
3503 ifp = dhd->iflist[0];
3504 ASSERT(ifp);
3505
3506#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31))
3507 if (ifp->net->open)
3508#else
3509 if (ifp->net->netdev_ops == &dhd_ops_pri)
3510#endif
3511 {
3512 if (ifp->net) {
3513 unregister_netdev(ifp->net);
3514 free_netdev(ifp->net);
3515 ifp->net = NULL;
3516 }
3517 MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
3518 dhd->iflist[0] = NULL;
3519 }
3520 }
3521
3522 /* Clear the watchdog timer */
3523 flags = dhd_os_spin_lock(&dhd->pub);
3524 timer_valid = dhd->wd_timer_valid;
3525 dhd->wd_timer_valid = FALSE;
3526 dhd_os_spin_unlock(&dhd->pub, flags);
3527 if (timer_valid)
3528 del_timer_sync(&dhd->timer);
3529
3530 if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) {
3531#ifdef DHDTHREAD
3532 if (dhd->thr_wdt_ctl.thr_pid >= 0) {
3533 PROC_STOP(&dhd->thr_wdt_ctl);
3534 }
3535
3536 if (dhd->thr_dpc_ctl.thr_pid >= 0) {
3537 PROC_STOP(&dhd->thr_dpc_ctl);
3538 }
3539 else
3540#endif /* DHDTHREAD */
3541 tasklet_kill(&dhd->tasklet);
3542 }
3543 if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) {
3544 dhd_bus_detach(dhdp);
3545
3546 if (dhdp->prot)
3547 dhd_prot_detach(dhdp);
3548 }
3549
3550#ifdef WL_CFG80211
3551 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) {
3552 wl_cfg80211_detach();
3553 dhd_monitor_uninit();
3554 }
3555#endif
3556
3557#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
3558 unregister_pm_notifier(&dhd_sleep_pm_notifier);
3559#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
3560
3561 if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) {
3562#ifdef CONFIG_HAS_WAKELOCK
3563 wake_lock_destroy(&dhd->wl_wifi);
3564 wake_lock_destroy(&dhd->wl_rxwake);
3565#endif
3566 }
3567}
3568
3569
3570void
3571dhd_free(dhd_pub_t *dhdp)
3572{
3573 dhd_info_t *dhd;
3574 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3575
3576 if (dhdp) {
3577 dhd = (dhd_info_t *)dhdp->info;
3578 if (dhd)
3579 MFREE(dhd->pub.osh, dhd, sizeof(*dhd));
3580 }
3581}
3582
3583static void __exit
3584dhd_module_cleanup(void)
3585{
3586 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3587
3588 dhd_bus_unregister();
3589
3590#if defined(CONFIG_WIFI_CONTROL_FUNC)
3591 wl_android_wifictrl_func_del();
3592#endif /* CONFIG_WIFI_CONTROL_FUNC */
3593 wl_android_exit();
3594
3595 /* Call customer gpio to turn off power with WL_REG_ON signal */
3596 dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
3597}
3598
3599
3600static int __init
3601dhd_module_init(void)
3602{
3603 int error = 0;
3604
3605 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3606
3607 wl_android_init();
3608
3609#ifdef DHDTHREAD
3610 /* Sanity check on the module parameters */
3611 do {
3612 /* Both watchdog and DPC as tasklets are ok */
3613 if ((dhd_watchdog_prio < 0) && (dhd_dpc_prio < 0))
3614 break;
3615
3616 /* If both watchdog and DPC are threads, TX must be deferred */
3617 if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0) && dhd_deferred_tx)
3618 break;
3619
3620 DHD_ERROR(("Invalid module parameters.\n"));
3621 return -EINVAL;
3622 } while (0);
3623#endif /* DHDTHREAD */
3624
3625 /* Call customer gpio to turn on power with WL_REG_ON signal */
3626 dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON);
3627
3628#if defined(CONFIG_WIFI_CONTROL_FUNC)
3629 if (wl_android_wifictrl_func_add() < 0)
3630 goto fail_1;
3631#endif
3632
3633#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3634 sema_init(&dhd_registration_sem, 0);
3635#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
3636 error = dhd_bus_register();
3637
3638 if (!error)
3639 printf("\n%s\n", dhd_version);
3640 else {
3641 DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__));
3642 goto fail_1;
3643 }
3644
3645#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3646 /*
3647 * Wait till MMC sdio_register_driver callback called and made driver attach.
3648 * It's needed to make sync up exit from dhd insmod and
3649 * Kernel MMC sdio device callback registration
3650 */
3651 if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) {
3652 error = -EINVAL;
3653 DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__));
3654 goto fail_2;
3655 }
3656#endif
3657#if defined(WL_CFG80211)
3658 error = wl_android_post_init();
3659#endif
3660
3661 return error;
3662#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1
3663fail_2:
3664 dhd_bus_unregister();
3665#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
3666fail_1:
3667#if defined(CONFIG_WIFI_CONTROL_FUNC)
3668 wl_android_wifictrl_func_del();
3669#endif
3670
3671 /* Call customer gpio to turn off power with WL_REG_ON signal */
3672 dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
3673
3674 return error;
3675}
3676
3677late_initcall(dhd_module_init);
3678module_exit(dhd_module_cleanup);
3679
3680/*
3681 * OS specific functions required to implement DHD driver in OS independent way
3682 */
3683int
3684dhd_os_proto_block(dhd_pub_t *pub)
3685{
3686 dhd_info_t * dhd = (dhd_info_t *)(pub->info);
3687
3688 if (dhd) {
3689 down(&dhd->proto_sem);
3690 return 1;
3691 }
3692
3693 return 0;
3694}
3695
3696int
3697dhd_os_proto_unblock(dhd_pub_t *pub)
3698{
3699 dhd_info_t * dhd = (dhd_info_t *)(pub->info);
3700
3701 if (dhd) {
3702 up(&dhd->proto_sem);
3703 return 1;
3704 }
3705
3706 return 0;
3707}
3708
3709unsigned int
3710dhd_os_get_ioctl_resp_timeout(void)
3711{
3712 return ((unsigned int)dhd_ioctl_timeout_msec);
3713}
3714
3715void
3716dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec)
3717{
3718 dhd_ioctl_timeout_msec = (int)timeout_msec;
3719}
3720
3721int
3722dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
3723{
3724 dhd_info_t * dhd = (dhd_info_t *)(pub->info);
3725 DECLARE_WAITQUEUE(wait, current);
3726 int timeout = dhd_ioctl_timeout_msec;
3727
3728 /* Convert timeout in millsecond to jiffies */
3729#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3730 timeout = msecs_to_jiffies(timeout);
3731#else
3732 timeout = timeout * HZ / 1000;
3733#endif
3734
3735 /* Wait until control frame is available */
3736 add_wait_queue(&dhd->ioctl_resp_wait, &wait);
3737 set_current_state(TASK_INTERRUPTIBLE);
3738
3739 /* Memory barrier to support multi-processing
3740 * As the variable "condition", which points to dhd->rxlen (dhd_bus_rxctl[dhd_sdio.c])
3741 * Can be changed by another processor.
3742 */
3743 smp_mb();
3744 while (!(*condition) && (!signal_pending(current) && timeout)) {
3745 timeout = schedule_timeout(timeout);
3746 smp_mb();
3747 }
3748
3749 if (signal_pending(current))
3750 *pending = TRUE;
3751
3752 set_current_state(TASK_RUNNING);
3753 remove_wait_queue(&dhd->ioctl_resp_wait, &wait);
3754
3755 return timeout;
3756}
3757
3758int
3759dhd_os_ioctl_resp_wake(dhd_pub_t *pub)
3760{
3761 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
3762
3763 if (waitqueue_active(&dhd->ioctl_resp_wait)) {
3764 wake_up_interruptible(&dhd->ioctl_resp_wait);
3765 }
3766
3767 return 0;
3768}
3769
3770void
3771dhd_os_wd_timer(void *bus, uint wdtick)
3772{
3773 dhd_pub_t *pub = bus;
3774 dhd_info_t *dhd = (dhd_info_t *)pub->info;
3775 unsigned long flags;
3776
3777 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3778
3779 flags = dhd_os_spin_lock(pub);
3780
3781 /* don't start the wd until fw is loaded */
3782 if (pub->busstate == DHD_BUS_DOWN) {
3783 dhd_os_spin_unlock(pub, flags);
3784 return;
3785 }
3786
3787 /* Totally stop the timer */
3788 if (!wdtick && dhd->wd_timer_valid == TRUE) {
3789 dhd->wd_timer_valid = FALSE;
3790 dhd_os_spin_unlock(pub, flags);
3791#ifdef DHDTHREAD
3792 del_timer_sync(&dhd->timer);
3793#else
3794 del_timer(&dhd->timer);
3795#endif /* DHDTHREAD */
3796 return;
3797 }
3798
3799 if (wdtick) {
3800 dhd_watchdog_ms = (uint)wdtick;
3801 /* Re arm the timer, at last watchdog period */
3802 mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
3803 dhd->wd_timer_valid = TRUE;
3804 }
3805 dhd_os_spin_unlock(pub, flags);
3806}
3807
3808void *
3809dhd_os_open_image(char *filename)
3810{
3811 struct file *fp;
3812
3813 fp = filp_open(filename, O_RDONLY, 0);
3814 /*
3815 * 2.6.11 (FC4) supports filp_open() but later revs don't?
3816 * Alternative:
3817 * fp = open_namei(AT_FDCWD, filename, O_RD, 0);
3818 * ???
3819 */
3820 if (IS_ERR(fp))
3821 fp = NULL;
3822
3823 return fp;
3824}
3825
3826int
3827dhd_os_get_image_block(char *buf, int len, void *image)
3828{
3829 struct file *fp = (struct file *)image;
3830 int rdlen;
3831
3832 if (!image)
3833 return 0;
3834
3835 rdlen = kernel_read(fp, fp->f_pos, buf, len);
3836 if (rdlen > 0)
3837 fp->f_pos += rdlen;
3838
3839 return rdlen;
3840}
3841
3842void
3843dhd_os_close_image(void *image)
3844{
3845 if (image)
3846 filp_close((struct file *)image, NULL);
3847}
3848
3849
3850void
3851dhd_os_sdlock(dhd_pub_t *pub)
3852{
3853 dhd_info_t *dhd;
3854
3855 dhd = (dhd_info_t *)(pub->info);
3856
3857#ifdef DHDTHREAD
3858 if (dhd->threads_only)
3859 down(&dhd->sdsem);
3860 else
3861#endif /* DHDTHREAD */
3862 spin_lock_bh(&dhd->sdlock);
3863}
3864
3865void
3866dhd_os_sdunlock(dhd_pub_t *pub)
3867{
3868 dhd_info_t *dhd;
3869
3870 dhd = (dhd_info_t *)(pub->info);
3871
3872#ifdef DHDTHREAD
3873 if (dhd->threads_only)
3874 up(&dhd->sdsem);
3875 else
3876#endif /* DHDTHREAD */
3877 spin_unlock_bh(&dhd->sdlock);
3878}
3879
3880void
3881dhd_os_sdlock_txq(dhd_pub_t *pub)
3882{
3883 dhd_info_t *dhd;
3884
3885 dhd = (dhd_info_t *)(pub->info);
3886 spin_lock_bh(&dhd->txqlock);
3887}
3888
3889void
3890dhd_os_sdunlock_txq(dhd_pub_t *pub)
3891{
3892 dhd_info_t *dhd;
3893
3894 dhd = (dhd_info_t *)(pub->info);
3895 spin_unlock_bh(&dhd->txqlock);
3896}
3897
3898void
3899dhd_os_sdlock_rxq(dhd_pub_t *pub)
3900{
3901}
3902
3903void
3904dhd_os_sdunlock_rxq(dhd_pub_t *pub)
3905{
3906}
3907
3908void
3909dhd_os_sdtxlock(dhd_pub_t *pub)
3910{
3911 dhd_os_sdlock(pub);
3912}
3913
3914void
3915dhd_os_sdtxunlock(dhd_pub_t *pub)
3916{
3917 dhd_os_sdunlock(pub);
3918}
3919
3920#if defined(DHD_USE_STATIC_BUF)
3921uint8* dhd_os_prealloc(void *osh, int section, uint size)
3922{
3923 return (uint8*)wl_android_prealloc(section, size);
3924}
3925
3926void dhd_os_prefree(void *osh, void *addr, uint size)
3927{
3928}
3929#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
3930
3931#if defined(CONFIG_BCMDHD_WEXT)
3932struct iw_statistics *
3933dhd_get_wireless_stats(struct net_device *dev)
3934{
3935 int res = 0;
3936 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3937
3938 if (!dhd->pub.up) {
3939 return NULL;
3940 }
3941
3942 res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats);
3943
3944 if (res == 0)
3945 return &dhd->iw.wstats;
3946 else
3947 return NULL;
3948}
3949#endif /* defined(CONFIG_BCMDHD_WEXT) */
3950
3951static int
3952dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
3953 wl_event_msg_t *event, void **data)
3954{
3955 int bcmerror = 0;
3956 ASSERT(dhd != NULL);
3957
3958 bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data);
3959 if (bcmerror != BCME_OK)
3960 return (bcmerror);
3961
3962#if defined(CONFIG_BCMDHD_WEXT)
3963 if (event->bsscfgidx == 0) {
3964 /*
3965 * Wireless ext is on primary interface only
3966 */
3967
3968 ASSERT(dhd->iflist[*ifidx] != NULL);
3969 ASSERT(dhd->iflist[*ifidx]->net != NULL);
3970
3971 if (dhd->iflist[*ifidx]->net) {
3972 wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
3973 }
3974 }
3975#endif /* defined(CONFIG_BCMDHD_WEXT) */
3976
3977#ifdef WL_CFG80211
3978
3979 if ((wl_cfg80211_is_progress_ifchange() ||
3980 wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) {
3981 /*
3982 * If IF_ADD/CHANGE operation is going on,
3983 * discard any event received on the virtual I/F
3984 */
3985 return (BCME_OK);
3986 }
3987
3988 ASSERT(dhd->iflist[*ifidx] != NULL);
3989 ASSERT(dhd->iflist[*ifidx]->net != NULL);
3990 if (dhd->iflist[*ifidx]->net) {
3991 wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data);
3992 }
3993#endif /* defined(WL_CFG80211) */
3994
3995 return (bcmerror);
3996}
3997
3998/* send up locally generated event */
3999void
4000dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
4001{
4002 switch (ntoh32(event->event_type)) {
4003 /* Send up locally generated AMP HCI Events */
4004 case WLC_E_BTA_HCI_EVENT: {
4005 struct sk_buff *p, *skb;
4006 bcm_event_t *msg;
4007 wl_event_msg_t *p_bcm_event;
4008 char *ptr;
4009 uint32 len;
4010 uint32 pktlen;
4011 dhd_if_t *ifp;
4012 dhd_info_t *dhd;
4013 uchar *eth;
4014 int ifidx;
4015
4016 len = ntoh32(event->datalen);
4017 pktlen = sizeof(bcm_event_t) + len + 2;
4018 dhd = dhdp->info;
4019 ifidx = dhd_ifname2idx(dhd, event->ifname);
4020
4021 if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) {
4022 ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32)));
4023
4024 msg = (bcm_event_t *) PKTDATA(dhdp->osh, p);
4025
4026 bcopy(&dhdp->mac, &msg->eth.ether_dhost, ETHER_ADDR_LEN);
4027 bcopy(&dhdp->mac, &msg->eth.ether_shost, ETHER_ADDR_LEN);
4028 ETHER_TOGGLE_LOCALADDR(&msg->eth.ether_shost);
4029
4030 msg->eth.ether_type = hton16(ETHER_TYPE_BRCM);
4031
4032 /* BCM Vendor specific header... */
4033 msg->bcm_hdr.subtype = hton16(BCMILCP_SUBTYPE_VENDOR_LONG);
4034 msg->bcm_hdr.version = BCMILCP_BCM_SUBTYPEHDR_VERSION;
4035 bcopy(BRCM_OUI, &msg->bcm_hdr.oui[0], DOT11_OUI_LEN);
4036
4037 /* vendor spec header length + pvt data length (private indication
4038 * hdr + actual message itself)
4039 */
4040 msg->bcm_hdr.length = hton16(BCMILCP_BCM_SUBTYPEHDR_MINLENGTH +
4041 BCM_MSG_LEN + sizeof(wl_event_msg_t) + (uint16)len);
4042 msg->bcm_hdr.usr_subtype = hton16(BCMILCP_BCM_SUBTYPE_EVENT);
4043
4044 PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2));
4045
4046 /* copy wl_event_msg_t into sk_buf */
4047
4048 /* pointer to wl_event_msg_t in sk_buf */
4049 p_bcm_event = &msg->event;
4050 bcopy(event, p_bcm_event, sizeof(wl_event_msg_t));
4051
4052 /* copy hci event into sk_buf */
4053 bcopy(data, (p_bcm_event + 1), len);
4054
4055 msg->bcm_hdr.length = hton16(sizeof(wl_event_msg_t) +
4056 ntoh16(msg->bcm_hdr.length));
4057 PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2));
4058
4059 ptr = (char *)(msg + 1);
4060 /* Last 2 bytes of the message are 0x00 0x00 to signal that there
4061 * are no ethertypes which are following this
4062 */
4063 ptr[len+0] = 0x00;
4064 ptr[len+1] = 0x00;
4065
4066 skb = PKTTONATIVE(dhdp->osh, p);
4067 eth = skb->data;
4068 len = skb->len;
4069
4070 ifp = dhd->iflist[ifidx];
4071 if (ifp == NULL)
4072 ifp = dhd->iflist[0];
4073
4074 ASSERT(ifp);
4075 skb->dev = ifp->net;
4076 skb->protocol = eth_type_trans(skb, skb->dev);
4077
4078 skb->data = eth;
4079 skb->len = len;
4080
4081 /* Strip header, count, deliver upward */
4082 skb_pull(skb, ETH_HLEN);
4083
4084 /* Send the packet */
4085 if (in_interrupt()) {
4086 netif_rx(skb);
4087 } else {
4088 netif_rx_ni(skb);
4089 }
4090 }
4091 else {
4092 /* Could not allocate a sk_buf */
4093 DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__));
4094 }
4095 break;
4096 } /* case WLC_E_BTA_HCI_EVENT */
4097
4098 default:
4099 break;
4100 }
4101}
4102
4103void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
4104{
4105#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
4106 struct dhd_info *dhdinfo = dhd->info;
4107 dhd_os_sdunlock(dhd);
4108 wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 2);
4109 dhd_os_sdlock(dhd);
4110#endif
4111 return;
4112}
4113
4114void dhd_wait_event_wakeup(dhd_pub_t *dhd)
4115{
4116#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
4117 struct dhd_info *dhdinfo = dhd->info;
4118 if (waitqueue_active(&dhdinfo->ctrl_wait))
4119 wake_up_interruptible(&dhdinfo->ctrl_wait);
4120#endif
4121 return;
4122}
4123
4124int
4125dhd_dev_reset(struct net_device *dev, uint8 flag)
4126{
4127 int ret;
4128
4129 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4130
4131 ret = dhd_bus_devreset(&dhd->pub, flag);
4132 if (ret) {
4133 DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret));
4134 return ret;
4135 }
4136
4137 return ret;
4138}
4139
4140int net_os_set_suspend_disable(struct net_device *dev, int val)
4141{
4142 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4143 int ret = 0;
4144
4145 if (dhd) {
4146 ret = dhd->pub.suspend_disable_flag;
4147 dhd->pub.suspend_disable_flag = val;
4148 }
4149 return ret;
4150}
4151
4152int net_os_set_suspend(struct net_device *dev, int val)
4153{
4154 int ret = 0;
4155#if defined(CONFIG_HAS_EARLYSUSPEND)
4156 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4157
4158 if (dhd) {
4159 ret = dhd_set_suspend(val, &dhd->pub);
4160 }
4161#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
4162 return ret;
4163}
4164
4165int net_os_set_dtim_skip(struct net_device *dev, int val)
4166{
4167 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4168
4169 if (dhd)
4170 dhd->pub.dtim_skip = val;
4171
4172 return 0;
4173}
4174
4175int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
4176{
4177 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4178 char *filterp = NULL;
4179 int ret = 0;
4180
4181 if (!dhd || (num == DHD_UNICAST_FILTER_NUM))
4182 return ret;
4183 if (num >= dhd->pub.pktfilter_count)
4184 return -EINVAL;
4185 if (add_remove) {
4186 switch (num) {
4187 case DHD_BROADCAST_FILTER_NUM:
4188 filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
4189 break;
4190 case DHD_MULTICAST4_FILTER_NUM:
4191 filterp = "102 0 0 0 0xFFFFFF 0x01005E";
4192 break;
4193 case DHD_MULTICAST6_FILTER_NUM:
4194 filterp = "103 0 0 0 0xFFFF 0x3333";
4195 break;
4196 default:
4197 return -EINVAL;
4198 }
4199 }
4200 dhd->pub.pktfilter[num] = filterp;
4201 return ret;
4202}
4203
4204int net_os_set_packet_filter(struct net_device *dev, int val)
4205{
4206 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4207 int ret = 0;
4208
4209 /* Packet filtering is set only if we still in early-suspend and
4210 * we need either to turn it ON or turn it OFF
4211 * We can always turn it OFF in case of early-suspend, but we turn it
4212 * back ON only if suspend_disable_flag was not set
4213 */
4214 if (dhd && dhd->pub.up) {
4215 if (dhd->pub.in_suspend) {
4216 if (!val || (val && !dhd->pub.suspend_disable_flag))
4217 dhd_set_packet_filter(val, &dhd->pub);
4218 }
4219 }
4220 return ret;
4221}
4222
4223
4224void
4225dhd_dev_init_ioctl(struct net_device *dev)
4226{
4227 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4228
4229 dhd_preinit_ioctls(&dhd->pub);
4230}
4231
4232#ifdef PNO_SUPPORT
4233/* Linux wrapper to call common dhd_pno_clean */
4234int
4235dhd_dev_pno_reset(struct net_device *dev)
4236{
4237 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4238
4239 return (dhd_pno_clean(&dhd->pub));
4240}
4241
4242
4243/* Linux wrapper to call common dhd_pno_enable */
4244int
4245dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled)
4246{
4247 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4248
4249 return (dhd_pno_enable(&dhd->pub, pfn_enabled));
4250}
4251
4252
4253/* Linux wrapper to call common dhd_pno_set */
4254int
4255dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid,
4256 ushort scan_fr, int pno_repeat, int pno_freq_expo_max)
4257{
4258 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4259
4260 return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max));
4261}
4262
4263/* Linux wrapper to get pno status */
4264int
4265dhd_dev_get_pno_status(struct net_device *dev)
4266{
4267 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4268
4269 return (dhd_pno_get_status(&dhd->pub));
4270}
4271
4272#endif /* PNO_SUPPORT */
4273
4274int net_os_send_hang_message(struct net_device *dev)
4275{
4276 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4277 int ret = 0;
4278
4279 if (dhd) {
4280 if (!dhd->pub.hang_was_sent) {
4281 dhd->pub.hang_was_sent = 1;
4282#if defined(CONFIG_BCMDHD_WEXT)
4283 ret = wl_iw_send_priv_event(dev, "HANG");
4284#endif
4285#if defined(WL_CFG80211)
4286 ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED);
4287#endif
4288 }
4289 }
4290 return ret;
4291}
4292
4293void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec)
4294{
4295 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4296
4297 if (dhd && dhd->pub.up)
4298 memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
4299}
4300
4301
4302void dhd_net_if_lock(struct net_device *dev)
4303{
4304 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4305 dhd_net_if_lock_local(dhd);
4306}
4307
4308void dhd_net_if_unlock(struct net_device *dev)
4309{
4310 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4311 dhd_net_if_unlock_local(dhd);
4312}
4313
4314static void dhd_net_if_lock_local(dhd_info_t *dhd)
4315{
4316#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
4317 if (dhd)
4318 mutex_lock(&dhd->dhd_net_if_mutex);
4319#endif
4320}
4321
4322static void dhd_net_if_unlock_local(dhd_info_t *dhd)
4323{
4324#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
4325 if (dhd)
4326 mutex_unlock(&dhd->dhd_net_if_mutex);
4327#endif
4328}
4329
4330unsigned long dhd_os_spin_lock(dhd_pub_t *pub)
4331{
4332 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
4333 unsigned long flags = 0;
4334
4335 if (dhd)
4336 spin_lock_irqsave(&dhd->dhd_lock, flags);
4337
4338 return flags;
4339}
4340
4341void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags)
4342{
4343 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
4344
4345 if (dhd)
4346 spin_unlock_irqrestore(&dhd->dhd_lock, flags);
4347}
4348
4349static int
4350dhd_get_pend_8021x_cnt(dhd_info_t *dhd)
4351{
4352 return (atomic_read(&dhd->pend_8021x_cnt));
4353}
4354
4355#define MAX_WAIT_FOR_8021X_TX 10
4356
4357int
4358dhd_wait_pend8021x(struct net_device *dev)
4359{
4360 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4361 int timeout = 10 * HZ / 1000;
4362 int ntimes = MAX_WAIT_FOR_8021X_TX;
4363 int pend = dhd_get_pend_8021x_cnt(dhd);
4364
4365 while (ntimes && pend) {
4366 if (pend) {
4367 set_current_state(TASK_INTERRUPTIBLE);
4368 schedule_timeout(timeout);
4369 set_current_state(TASK_RUNNING);
4370 ntimes--;
4371 }
4372 pend = dhd_get_pend_8021x_cnt(dhd);
4373 }
4374 return pend;
4375}
4376
4377#ifdef DHD_DEBUG
4378int
4379write_to_file(dhd_pub_t *dhd, uint8 *buf, int size)
4380{
4381 int ret = 0;
4382 struct file *fp;
4383 mm_segment_t old_fs;
4384 loff_t pos = 0;
4385
4386 /* change to KERNEL_DS address limit */
4387 old_fs = get_fs();
4388 set_fs(KERNEL_DS);
4389
4390 /* open file to write */
4391 fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640);
4392 if (!fp) {
4393 printf("%s: open file error\n", __FUNCTION__);
4394 ret = -1;
4395 goto exit;
4396 }
4397
4398 /* Write buf to file */
4399 fp->f_op->write(fp, buf, size, &pos);
4400
4401exit:
4402 /* free buf before return */
4403 MFREE(dhd->osh, buf, size);
4404 /* close file before return */
4405 if (fp)
4406 filp_close(fp, current->files);
4407 /* restore previous address limit */
4408 set_fs(old_fs);
4409
4410 return ret;
4411}
4412#endif /* DHD_DEBUG */
4413
4414int dhd_os_wake_lock_timeout(dhd_pub_t *pub)
4415{
4416 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
4417 unsigned long flags;
4418 int ret = 0;
4419
4420 if (dhd) {
4421 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
4422 ret = dhd->wakelock_timeout_enable;
4423#ifdef CONFIG_HAS_WAKELOCK
4424 if (dhd->wakelock_timeout_enable)
4425 wake_lock_timeout(&dhd->wl_rxwake,
4426 dhd->wakelock_timeout_enable * HZ);
4427#endif
4428 dhd->wakelock_timeout_enable = 0;
4429 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
4430 }
4431 return ret;
4432}
4433
4434int net_os_wake_lock_timeout(struct net_device *dev)
4435{
4436 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4437 int ret = 0;
4438
4439 if (dhd)
4440 ret = dhd_os_wake_lock_timeout(&dhd->pub);
4441 return ret;
4442}
4443
4444int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val)
4445{
4446 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
4447 unsigned long flags;
4448
4449 if (dhd) {
4450 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
4451 if (val > dhd->wakelock_timeout_enable)
4452 dhd->wakelock_timeout_enable = val;
4453 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
4454 }
4455 return 0;
4456}
4457
4458int net_os_wake_lock_timeout_enable(struct net_device *dev, int val)
4459{
4460 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4461 int ret = 0;
4462
4463 if (dhd)
4464 ret = dhd_os_wake_lock_timeout_enable(&dhd->pub, val);
4465 return ret;
4466}
4467
4468int dhd_os_wake_lock(dhd_pub_t *pub)
4469{
4470 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
4471 unsigned long flags;
4472 int ret = 0;
4473
4474 if (dhd) {
4475 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
4476#ifdef CONFIG_HAS_WAKELOCK
4477 if (!dhd->wakelock_counter)
4478 wake_lock(&dhd->wl_wifi);
4479#endif
4480 dhd->wakelock_counter++;
4481 ret = dhd->wakelock_counter;
4482 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
4483 }
4484 return ret;
4485}
4486
4487int net_os_wake_lock(struct net_device *dev)
4488{
4489 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4490 int ret = 0;
4491
4492 if (dhd)
4493 ret = dhd_os_wake_lock(&dhd->pub);
4494 return ret;
4495}
4496
4497int dhd_os_wake_unlock(dhd_pub_t *pub)
4498{
4499 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
4500 unsigned long flags;
4501 int ret = 0;
4502
4503 dhd_os_wake_lock_timeout(pub);
4504 if (dhd) {
4505 spin_lock_irqsave(&dhd->wakelock_spinlock, flags);
4506 if (dhd->wakelock_counter) {
4507 dhd->wakelock_counter--;
4508#ifdef CONFIG_HAS_WAKELOCK
4509 if (!dhd->wakelock_counter)
4510 wake_unlock(&dhd->wl_wifi);
4511#endif
4512 ret = dhd->wakelock_counter;
4513 }
4514 spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags);
4515 }
4516 return ret;
4517}
4518
4519int dhd_os_check_wakelock(void *dhdp)
4520{
4521#ifdef CONFIG_HAS_WAKELOCK
4522 dhd_pub_t *pub = (dhd_pub_t *)dhdp;
4523 dhd_info_t *dhd;
4524
4525 if (!pub)
4526 return 0;
4527 dhd = (dhd_info_t *)(pub->info);
4528
4529 if (dhd && wake_lock_active(&dhd->wl_wifi))
4530 return 1;
4531#endif
4532 return 0;
4533}
4534
4535int dhd_os_check_if_up(void *dhdp)
4536{
4537 dhd_pub_t *pub = (dhd_pub_t *)dhdp;
4538
4539 if (!pub)
4540 return 0;
4541 return pub->up;
4542}
4543
4544int net_os_wake_unlock(struct net_device *dev)
4545{
4546 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
4547 int ret = 0;
4548
4549 if (dhd)
4550 ret = dhd_os_wake_unlock(&dhd->pub);
4551 return ret;
4552}
4553
4554int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd)
4555{
4556 int ifidx;
4557 int ret = 0;
4558 dhd_info_t *dhd = NULL;
4559
4560 if (!net || !netdev_priv(net)) {
4561 DHD_ERROR(("%s invalid parameter\n", __FUNCTION__));
4562 return -EINVAL;
4563 }
4564
4565 dhd = *(dhd_info_t **)netdev_priv(net);
4566 ifidx = dhd_net2idx(dhd, net);
4567 if (ifidx == DHD_BAD_IF) {
4568 DHD_ERROR(("%s bad ifidx\n", __FUNCTION__));
4569 return -ENODEV;
4570 }
4571
4572 DHD_OS_WAKE_LOCK(&dhd->pub);
4573 ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len);
4574 dhd_check_hang(net, &dhd->pub, ret);
4575 DHD_OS_WAKE_UNLOCK(&dhd->pub);
4576
4577 return ret;
4578}
4579
4580bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret)
4581{
4582 struct net_device *net;
4583
4584 net = dhd_idx2net(dhdp, ifidx);
4585 return dhd_check_hang(net, dhdp, ret);
4586}
4587
4588#ifdef PROP_TXSTATUS
4589extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t action, uint8 ifid,
4590 uint8 iftype, uint8* ea);
4591extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits);
4592
4593int dhd_wlfc_interface_event(struct dhd_info *dhd, uint8 action, uint8 ifid, uint8 iftype,
4594 uint8* ea)
4595{
4596 if (dhd->pub.wlfc_state == NULL)
4597 return BCME_OK;
4598
4599 return dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea);
4600}
4601
4602int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data)
4603{
4604 if (dhd->pub.wlfc_state == NULL)
4605 return BCME_OK;
4606
4607 return dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data);
4608}
4609
4610int dhd_wlfc_event(struct dhd_info *dhd)
4611{
4612 return dhd_wlfc_enable(&dhd->pub);
4613}
4614#endif /* PROP_TXSTATUS */
4615
4616#ifdef BCMDBGFS
4617
4618#include <linux/debugfs.h>
4619
4620extern uint32 dhd_readregl(void *bp, uint32 addr);
4621extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data);
4622
4623typedef struct dhd_dbgfs {
4624 struct dentry *debugfs_dir;
4625 struct dentry *debugfs_mem;
4626 dhd_pub_t *dhdp;
4627 uint32 size;
4628} dhd_dbgfs_t;
4629
4630dhd_dbgfs_t g_dbgfs;
4631
4632static int
4633dhd_dbg_state_open(struct inode *inode, struct file *file)
4634{
4635 file->private_data = inode->i_private;
4636 return 0;
4637}
4638
4639static ssize_t
4640dhd_dbg_state_read(struct file *file, char __user *ubuf,
4641 size_t count, loff_t *ppos)
4642{
4643 ssize_t rval;
4644 uint32 tmp;
4645 loff_t pos = *ppos;
4646 size_t ret;
4647
4648 if (pos < 0)
4649 return -EINVAL;
4650 if (pos >= g_dbgfs.size || !count)
4651 return 0;
4652 if (count > g_dbgfs.size - pos)
4653 count = g_dbgfs.size - pos;
4654
4655 /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */
4656 tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3));
4657
4658 ret = copy_to_user(ubuf, &tmp, 4);
4659 if (ret == count)
4660 return -EFAULT;
4661
4662 count -= ret;
4663 *ppos = pos + count;
4664 rval = count;
4665
4666 return rval;
4667}
4668
4669
4670static ssize_t
4671dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos)
4672{
4673 loff_t pos = *ppos;
4674 size_t ret;
4675 uint32 buf;
4676
4677 if (pos < 0)
4678 return -EINVAL;
4679 if (pos >= g_dbgfs.size || !count)
4680 return 0;
4681 if (count > g_dbgfs.size - pos)
4682 count = g_dbgfs.size - pos;
4683
4684 ret = copy_from_user(&buf, ubuf, sizeof(uint32));
4685 if (ret == count)
4686 return -EFAULT;
4687
4688 /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */
4689 dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf);
4690
4691 return count;
4692}
4693
4694
4695loff_t
4696dhd_debugfs_lseek(struct file *file, loff_t off, int whence)
4697{
4698 loff_t pos = -1;
4699
4700 switch (whence) {
4701 case 0:
4702 pos = off;
4703 break;
4704 case 1:
4705 pos = file->f_pos + off;
4706 break;
4707 case 2:
4708 pos = g_dbgfs.size - off;
4709 }
4710 return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos);
4711}
4712
4713static const struct file_operations dhd_dbg_state_ops = {
4714 .read = dhd_dbg_state_read,
4715 .write = dhd_debugfs_write,
4716 .open = dhd_dbg_state_open,
4717 .llseek = dhd_debugfs_lseek
4718};
4719
4720static void dhd_dbg_create(void)
4721{
4722 if (g_dbgfs.debugfs_dir) {
4723 g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir,
4724 NULL, &dhd_dbg_state_ops);
4725 }
4726}
4727
4728void dhd_dbg_init(dhd_pub_t *dhdp)
4729{
4730 int err;
4731
4732 g_dbgfs.dhdp = dhdp;
4733 g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */
4734
4735 g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0);
4736 if (IS_ERR(g_dbgfs.debugfs_dir)) {
4737 err = PTR_ERR(g_dbgfs.debugfs_dir);
4738 g_dbgfs.debugfs_dir = NULL;
4739 return;
4740 }
4741
4742 dhd_dbg_create();
4743
4744 return;
4745}
4746
4747void dhd_dbg_remove(void)
4748{
4749 debugfs_remove(g_dbgfs.debugfs_mem);
4750 debugfs_remove(g_dbgfs.debugfs_dir);
4751
4752 bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs));
4753
4754}
4755#endif /* ifdef BCMDBGFS */
4756
4757#ifdef WLMEDIA_HTSF
4758
4759static
4760void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf)
4761{
4762 dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
4763 struct sk_buff *skb;
4764 uint32 htsf = 0;
4765 uint16 dport = 0, oldmagic = 0xACAC;
4766 char *p1;
4767 htsfts_t ts;
4768
4769 /* timestamp packet */
4770
4771 p1 = (char*) PKTDATA(dhdp->osh, pktbuf);
4772
4773 if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) {
4774/* memcpy(&proto, p1+26, 4); */
4775 memcpy(&dport, p1+40, 2);
4776/* proto = ((ntoh32(proto))>> 16) & 0xFF; */
4777 dport = ntoh16(dport);
4778 }
4779
4780 /* timestamp only if icmp or udb iperf with port 5555 */
4781/* if (proto == 17 && dport == tsport) { */
4782 if (dport >= tsport && dport <= tsport + 20) {
4783
4784 skb = (struct sk_buff *) pktbuf;
4785
4786 htsf = dhd_get_htsf(dhd, 0);
4787 memset(skb->data + 44, 0, 2); /* clear checksum */
4788 memcpy(skb->data+82, &oldmagic, 2);
4789 memcpy(skb->data+84, &htsf, 4);
4790
4791 memset(&ts, 0, sizeof(htsfts_t));
4792 ts.magic = HTSFMAGIC;
4793 ts.prio = PKTPRIO(pktbuf);
4794 ts.seqnum = htsf_seqnum++;
4795 ts.c10 = get_cycles();
4796 ts.t10 = htsf;
4797 ts.endmagic = HTSFENDMAGIC;
4798
4799 memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts));
4800 }
4801}
4802
4803static void dhd_dump_htsfhisto(histo_t *his, char *s)
4804{
4805 int pktcnt = 0, curval = 0, i;
4806 for (i = 0; i < (NUMBIN-2); i++) {
4807 curval += 500;
4808 printf("%d ", his->bin[i]);
4809 pktcnt += his->bin[i];
4810 }
4811 printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt,
4812 his->bin[NUMBIN-1], s);
4813}
4814
4815static
4816void sorttobin(int value, histo_t *histo)
4817{
4818 int i, binval = 0;
4819
4820 if (value < 0) {
4821 histo->bin[NUMBIN-1]++;
4822 return;
4823 }
4824 if (value > histo->bin[NUMBIN-2]) /* store the max value */
4825 histo->bin[NUMBIN-2] = value;
4826
4827 for (i = 0; i < (NUMBIN-2); i++) {
4828 binval += 500; /* 500m s bins */
4829 if (value <= binval) {
4830 histo->bin[i]++;
4831 return;
4832 }
4833 }
4834 histo->bin[NUMBIN-3]++;
4835}
4836
4837static
4838void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf)
4839{
4840 dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
4841 struct sk_buff *skb;
4842 char *p1;
4843 uint16 old_magic;
4844 int d1, d2, d3, end2end;
4845 htsfts_t *htsf_ts;
4846 uint32 htsf;
4847
4848 skb = PKTTONATIVE(dhdp->osh, pktbuf);
4849 p1 = (char*)PKTDATA(dhdp->osh, pktbuf);
4850
4851 if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) {
4852 memcpy(&old_magic, p1+78, 2);
4853 htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4);
4854 }
4855 else
4856 return;
4857
4858 if (htsf_ts->magic == HTSFMAGIC) {
4859 htsf_ts->tE0 = dhd_get_htsf(dhd, 0);
4860 htsf_ts->cE0 = get_cycles();
4861 }
4862
4863 if (old_magic == 0xACAC) {
4864
4865 tspktcnt++;
4866 htsf = dhd_get_htsf(dhd, 0);
4867 memcpy(skb->data+92, &htsf, sizeof(uint32));
4868
4869 memcpy(&ts[tsidx].t1, skb->data+80, 16);
4870
4871 d1 = ts[tsidx].t2 - ts[tsidx].t1;
4872 d2 = ts[tsidx].t3 - ts[tsidx].t2;
4873 d3 = ts[tsidx].t4 - ts[tsidx].t3;
4874 end2end = ts[tsidx].t4 - ts[tsidx].t1;
4875
4876 sorttobin(d1, &vi_d1);
4877 sorttobin(d2, &vi_d2);
4878 sorttobin(d3, &vi_d3);
4879 sorttobin(end2end, &vi_d4);
4880
4881 if (end2end > 0 && end2end > maxdelay) {
4882 maxdelay = end2end;
4883 maxdelaypktno = tspktcnt;
4884 memcpy(&maxdelayts, &ts[tsidx], 16);
4885 }
4886 if (++tsidx >= TSMAX)
4887 tsidx = 0;
4888 }
4889}
4890
4891uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx)
4892{
4893 uint32 htsf = 0, cur_cycle, delta, delta_us;
4894 uint32 factor, baseval, baseval2;
4895 cycles_t t;
4896
4897 t = get_cycles();
4898 cur_cycle = t;
4899
4900 if (cur_cycle > dhd->htsf.last_cycle)
4901 delta = cur_cycle - dhd->htsf.last_cycle;
4902 else {
4903 delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle);
4904 }
4905
4906 delta = delta >> 4;
4907
4908 if (dhd->htsf.coef) {
4909 /* times ten to get the first digit */
4910 factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1);
4911 baseval = (delta*10)/factor;
4912 baseval2 = (delta*10)/(factor+1);
4913 delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10);
4914 htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY;
4915 }
4916 else {
4917 DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n"));
4918 }
4919
4920 return htsf;
4921}
4922
4923static void dhd_dump_latency(void)
4924{
4925 int i, max = 0;
4926 int d1, d2, d3, d4, d5;
4927
4928 printf("T1 T2 T3 T4 d1 d2 t4-t1 i \n");
4929 for (i = 0; i < TSMAX; i++) {
4930 d1 = ts[i].t2 - ts[i].t1;
4931 d2 = ts[i].t3 - ts[i].t2;
4932 d3 = ts[i].t4 - ts[i].t3;
4933 d4 = ts[i].t4 - ts[i].t1;
4934 d5 = ts[max].t4-ts[max].t1;
4935 if (d4 > d5 && d4 > 0) {
4936 max = i;
4937 }
4938 printf("%08X %08X %08X %08X \t%d %d %d %d i=%d\n",
4939 ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4,
4940 d1, d2, d3, d4, i);
4941 }
4942
4943 printf("current idx = %d \n", tsidx);
4944
4945 printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt);
4946 printf("%08X %08X %08X %08X \t%d %d %d %d\n",
4947 maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4,
4948 maxdelayts.t2 - maxdelayts.t1,
4949 maxdelayts.t3 - maxdelayts.t2,
4950 maxdelayts.t4 - maxdelayts.t3,
4951 maxdelayts.t4 - maxdelayts.t1);
4952}
4953
4954
4955static int
4956dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx)
4957{
4958 wl_ioctl_t ioc;
4959 char buf[32];
4960 int ret;
4961 uint32 s1, s2;
4962
4963 struct tsf {
4964 uint32 low;
4965 uint32 high;
4966 } tsf_buf;
4967
4968 memset(&ioc, 0, sizeof(ioc));
4969 memset(&tsf_buf, 0, sizeof(tsf_buf));
4970
4971 ioc.cmd = WLC_GET_VAR;
4972 ioc.buf = buf;
4973 ioc.len = (uint)sizeof(buf);
4974 ioc.set = FALSE;
4975
4976 strcpy(buf, "tsf");
4977 s1 = dhd_get_htsf(dhd, 0);
4978 if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
4979 if (ret == -EIO) {
4980 DHD_ERROR(("%s: tsf is not supported by device\n",
4981 dhd_ifname(&dhd->pub, ifidx)));
4982 return -EOPNOTSUPP;
4983 }
4984 return ret;
4985 }
4986 s2 = dhd_get_htsf(dhd, 0);
4987
4988 memcpy(&tsf_buf, buf, sizeof(tsf_buf));
4989 printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ",
4990 tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1,
4991 dhd->htsf.coefdec2, s2-tsf_buf.low);
4992 printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle);
4993 return 0;
4994}
4995
4996void htsf_update(dhd_info_t *dhd, void *data)
4997{
4998 static ulong cur_cycle = 0, prev_cycle = 0;
4999 uint32 htsf, tsf_delta = 0;
5000 uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp;
5001 ulong b, a;
5002 cycles_t t;
5003
5004 /* cycles_t in inlcude/mips/timex.h */
5005
5006 t = get_cycles();
5007
5008 prev_cycle = cur_cycle;
5009 cur_cycle = t;
5010
5011 if (cur_cycle > prev_cycle)
5012 cyc_delta = cur_cycle - prev_cycle;
5013 else {
5014 b = cur_cycle;
5015 a = prev_cycle;
5016 cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle);
5017 }
5018
5019 if (data == NULL)
5020 printf(" tsf update ata point er is null \n");
5021
5022 memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t));
5023 memcpy(&cur_tsf, data, sizeof(tsf_t));
5024
5025 if (cur_tsf.low == 0) {
5026 DHD_INFO((" ---- 0 TSF, do not update, return\n"));
5027 return;
5028 }
5029
5030 if (cur_tsf.low > prev_tsf.low)
5031 tsf_delta = (cur_tsf.low - prev_tsf.low);
5032 else {
5033 DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n",
5034 cur_tsf.low, prev_tsf.low));
5035 if (cur_tsf.high > prev_tsf.high) {
5036 tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low);
5037 DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta));
5038 }
5039 else
5040 return; /* do not update */
5041 }
5042
5043 if (tsf_delta) {
5044 hfactor = cyc_delta / tsf_delta;
5045 tmp = (cyc_delta - (hfactor * tsf_delta))*10;
5046 dec1 = tmp/tsf_delta;
5047 dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta;
5048 tmp = (tmp - (dec1*tsf_delta))*10;
5049 dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta;
5050
5051 if (dec3 > 4) {
5052 if (dec2 == 9) {
5053 dec2 = 0;
5054 if (dec1 == 9) {
5055 dec1 = 0;
5056 hfactor++;
5057 }
5058 else {
5059 dec1++;
5060 }
5061 }
5062 else
5063 dec2++;
5064 }
5065 }
5066
5067 if (hfactor) {
5068 htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low;
5069 dhd->htsf.coef = hfactor;
5070 dhd->htsf.last_cycle = cur_cycle;
5071 dhd->htsf.last_tsf = cur_tsf.low;
5072 dhd->htsf.coefdec1 = dec1;
5073 dhd->htsf.coefdec2 = dec2;
5074 }
5075 else {
5076 htsf = prev_tsf.low;
5077 }
5078}
5079
5080#endif /* WLMEDIA_HTSF */
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c
new file mode 100644
index 00000000000..dd9c71f75be
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c
@@ -0,0 +1,393 @@
1/*
2 * Broadcom Dongle Host Driver (DHD), Linux monitor network interface
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: dhd_linux_mon.c,v 1.131.2.55 2011-02-09 05:31:56 Exp $
25 */
26
27#include <linux/string.h>
28#include <linux/module.h>
29#include <linux/netdevice.h>
30#include <linux/etherdevice.h>
31#include <linux/if_arp.h>
32#include <linux/ieee80211.h>
33#include <linux/rtnetlink.h>
34#include <net/ieee80211_radiotap.h>
35
36#include <wlioctl.h>
37#include <bcmutils.h>
38#include <linux_osl.h>
39#include <dhd_dbg.h>
40#include <dngl_stats.h>
41#include <dhd.h>
42
43typedef enum monitor_states
44{
45 MONITOR_STATE_DEINIT = 0x0,
46 MONITOR_STATE_INIT = 0x1,
47 MONITOR_STATE_INTERFACE_ADDED = 0x2,
48 MONITOR_STATE_INTERFACE_DELETED = 0x4
49} monitor_states_t;
50extern int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
51
52/**
53 * Local declarations and defintions (not exposed)
54 */
55#define MON_PRINT(format, ...) printk("DHD-MON: %s " format, __func__, ##__VA_ARGS__)
56#define MON_TRACE MON_PRINT
57
58typedef struct monitor_interface {
59 int radiotap_enabled;
60 struct net_device* real_ndev; /* The real interface that the monitor is on */
61 struct net_device* mon_ndev;
62} monitor_interface;
63
64typedef struct dhd_linux_monitor {
65 void *dhd_pub;
66 monitor_states_t monitor_state;
67 monitor_interface mon_if[DHD_MAX_IFS];
68 struct mutex lock; /* lock to protect mon_if */
69} dhd_linux_monitor_t;
70
71static dhd_linux_monitor_t g_monitor;
72
73static struct net_device* lookup_real_netdev(char *name);
74static monitor_interface* ndev_to_monif(struct net_device *ndev);
75static int dhd_mon_if_open(struct net_device *ndev);
76static int dhd_mon_if_stop(struct net_device *ndev);
77static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev);
78static void dhd_mon_if_set_multicast_list(struct net_device *ndev);
79static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr);
80
81static const struct net_device_ops dhd_mon_if_ops = {
82 .ndo_open = dhd_mon_if_open,
83 .ndo_stop = dhd_mon_if_stop,
84 .ndo_start_xmit = dhd_mon_if_subif_start_xmit,
85 .ndo_set_multicast_list = dhd_mon_if_set_multicast_list,
86 .ndo_set_mac_address = dhd_mon_if_change_mac,
87};
88
89/**
90 * Local static function defintions
91 */
92
93/* Look up dhd's net device table to find a match (e.g. interface "eth0" is a match for "mon.eth0"
94 * "p2p-eth0-0" is a match for "mon.p2p-eth0-0")
95 */
96static struct net_device* lookup_real_netdev(char *name)
97{
98 int i;
99 int last_name_len = 0;
100 struct net_device *ndev;
101 struct net_device *ndev_found = NULL;
102
103 /* We want to find interface "p2p-eth0-0" for monitor interface "mon.p2p-eth0-0", so
104 * we skip "eth0" even if "mon.p2p-eth0-0" contains "eth0"
105 */
106 for (i = 0; i < DHD_MAX_IFS; i++) {
107 ndev = dhd_idx2net(g_monitor.dhd_pub, i);
108 if (ndev && strstr(name, ndev->name)) {
109 if (strlen(ndev->name) > last_name_len) {
110 ndev_found = ndev;
111 last_name_len = strlen(ndev->name);
112 }
113 }
114 }
115
116 return ndev_found;
117}
118
119static monitor_interface* ndev_to_monif(struct net_device *ndev)
120{
121 int i;
122
123 for (i = 0; i < DHD_MAX_IFS; i++) {
124 if (g_monitor.mon_if[i].mon_ndev == ndev)
125 return &g_monitor.mon_if[i];
126 }
127
128 return NULL;
129}
130
131static int dhd_mon_if_open(struct net_device *ndev)
132{
133 int ret = 0;
134
135 MON_PRINT("enter\n");
136 return ret;
137}
138
139static int dhd_mon_if_stop(struct net_device *ndev)
140{
141 int ret = 0;
142
143 MON_PRINT("enter\n");
144 return ret;
145}
146
147static int dhd_mon_if_subif_start_xmit(struct sk_buff *skb, struct net_device *ndev)
148{
149 int ret = 0;
150 int rtap_len;
151 int qos_len = 0;
152 int dot11_hdr_len = 24;
153 int snap_len = 6;
154 unsigned char *pdata;
155 unsigned short frame_ctl;
156 unsigned char src_mac_addr[6];
157 unsigned char dst_mac_addr[6];
158 struct ieee80211_hdr *dot11_hdr;
159 struct ieee80211_radiotap_header *rtap_hdr;
160 monitor_interface* mon_if;
161
162 MON_PRINT("enter\n");
163
164 mon_if = ndev_to_monif(ndev);
165 if (mon_if == NULL || mon_if->real_ndev == NULL) {
166 MON_PRINT(" cannot find matched net dev, skip the packet\n");
167 goto fail;
168 }
169
170 if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
171 goto fail;
172
173 rtap_hdr = (struct ieee80211_radiotap_header *)skb->data;
174 if (unlikely(rtap_hdr->it_version))
175 goto fail;
176
177 rtap_len = ieee80211_get_radiotap_len(skb->data);
178 if (unlikely(skb->len < rtap_len))
179 goto fail;
180
181 MON_PRINT("radiotap len (should be 14): %d\n", rtap_len);
182
183 /* Skip the ratio tap header */
184 skb_pull(skb, rtap_len);
185
186 dot11_hdr = (struct ieee80211_hdr *)skb->data;
187 frame_ctl = le16_to_cpu(dot11_hdr->frame_control);
188 /* Check if the QoS bit is set */
189 if ((frame_ctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
190 /* Check if this ia a Wireless Distribution System (WDS) frame
191 * which has 4 MAC addresses
192 */
193 if (dot11_hdr->frame_control & 0x0080)
194 qos_len = 2;
195 if ((dot11_hdr->frame_control & 0x0300) == 0x0300)
196 dot11_hdr_len += 6;
197
198 memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
199 memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
200
201 /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for
202 * for two MAC addresses
203 */
204 skb_pull(skb, dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2);
205 pdata = (unsigned char*)skb->data;
206 memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr));
207 memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, sizeof(src_mac_addr));
208
209 MON_PRINT("if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
210
211 /* Use the real net device to transmit the packet */
212 ret = dhd_start_xmit(skb, mon_if->real_ndev);
213
214 return ret;
215 }
216fail:
217 dev_kfree_skb(skb);
218 return 0;
219}
220
221static void dhd_mon_if_set_multicast_list(struct net_device *ndev)
222{
223 monitor_interface* mon_if;
224
225 mon_if = ndev_to_monif(ndev);
226 if (mon_if == NULL || mon_if->real_ndev == NULL) {
227 MON_PRINT(" cannot find matched net dev, skip the packet\n");
228 }
229
230 MON_PRINT("enter, if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
231}
232
233static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr)
234{
235 int ret = 0;
236 monitor_interface* mon_if;
237
238 mon_if = ndev_to_monif(ndev);
239 if (mon_if == NULL || mon_if->real_ndev == NULL) {
240 MON_PRINT(" cannot find matched net dev, skip the packet\n");
241 }
242
243 MON_PRINT("enter, if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name);
244 return ret;
245}
246
247/**
248 * Global function definitions (declared in dhd_linux_mon.h)
249 */
250
251int dhd_add_monitor(char *name, struct net_device **new_ndev)
252{
253 int i;
254 int idx = -1;
255 int ret = 0;
256 struct net_device* ndev = NULL;
257 dhd_linux_monitor_t **dhd_mon;
258
259 mutex_lock(&g_monitor.lock);
260
261 MON_TRACE("enter, if name: %s\n", name);
262 if (!name || !new_ndev) {
263 MON_PRINT("invalid parameters\n");
264 ret = -EINVAL;
265 goto out;
266 }
267
268 /*
269 * Find a vacancy
270 */
271 for (i = 0; i < DHD_MAX_IFS; i++)
272 if (g_monitor.mon_if[i].mon_ndev == NULL) {
273 idx = i;
274 break;
275 }
276 if (idx == -1) {
277 MON_PRINT("exceeds maximum interfaces\n");
278 ret = -EFAULT;
279 goto out;
280 }
281
282 ndev = alloc_etherdev(sizeof(dhd_linux_monitor_t*));
283 if (!ndev) {
284 MON_PRINT("failed to allocate memory\n");
285 ret = -ENOMEM;
286 goto out;
287 }
288
289 ndev->type = ARPHRD_IEEE80211_RADIOTAP;
290 strncpy(ndev->name, name, IFNAMSIZ);
291 ndev->name[IFNAMSIZ - 1] = 0;
292 ndev->netdev_ops = &dhd_mon_if_ops;
293
294 ret = register_netdevice(ndev);
295 if (ret) {
296 MON_PRINT(" register_netdevice failed (%d)\n", ret);
297 goto out;
298 }
299
300 *new_ndev = ndev;
301 g_monitor.mon_if[idx].radiotap_enabled = TRUE;
302 g_monitor.mon_if[idx].mon_ndev = ndev;
303 g_monitor.mon_if[idx].real_ndev = lookup_real_netdev(name);
304 dhd_mon = (dhd_linux_monitor_t **)netdev_priv(ndev);
305 *dhd_mon = &g_monitor;
306 g_monitor.monitor_state = MONITOR_STATE_INTERFACE_ADDED;
307 MON_PRINT("net device returned: 0x%p\n", ndev);
308 MON_PRINT("found a matched net device, name %s\n", g_monitor.mon_if[idx].real_ndev->name);
309
310out:
311 if (ret && ndev)
312 free_netdev(ndev);
313
314 mutex_unlock(&g_monitor.lock);
315 return ret;
316
317}
318
319int dhd_del_monitor(struct net_device *ndev)
320{
321 int i;
322 bool rollback_lock = false;
323 if (!ndev)
324 return -EINVAL;
325 mutex_lock(&g_monitor.lock);
326 for (i = 0; i < DHD_MAX_IFS; i++) {
327 if (g_monitor.mon_if[i].mon_ndev == ndev ||
328 g_monitor.mon_if[i].real_ndev == ndev) {
329 g_monitor.mon_if[i].real_ndev = NULL;
330 if (rtnl_is_locked()) {
331 rtnl_unlock();
332 rollback_lock = true;
333 }
334 unregister_netdev(g_monitor.mon_if[i].mon_ndev);
335 free_netdev(g_monitor.mon_if[i].mon_ndev);
336 g_monitor.mon_if[i].mon_ndev = NULL;
337 g_monitor.monitor_state = MONITOR_STATE_INTERFACE_DELETED;
338 break;
339 }
340 }
341 if (rollback_lock) {
342 rtnl_lock();
343 rollback_lock = false;
344 }
345
346 if (g_monitor.monitor_state !=
347 MONITOR_STATE_INTERFACE_DELETED)
348 MON_PRINT("interface not found in monitor IF array, is this a monitor IF? 0x%p\n",
349 ndev);
350 mutex_unlock(&g_monitor.lock);
351
352 return 0;
353}
354
355int dhd_monitor_init(void *dhd_pub)
356{
357 if (g_monitor.monitor_state == MONITOR_STATE_DEINIT) {
358 g_monitor.dhd_pub = dhd_pub;
359 mutex_init(&g_monitor.lock);
360 g_monitor.monitor_state = MONITOR_STATE_INIT;
361 }
362 return 0;
363}
364
365int dhd_monitor_uninit(void)
366{
367 int i;
368 struct net_device *ndev;
369 bool rollback_lock = false;
370 mutex_lock(&g_monitor.lock);
371 if (g_monitor.monitor_state != MONITOR_STATE_DEINIT) {
372 for (i = 0; i < DHD_MAX_IFS; i++) {
373 ndev = g_monitor.mon_if[i].mon_ndev;
374 if (ndev) {
375 if (rtnl_is_locked()) {
376 rtnl_unlock();
377 rollback_lock = true;
378 }
379 unregister_netdev(ndev);
380 free_netdev(ndev);
381 g_monitor.mon_if[i].real_ndev = NULL;
382 g_monitor.mon_if[i].mon_ndev = NULL;
383 if (rollback_lock) {
384 rtnl_lock();
385 rollback_lock = false;
386 }
387 }
388 }
389 g_monitor.monitor_state = MONITOR_STATE_DEINIT;
390 }
391 mutex_unlock(&g_monitor.lock);
392 return 0;
393}
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd/dhd_linux_sched.c
new file mode 100644
index 00000000000..aadd122f5b0
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_linux_sched.c
@@ -0,0 +1,39 @@
1/*
2 * Expose some of the kernel scheduler routines
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: dhd_linux_sched.c,v 1.3 2009-04-10 04:14:49 Exp $
25 */
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/sched.h>
29#include <typedefs.h>
30#include <linuxver.h>
31
32int setScheduler(struct task_struct *p, int policy, struct sched_param *param)
33{
34 int rc = 0;
35#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
36 rc = sched_setscheduler(p, policy, param);
37#endif /* LinuxVer */
38 return rc;
39}
diff --git a/drivers/net/wireless/bcmdhd/dhd_proto.h b/drivers/net/wireless/bcmdhd/dhd_proto.h
new file mode 100644
index 00000000000..e0a54ad0269
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_proto.h
@@ -0,0 +1,105 @@
1/*
2 * Header file describing the internal (inter-module) DHD interfaces.
3 *
4 * Provides type definitions and function prototypes used to link the
5 * DHD OS, bus, and protocol modules.
6 *
7 * Copyright (C) 1999-2011, Broadcom Corporation
8 *
9 * Unless you and Broadcom execute a separate written software license
10 * agreement governing use of this software, this software is licensed to you
11 * under the terms of the GNU General Public License version 2 (the "GPL"),
12 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
13 * following added to such license:
14 *
15 * As a special exception, the copyright holders of this software give you
16 * permission to link this software with independent modules, and to copy and
17 * distribute the resulting executable under terms of your choice, provided that
18 * you also meet, for each linked independent module, the terms and conditions of
19 * the license of that module. An independent module is a module which is not
20 * derived from this software. The special exception does not apply to any
21 * modifications of the software.
22 *
23 * Notwithstanding the above, under no circumstances may you combine this
24 * software in any way with any other Broadcom software provided under a license
25 * other than the GPL, without Broadcom's express prior written consent.
26 *
27 * $Id: dhd_proto.h,v 1.8.10.6 2010-12-22 23:47:24 Exp $
28 */
29
30#ifndef _dhd_proto_h_
31#define _dhd_proto_h_
32
33#include <dhdioctl.h>
34#include <wlioctl.h>
35
36#ifndef IOCTL_RESP_TIMEOUT
37#define IOCTL_RESP_TIMEOUT 20000 /* In milli second */
38#endif
39
40/*
41 * Exported from the dhd protocol module (dhd_cdc, dhd_rndis)
42 */
43
44/* Linkage, sets prot link and updates hdrlen in pub */
45extern int dhd_prot_attach(dhd_pub_t *dhdp);
46
47/* Unlink, frees allocated protocol memory (including dhd_prot) */
48extern void dhd_prot_detach(dhd_pub_t *dhdp);
49
50/* Initialize protocol: sync w/dongle state.
51 * Sets dongle media info (iswl, drv_version, mac address).
52 */
53extern int dhd_prot_init(dhd_pub_t *dhdp);
54
55/* Stop protocol: sync w/dongle state. */
56extern void dhd_prot_stop(dhd_pub_t *dhdp);
57
58/* Add any protocol-specific data header.
59 * Caller must reserve prot_hdrlen prepend space.
60 */
61extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp);
62
63/* Remove any protocol-specific data header. */
64extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp);
65
66/* Use protocol to issue ioctl to dongle */
67extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len);
68
69/* Handles a protocol control response asynchronously */
70extern int dhd_prot_ctl_complete(dhd_pub_t *dhd);
71
72/* Check for and handle local prot-specific iovar commands */
73extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
74 void *params, int plen, void *arg, int len, bool set);
75
76/* Add prot dump output to a buffer */
77extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
78
79/* Update local copy of dongle statistics */
80extern void dhd_prot_dstats(dhd_pub_t *dhdp);
81
82extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen);
83
84extern int dhd_preinit_ioctls(dhd_pub_t *dhd);
85
86#ifdef PROP_TXSTATUS
87extern int dhd_wlfc_enque_sendq(void* state, int prec, void* p);
88extern int dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx);
89extern void dhd_wlfc_cleanup(dhd_pub_t *dhd);
90#endif /* PROP_TXSTATUS */
91
92/********************************
93 * For version-string expansion *
94 */
95#if defined(BDC)
96#define DHD_PROTOCOL "bdc"
97#elif defined(CDC)
98#define DHD_PROTOCOL "cdc"
99#elif defined(RNDIS)
100#define DHD_PROTOCOL "rndis"
101#else
102#define DHD_PROTOCOL "unknown"
103#endif /* proto */
104
105#endif /* _dhd_proto_h_ */
diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c
new file mode 100644
index 00000000000..57aee570545
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c
@@ -0,0 +1,6289 @@
1/*
2 * DHD Bus Module for SDIO
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: dhd_sdio.c 288105 2011-10-06 01:58:02Z $
25 */
26
27#include <typedefs.h>
28#include <osl.h>
29#include <bcmsdh.h>
30
31#ifdef BCMEMBEDIMAGE
32#include BCMEMBEDIMAGE
33#endif /* BCMEMBEDIMAGE */
34
35#include <bcmdefs.h>
36#include <bcmutils.h>
37#include <bcmendian.h>
38#include <bcmdevs.h>
39
40#include <siutils.h>
41#include <hndpmu.h>
42#include <hndsoc.h>
43#include <bcmsdpcm.h>
44#if defined(DHD_DEBUG)
45#include <hndrte_armtrap.h>
46#include <hndrte_cons.h>
47#endif /* defined(DHD_DEBUG) */
48#include <sbchipc.h>
49#include <sbhnddma.h>
50
51#include <sdio.h>
52#include <sbsdio.h>
53#include <sbsdpcmdev.h>
54#include <bcmsdpcm.h>
55#include <bcmsdbus.h>
56
57#include <proto/ethernet.h>
58#include <proto/802.1d.h>
59#include <proto/802.11.h>
60
61#include <dngl_stats.h>
62#include <dhd.h>
63#include <dhd_bus.h>
64#include <dhd_proto.h>
65#include <dhd_dbg.h>
66#include <dhdioctl.h>
67#include <sdiovar.h>
68
69#ifndef DHDSDIO_MEM_DUMP_FNAME
70#define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
71#endif
72
73#define QLEN 256 /* bulk rx and tx queue lengths */
74#define FCHI (QLEN - 10)
75#define FCLOW (FCHI / 2)
76#define PRIOMASK 7
77
78#define TXRETRIES 2 /* # of retries for tx frames */
79
80#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
81
82#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
83
84#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
85
86#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
87#define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */
88#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */
89
90#ifndef DHD_FIRSTREAD
91#define DHD_FIRSTREAD 32
92#endif
93#if !ISPOWEROF2(DHD_FIRSTREAD)
94#error DHD_FIRSTREAD is not a power of 2!
95#endif
96
97/* Total length of frame header for dongle protocol */
98#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
99#ifdef SDTEST
100#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
101#else
102#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
103#endif
104
105/* Space for header read, limit for data packets */
106#ifndef MAX_HDR_READ
107#define MAX_HDR_READ 32
108#endif
109#if !ISPOWEROF2(MAX_HDR_READ)
110#error MAX_HDR_READ is not a power of 2!
111#endif
112
113#define MAX_RX_DATASZ 2048
114
115/* Maximum milliseconds to wait for F2 to come up */
116#define DHD_WAIT_F2RDY 3000
117
118/* Bump up limit on waiting for HT to account for first startup;
119 * if the image is doing a CRC calculation before programming the PMU
120 * for HT availability, it could take a couple hundred ms more, so
121 * max out at a 1 second (1000000us).
122 */
123#if (PMU_MAX_TRANSITION_DLY <= 1000000)
124#undef PMU_MAX_TRANSITION_DLY
125#define PMU_MAX_TRANSITION_DLY 1000000
126#endif
127
128/* Value for ChipClockCSR during initial setup */
129#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
130#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
131
132/* Flags for SDH calls */
133#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
134
135/* Packet free applicable unconditionally for sdio and sdspi. Conditional if
136 * bufpool was present for gspi bus.
137 */
138#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
139 PKTFREE(bus->dhd->osh, pkt, FALSE);
140DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
141#if defined(OOB_INTR_ONLY)
142extern void bcmsdh_set_irq(int flag);
143#endif /* defined(OOB_INTR_ONLY) */
144#ifdef PROP_TXSTATUS
145extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success);
146#endif
147
148#ifdef DHD_DEBUG
149/* Device console log buffer state */
150#define CONSOLE_LINE_MAX 192
151#define CONSOLE_BUFFER_MAX 2024
152typedef struct dhd_console {
153 uint count; /* Poll interval msec counter */
154 uint log_addr; /* Log struct address (fixed) */
155 hndrte_log_t log; /* Log struct (host copy) */
156 uint bufsize; /* Size of log buffer */
157 uint8 *buf; /* Log buffer (host copy) */
158 uint last; /* Last buffer read index */
159} dhd_console_t;
160#endif /* DHD_DEBUG */
161
162/* Private data for SDIO bus interaction */
163typedef struct dhd_bus {
164 dhd_pub_t *dhd;
165
166 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
167 si_t *sih; /* Handle for SI calls */
168 char *vars; /* Variables (from CIS and/or other) */
169 uint varsz; /* Size of variables buffer */
170 uint32 sbaddr; /* Current SB window pointer (-1, invalid) */
171
172 sdpcmd_regs_t *regs; /* Registers for SDIO core */
173 uint sdpcmrev; /* SDIO core revision */
174 uint armrev; /* CPU core revision */
175 uint ramrev; /* SOCRAM core revision */
176 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
177 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
178
179 uint32 bus; /* gSPI or SDIO bus */
180 uint32 hostintmask; /* Copy of Host Interrupt Mask */
181 uint32 intstatus; /* Intstatus bits (events) pending */
182 bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
183 bool fcstate; /* State of dongle flow-control */
184
185 uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
186 char *fw_path; /* module_param: path to firmware image */
187 char *nv_path; /* module_param: path to nvram vars file */
188 const char *nvram_params; /* user specified nvram params. */
189
190 uint blocksize; /* Block size of SDIO transfers */
191 uint roundup; /* Max roundup limit */
192
193 struct pktq txq; /* Queue length used for flow-control */
194 uint8 flowcontrol; /* per prio flow control bitmask */
195 uint8 tx_seq; /* Transmit sequence number (next) */
196 uint8 tx_max; /* Maximum transmit sequence allowed */
197
198 uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
199 uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
200 uint16 nextlen; /* Next Read Len from last header */
201 uint8 rx_seq; /* Receive sequence number (expected) */
202 bool rxskip; /* Skip receive (awaiting NAK ACK) */
203
204 void *glomd; /* Packet containing glomming descriptor */
205 void *glom; /* Packet chain for glommed superframe */
206 uint glomerr; /* Glom packet read errors */
207
208 uint8 *rxbuf; /* Buffer for receiving control packets */
209 uint rxblen; /* Allocated length of rxbuf */
210 uint8 *rxctl; /* Aligned pointer into rxbuf */
211 uint8 *databuf; /* Buffer for receiving big glom packet */
212 uint8 *dataptr; /* Aligned pointer into databuf */
213 uint rxlen; /* Length of valid data in buffer */
214
215 uint8 sdpcm_ver; /* Bus protocol reported by dongle */
216
217 bool intr; /* Use interrupts */
218 bool poll; /* Use polling */
219 bool ipend; /* Device interrupt is pending */
220 bool intdis; /* Interrupts disabled by isr */
221 uint intrcount; /* Count of device interrupt callbacks */
222 uint lastintrs; /* Count as of last watchdog timer */
223 uint spurious; /* Count of spurious interrupts */
224 uint pollrate; /* Ticks between device polls */
225 uint polltick; /* Tick counter */
226 uint pollcnt; /* Count of active polls */
227
228#ifdef DHD_DEBUG
229 dhd_console_t console; /* Console output polling support */
230 uint console_addr; /* Console address from shared struct */
231#endif /* DHD_DEBUG */
232
233 uint regfails; /* Count of R_REG/W_REG failures */
234
235 uint clkstate; /* State of sd and backplane clock(s) */
236 bool activity; /* Activity flag for clock down */
237 int32 idletime; /* Control for activity timeout */
238 int32 idlecount; /* Activity timeout counter */
239 int32 idleclock; /* How to set bus driver when idle */
240 int32 sd_divisor; /* Speed control to bus driver */
241 int32 sd_mode; /* Mode control to bus driver */
242 int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
243 bool use_rxchain; /* If dhd should use PKT chains */
244 bool sleeping; /* Is SDIO bus sleeping? */
245 bool rxflow_mode; /* Rx flow control mode */
246 bool rxflow; /* Is rx flow control on */
247 uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
248 bool alp_only; /* Don't use HT clock (ALP only) */
249 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
250 bool usebufpool;
251
252#ifdef SDTEST
253 /* external loopback */
254 bool ext_loop;
255 uint8 loopid;
256
257 /* pktgen configuration */
258 uint pktgen_freq; /* Ticks between bursts */
259 uint pktgen_count; /* Packets to send each burst */
260 uint pktgen_print; /* Bursts between count displays */
261 uint pktgen_total; /* Stop after this many */
262 uint pktgen_minlen; /* Minimum packet data len */
263 uint pktgen_maxlen; /* Maximum packet data len */
264 uint pktgen_mode; /* Configured mode: tx, rx, or echo */
265 uint pktgen_stop; /* Number of tx failures causing stop */
266
267 /* active pktgen fields */
268 uint pktgen_tick; /* Tick counter for bursts */
269 uint pktgen_ptick; /* Burst counter for printing */
270 uint pktgen_sent; /* Number of test packets generated */
271 uint pktgen_rcvd; /* Number of test packets received */
272 uint pktgen_fail; /* Number of failed send attempts */
273 uint16 pktgen_len; /* Length of next packet to send */
274#define PKTGEN_RCV_IDLE (0)
275#define PKTGEN_RCV_ONGOING (1)
276 uint16 pktgen_rcv_state; /* receive state */
277 uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */
278#endif /* SDTEST */
279
280 /* Some additional counters */
281 uint tx_sderrs; /* Count of tx attempts with sd errors */
282 uint fcqueued; /* Tx packets that got queued */
283 uint rxrtx; /* Count of rtx requests (NAK to dongle) */
284 uint rx_toolong; /* Receive frames too long to receive */
285 uint rxc_errors; /* SDIO errors when reading control frames */
286 uint rx_hdrfail; /* SDIO errors on header reads */
287 uint rx_badhdr; /* Bad received headers (roosync?) */
288 uint rx_badseq; /* Mismatched rx sequence number */
289 uint fc_rcvd; /* Number of flow-control events received */
290 uint fc_xoff; /* Number which turned on flow-control */
291 uint fc_xon; /* Number which turned off flow-control */
292 uint rxglomfail; /* Failed deglom attempts */
293 uint rxglomframes; /* Number of glom frames (superframes) */
294 uint rxglompkts; /* Number of packets from glom frames */
295 uint f2rxhdrs; /* Number of header reads */
296 uint f2rxdata; /* Number of frame data reads */
297 uint f2txdata; /* Number of f2 frame writes */
298 uint f1regdata; /* Number of f1 register accesses */
299
300 uint8 *ctrl_frame_buf;
301 uint32 ctrl_frame_len;
302 bool ctrl_frame_stat;
303 uint32 rxint_mode; /* rx interrupt mode */
304} dhd_bus_t;
305
306/* clkstate */
307#define CLK_NONE 0
308#define CLK_SDONLY 1
309#define CLK_PENDING 2 /* Not used yet */
310#define CLK_AVAIL 3
311
312#define DHD_NOPMU(dhd) (FALSE)
313
314#ifdef DHD_DEBUG
315static int qcount[NUMPRIO];
316static int tx_packets[NUMPRIO];
317#endif /* DHD_DEBUG */
318
319/* Deferred transmit */
320const uint dhd_deferred_tx = 1;
321
322extern uint dhd_watchdog_ms;
323extern void dhd_os_wd_timer(void *bus, uint wdtick);
324
325/* Tx/Rx bounds */
326uint dhd_txbound;
327uint dhd_rxbound;
328uint dhd_txminmax = DHD_TXMINMAX;
329
330/* override the RAM size if possible */
331#define DONGLE_MIN_MEMSIZE (128 *1024)
332int dhd_dongle_memsize;
333
334static bool dhd_doflow;
335static bool dhd_alignctl;
336
337static bool sd1idle;
338
339static bool retrydata;
340#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata)
341
342static const uint watermark = 8;
343static const uint firstread = DHD_FIRSTREAD;
344
345#define HDATLEN (firstread - (SDPCM_HDRLEN))
346
347/* Retry count for register access failures */
348static const uint retry_limit = 2;
349
350/* Force even SD lengths (some host controllers mess up on odd bytes) */
351static bool forcealign;
352
353/* Flag to indicate if we should download firmware on driver load */
354uint dhd_download_fw_on_driverload = TRUE;
355
356#define ALIGNMENT 4
357
358#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
359extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
360#endif
361
362#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
363#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
364#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
365#define PKTALIGN(osh, p, len, align) \
366 do { \
367 uint datalign; \
368 datalign = (uintptr)PKTDATA((osh), (p)); \
369 datalign = ROUNDUP(datalign, (align)) - datalign; \
370 ASSERT(datalign < (align)); \
371 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
372 if (datalign) \
373 PKTPULL((osh), (p), datalign); \
374 PKTSETLEN((osh), (p), (len)); \
375 } while (0)
376
377/* Limit on rounding up frames */
378static const uint max_roundup = 512;
379
380/* Try doing readahead */
381static bool dhd_readahead;
382
383/* To check if there's window offered */
384#define DATAOK(bus) \
385 (((uint8)(bus->tx_max - bus->tx_seq) > 2) && \
386 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
387
388/* To check if there's window offered for ctrl frame */
389#define TXCTLOK(bus) \
390 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
391 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
392
393/* Macros to get register read/write status */
394/* NOTE: these assume a local dhdsdio_bus_t *bus! */
395#define R_SDREG(regvar, regaddr, retryvar) \
396do { \
397 retryvar = 0; \
398 do { \
399 regvar = R_REG(bus->dhd->osh, regaddr); \
400 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
401 if (retryvar) { \
402 bus->regfails += (retryvar-1); \
403 if (retryvar > retry_limit) { \
404 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
405 __FUNCTION__, __LINE__)); \
406 regvar = 0; \
407 } \
408 } \
409} while (0)
410
411#define W_SDREG(regval, regaddr, retryvar) \
412do { \
413 retryvar = 0; \
414 do { \
415 W_REG(bus->dhd->osh, regaddr, regval); \
416 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
417 if (retryvar) { \
418 bus->regfails += (retryvar-1); \
419 if (retryvar > retry_limit) \
420 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
421 __FUNCTION__, __LINE__)); \
422 } \
423} while (0)
424
425#define BUS_WAKE(bus) \
426 do { \
427 if ((bus)->sleeping) \
428 dhdsdio_bussleep((bus), FALSE); \
429 } while (0);
430
431/*
432 * pktavail interrupts from dongle to host can be managed in 3 different ways
433 * whenever there is a packet available in dongle to transmit to host.
434 *
435 * Mode 0: Dongle writes the software host mailbox and host is interrupted.
436 * Mode 1: (sdiod core rev >= 4)
437 * Device sets a new bit in the intstatus whenever there is a packet
438 * available in fifo. Host can't clear this specific status bit until all the
439 * packets are read from the FIFO. No need to ack dongle intstatus.
440 * Mode 2: (sdiod core rev >= 4)
441 * Device sets a bit in the intstatus, and host acks this by writing
442 * one to this bit. Dongle won't generate anymore packet interrupts
443 * until host reads all the packets from the dongle and reads a zero to
444 * figure that there are no more packets. No need to disable host ints.
445 * Need to ack the intstatus.
446 */
447
448#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */
449#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */
450#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */
451
452
453#define FRAME_AVAIL_MASK(bus) \
454 ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL)
455
456#define DHD_BUS SDIO_BUS
457
458#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus)))
459
460#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
461
462#define GSPI_PR55150_BAILOUT
463
464
465#ifdef SDTEST
466static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
467static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count);
468#endif
469
470#ifdef DHD_DEBUG
471static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size);
472static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror);
473#endif /* DHD_DEBUG */
474
475static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
476
477static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
478static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
479static void dhdsdio_disconnect(void *ptr);
480static bool dhdsdio_chipmatch(uint16 chipid);
481static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
482 void * regsva, uint16 devid);
483static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
484static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
485static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation,
486 bool reset_flag);
487
488static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size);
489static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
490 uint8 *buf, uint nbytes,
491 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
492static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
493 uint8 *buf, uint nbytes,
494 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
495
496static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh);
497static int _dhdsdio_download_firmware(dhd_bus_t *bus);
498
499static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path);
500static int dhdsdio_download_nvram(dhd_bus_t *bus);
501#ifdef BCMEMBEDIMAGE
502static int dhdsdio_download_code_array(dhd_bus_t *bus);
503#endif
504
505#ifdef WLMEDIA_HTSF
506#include <htsf.h>
507extern uint32 dhd_get_htsf(void *dhd, int ifidx);
508#endif /* WLMEDIA_HTSF */
509
510static void
511dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
512{
513 int32 min_size = DONGLE_MIN_MEMSIZE;
514 /* Restrict the memsize to user specified limit */
515 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
516 dhd_dongle_memsize, min_size));
517 if ((dhd_dongle_memsize > min_size) &&
518 (dhd_dongle_memsize < (int32)bus->orig_ramsize))
519 bus->ramsize = dhd_dongle_memsize;
520}
521
522static int
523dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
524{
525 int err = 0;
526 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
527 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
528 if (!err)
529 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
530 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
531 if (!err)
532 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
533 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
534 return err;
535}
536
537
538/* Turn backplane clock on or off */
539static int
540dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
541{
542 int err;
543 uint8 clkctl, clkreq, devctl;
544 bcmsdh_info_t *sdh;
545
546 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
547
548#if defined(OOB_INTR_ONLY)
549 pendok = FALSE;
550#endif
551 clkctl = 0;
552 sdh = bus->sdh;
553
554
555 if (on) {
556 /* Request HT Avail */
557 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
558
559
560
561
562 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
563 if (err) {
564 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
565 return BCME_ERROR;
566 }
567
568 if (pendok &&
569 ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) {
570 uint32 dummy, retries;
571 R_SDREG(dummy, &bus->regs->clockctlstatus, retries);
572 }
573
574 /* Check current status */
575 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
576 if (err) {
577 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
578 return BCME_ERROR;
579 }
580
581 /* Go to pending and await interrupt if appropriate */
582 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
583 /* Allow only clock-available interrupt */
584 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
585 if (err) {
586 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
587 __FUNCTION__, err));
588 return BCME_ERROR;
589 }
590
591 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
592 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
593 DHD_INFO(("CLKCTL: set PENDING\n"));
594 bus->clkstate = CLK_PENDING;
595 return BCME_OK;
596 } else if (bus->clkstate == CLK_PENDING) {
597 /* Cancel CA-only interrupt filter */
598 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
599 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
600 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
601 }
602
603 /* Otherwise, wait here (polling) for HT Avail */
604 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
605 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
606 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
607 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
608 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
609 }
610 if (err) {
611 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
612 return BCME_ERROR;
613 }
614 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
615 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
616 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
617 return BCME_ERROR;
618 }
619
620
621 /* Mark clock available */
622 bus->clkstate = CLK_AVAIL;
623 DHD_INFO(("CLKCTL: turned ON\n"));
624
625#if defined(DHD_DEBUG)
626 if (bus->alp_only == TRUE) {
627#if !defined(BCMLXSDMMC)
628 if (!SBSDIO_ALPONLY(clkctl)) {
629 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
630 }
631#endif /* !defined(BCMLXSDMMC) */
632 } else {
633 if (SBSDIO_ALPONLY(clkctl)) {
634 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
635 }
636 }
637#endif /* defined (DHD_DEBUG) */
638
639 bus->activity = TRUE;
640 } else {
641 clkreq = 0;
642
643 if (bus->clkstate == CLK_PENDING) {
644 /* Cancel CA-only interrupt filter */
645 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
646 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
647 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
648 }
649
650 bus->clkstate = CLK_SDONLY;
651 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
652 DHD_INFO(("CLKCTL: turned OFF\n"));
653 if (err) {
654 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
655 __FUNCTION__, err));
656 return BCME_ERROR;
657 }
658 }
659 return BCME_OK;
660}
661
662/* Change idle/active SD state */
663static int
664dhdsdio_sdclk(dhd_bus_t *bus, bool on)
665{
666 int err;
667 int32 iovalue;
668
669 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
670
671 if (on) {
672 if (bus->idleclock == DHD_IDLE_STOP) {
673 /* Turn on clock and restore mode */
674 iovalue = 1;
675 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
676 &iovalue, sizeof(iovalue), TRUE);
677 if (err) {
678 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
679 __FUNCTION__, err));
680 return BCME_ERROR;
681 }
682
683 iovalue = bus->sd_mode;
684 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
685 &iovalue, sizeof(iovalue), TRUE);
686 if (err) {
687 DHD_ERROR(("%s: error changing sd_mode: %d\n",
688 __FUNCTION__, err));
689 return BCME_ERROR;
690 }
691 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
692 /* Restore clock speed */
693 iovalue = bus->sd_divisor;
694 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
695 &iovalue, sizeof(iovalue), TRUE);
696 if (err) {
697 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
698 __FUNCTION__, err));
699 return BCME_ERROR;
700 }
701 }
702 bus->clkstate = CLK_SDONLY;
703 } else {
704 /* Stop or slow the SD clock itself */
705 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
706 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
707 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
708 return BCME_ERROR;
709 }
710 if (bus->idleclock == DHD_IDLE_STOP) {
711 if (sd1idle) {
712 /* Change to SD1 mode and turn off clock */
713 iovalue = 1;
714 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
715 &iovalue, sizeof(iovalue), TRUE);
716 if (err) {
717 DHD_ERROR(("%s: error changing sd_clock: %d\n",
718 __FUNCTION__, err));
719 return BCME_ERROR;
720 }
721 }
722
723 iovalue = 0;
724 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
725 &iovalue, sizeof(iovalue), TRUE);
726 if (err) {
727 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
728 __FUNCTION__, err));
729 return BCME_ERROR;
730 }
731 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
732 /* Set divisor to idle value */
733 iovalue = bus->idleclock;
734 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
735 &iovalue, sizeof(iovalue), TRUE);
736 if (err) {
737 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
738 __FUNCTION__, err));
739 return BCME_ERROR;
740 }
741 }
742 bus->clkstate = CLK_NONE;
743 }
744
745 return BCME_OK;
746}
747
748/* Transition SD and backplane clock readiness */
749static int
750dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
751{
752 int ret = BCME_OK;
753#ifdef DHD_DEBUG
754 uint oldstate = bus->clkstate;
755#endif /* DHD_DEBUG */
756
757 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
758
759 /* Early exit if we're already there */
760 if (bus->clkstate == target) {
761 if (target == CLK_AVAIL) {
762 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
763 bus->activity = TRUE;
764 }
765 return ret;
766 }
767
768 switch (target) {
769 case CLK_AVAIL:
770 /* Make sure SD clock is available */
771 if (bus->clkstate == CLK_NONE)
772 dhdsdio_sdclk(bus, TRUE);
773 /* Now request HT Avail on the backplane */
774 ret = dhdsdio_htclk(bus, TRUE, pendok);
775 if (ret == BCME_OK) {
776 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
777 bus->activity = TRUE;
778 }
779 break;
780
781 case CLK_SDONLY:
782 /* Remove HT request, or bring up SD clock */
783 if (bus->clkstate == CLK_NONE)
784 ret = dhdsdio_sdclk(bus, TRUE);
785 else if (bus->clkstate == CLK_AVAIL)
786 ret = dhdsdio_htclk(bus, FALSE, FALSE);
787 else
788 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
789 bus->clkstate, target));
790 if (ret == BCME_OK) {
791 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
792 }
793 break;
794
795 case CLK_NONE:
796 /* Make sure to remove HT request */
797 if (bus->clkstate == CLK_AVAIL)
798 ret = dhdsdio_htclk(bus, FALSE, FALSE);
799 /* Now remove the SD clock */
800 ret = dhdsdio_sdclk(bus, FALSE);
801#ifdef DHD_DEBUG
802 if (dhd_console_ms == 0)
803#endif /* DHD_DEBUG */
804 dhd_os_wd_timer(bus->dhd, 0);
805 break;
806 }
807#ifdef DHD_DEBUG
808 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
809#endif /* DHD_DEBUG */
810
811 return ret;
812}
813
814static int
815dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
816{
817 bcmsdh_info_t *sdh = bus->sdh;
818 sdpcmd_regs_t *regs = bus->regs;
819 uint retries = 0;
820
821 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
822 (sleep ? "SLEEP" : "WAKE"),
823 (bus->sleeping ? "SLEEP" : "WAKE")));
824
825 /* Done if we're already in the requested state */
826 if (sleep == bus->sleeping)
827 return BCME_OK;
828
829 /* Going to sleep: set the alarm and turn off the lights... */
830 if (sleep) {
831 /* Don't sleep if something is pending */
832 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
833 return BCME_BUSY;
834
835
836 /* Disable SDIO interrupts (no longer interested) */
837 bcmsdh_intr_disable(bus->sdh);
838
839 /* Make sure the controller has the bus up */
840 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
841
842 /* Tell device to start using OOB wakeup */
843 W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
844 if (retries > retry_limit)
845 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
846
847 /* Turn off our contribution to the HT clock request */
848 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
849
850 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
851 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
852
853 /* Isolate the bus */
854 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
855 SBSDIO_DEVCTL_PADS_ISO, NULL);
856
857 /* Change state */
858 bus->sleeping = TRUE;
859
860 } else {
861 /* Waking up: bus power up is ok, set local state */
862
863 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
864 0, NULL);
865
866 /* Force pad isolation off if possible (in case power never toggled) */
867 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
868
869
870 /* Make sure the controller has the bus up */
871 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
872
873 /* Send misc interrupt to indicate OOB not needed */
874 W_SDREG(0, &regs->tosbmailboxdata, retries);
875 if (retries <= retry_limit)
876 W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
877
878 if (retries > retry_limit)
879 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
880
881 /* Make sure we have SD bus access */
882 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
883
884 /* Change state */
885 bus->sleeping = FALSE;
886
887 /* Enable interrupts again */
888 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
889 bus->intdis = FALSE;
890 bcmsdh_intr_enable(bus->sdh);
891 }
892 }
893
894 return BCME_OK;
895}
896
897#if defined(OOB_INTR_ONLY)
898void
899dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
900{
901#if defined(HW_OOB)
902 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
903#else
904 sdpcmd_regs_t *regs = bus->regs;
905 uint retries = 0;
906
907 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
908 if (enable == TRUE) {
909
910 /* Tell device to start using OOB wakeup */
911 W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
912 if (retries > retry_limit)
913 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
914
915 } else {
916 /* Send misc interrupt to indicate OOB not needed */
917 W_SDREG(0, &regs->tosbmailboxdata, retries);
918 if (retries <= retry_limit)
919 W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
920 }
921
922 /* Turn off our contribution to the HT clock request */
923 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
924#endif /* !defined(HW_OOB) */
925}
926#endif /* defined(OOB_INTR_ONLY) */
927
928/* Writes a HW/SW header into the packet and sends it. */
929/* Assumes: (a) header space already there, (b) caller holds lock */
930static int
931dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
932{
933 int ret;
934 osl_t *osh;
935 uint8 *frame;
936 uint16 len, pad1 = 0;
937 uint32 swheader;
938 uint retries = 0;
939 bcmsdh_info_t *sdh;
940 void *new;
941 int i;
942#ifdef WLMEDIA_HTSF
943 char *p;
944 htsfts_t *htsf_ts;
945#endif
946
947
948 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
949
950 sdh = bus->sdh;
951 osh = bus->dhd->osh;
952
953 if (bus->dhd->dongle_reset) {
954 ret = BCME_NOTREADY;
955 goto done;
956 }
957
958 frame = (uint8*)PKTDATA(osh, pkt);
959
960#ifdef WLMEDIA_HTSF
961 if (PKTLEN(osh, pkt) >= 100) {
962 p = PKTDATA(osh, pkt);
963 htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12);
964 if (htsf_ts->magic == HTSFMAGIC) {
965 htsf_ts->c20 = get_cycles();
966 htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0);
967 }
968 }
969#endif /* WLMEDIA_HTSF */
970
971 /* Add alignment padding, allocate new packet if needed */
972 if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) {
973 if (PKTHEADROOM(osh, pkt) < pad1) {
974 DHD_INFO(("%s: insufficient headroom %d for %d pad1\n",
975 __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1));
976 bus->dhd->tx_realloc++;
977 new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
978 if (!new) {
979 DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
980 __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
981 ret = BCME_NOMEM;
982 goto done;
983 }
984
985 PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
986 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
987 if (free_pkt)
988 PKTFREE(osh, pkt, TRUE);
989 /* free the pkt if canned one is not used */
990 free_pkt = TRUE;
991 pkt = new;
992 frame = (uint8*)PKTDATA(osh, pkt);
993 ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
994 pad1 = 0;
995 } else {
996 PKTPUSH(osh, pkt, pad1);
997 frame = (uint8*)PKTDATA(osh, pkt);
998
999 ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
1000 bzero(frame, pad1 + SDPCM_HDRLEN);
1001 }
1002 }
1003 ASSERT(pad1 < DHD_SDALIGN);
1004
1005 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1006 len = (uint16)PKTLEN(osh, pkt);
1007 *(uint16*)frame = htol16(len);
1008 *(((uint16*)frame) + 1) = htol16(~len);
1009
1010 /* Software tag: channel, sequence number, data offset */
1011 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
1012 (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1013 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1014 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1015
1016#ifdef DHD_DEBUG
1017 if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) {
1018 tx_packets[PKTPRIO(pkt)]++;
1019 }
1020 if (DHD_BYTES_ON() &&
1021 (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
1022 (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
1023 prhex("Tx Frame", frame, len);
1024 } else if (DHD_HDRS_ON()) {
1025 prhex("TxHdr", frame, MIN(len, 16));
1026 }
1027#endif
1028
1029 /* Raise len to next SDIO block to eliminate tail command */
1030 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1031 uint16 pad2 = bus->blocksize - (len % bus->blocksize);
1032 if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize))
1033#ifdef NOTUSED
1034 if (pad2 <= PKTTAILROOM(osh, pkt))
1035#endif /* NOTUSED */
1036 len += pad2;
1037 } else if (len % DHD_SDALIGN) {
1038 len += DHD_SDALIGN - (len % DHD_SDALIGN);
1039 }
1040
1041 /* Some controllers have trouble with odd bytes -- round to even */
1042 if (forcealign && (len & (ALIGNMENT - 1))) {
1043#ifdef NOTUSED
1044 if (PKTTAILROOM(osh, pkt))
1045#endif
1046 len = ROUNDUP(len, ALIGNMENT);
1047#ifdef NOTUSED
1048 else
1049 DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
1050#endif
1051 }
1052
1053 do {
1054 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1055 frame, len, pkt, NULL, NULL);
1056 bus->f2txdata++;
1057 ASSERT(ret != BCME_PENDING);
1058
1059 if (ret < 0) {
1060 /* On failure, abort the command and terminate the frame */
1061 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1062 __FUNCTION__, ret));
1063 bus->tx_sderrs++;
1064
1065 bcmsdh_abort(sdh, SDIO_FUNC_2);
1066 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1067 SFC_WF_TERM, NULL);
1068 bus->f1regdata++;
1069
1070 for (i = 0; i < 3; i++) {
1071 uint8 hi, lo;
1072 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1073 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1074 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1075 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1076 bus->f1regdata += 2;
1077 if ((hi == 0) && (lo == 0))
1078 break;
1079 }
1080
1081 }
1082 if (ret == 0) {
1083 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1084 }
1085 } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
1086
1087done:
1088 /* restore pkt buffer pointer before calling tx complete routine */
1089 PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1);
1090#ifdef PROP_TXSTATUS
1091 if (bus->dhd->wlfc_state) {
1092 dhd_os_sdunlock(bus->dhd);
1093 dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0);
1094 dhd_os_sdlock(bus->dhd);
1095 } else {
1096#endif /* PROP_TXSTATUS */
1097 dhd_txcomplete(bus->dhd, pkt, ret != 0);
1098 if (free_pkt)
1099 PKTFREE(osh, pkt, TRUE);
1100
1101#ifdef PROP_TXSTATUS
1102 }
1103#endif
1104 return ret;
1105}
1106
1107int
1108dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1109{
1110 int ret = BCME_ERROR;
1111 osl_t *osh;
1112 uint datalen, prec;
1113
1114 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1115
1116 osh = bus->dhd->osh;
1117 datalen = PKTLEN(osh, pkt);
1118
1119#ifdef SDTEST
1120 /* Push the test header if doing loopback */
1121 if (bus->ext_loop) {
1122 uint8* data;
1123 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1124 data = PKTDATA(osh, pkt);
1125 *data++ = SDPCM_TEST_ECHOREQ;
1126 *data++ = (uint8)bus->loopid++;
1127 *data++ = (datalen >> 0);
1128 *data++ = (datalen >> 8);
1129 datalen += SDPCM_TEST_HDRLEN;
1130 }
1131#endif /* SDTEST */
1132
1133 /* Add space for the header */
1134 PKTPUSH(osh, pkt, SDPCM_HDRLEN);
1135 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
1136
1137 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1138#ifndef DHDTHREAD
1139 /* Lock: we're about to use shared data/code (and SDIO) */
1140 dhd_os_sdlock(bus->dhd);
1141#endif /* DHDTHREAD */
1142
1143 /* Check for existing queue, current flow-control, pending event, or pending clock */
1144 if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
1145 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
1146 (bus->clkstate != CLK_AVAIL)) {
1147 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
1148 pktq_len(&bus->txq)));
1149 bus->fcqueued++;
1150
1151 /* Priority based enq */
1152 dhd_os_sdlock_txq(bus->dhd);
1153 if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
1154 PKTPULL(osh, pkt, SDPCM_HDRLEN);
1155#ifndef DHDTHREAD
1156 /* Need to also release txqlock before releasing sdlock.
1157 * This thread still has txqlock and releases sdlock.
1158 * Deadlock happens when dpc() grabs sdlock first then
1159 * attempts to grab txqlock.
1160 */
1161 dhd_os_sdunlock_txq(bus->dhd);
1162 dhd_os_sdunlock(bus->dhd);
1163#endif
1164#ifdef PROP_TXSTATUS
1165 if (bus->dhd->wlfc_state)
1166 dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE);
1167 else
1168#endif
1169 dhd_txcomplete(bus->dhd, pkt, FALSE);
1170#ifndef DHDTHREAD
1171 dhd_os_sdlock(bus->dhd);
1172 dhd_os_sdlock_txq(bus->dhd);
1173#endif
1174#ifdef PROP_TXSTATUS
1175 /* let the caller decide whether to free the packet */
1176 if (!bus->dhd->wlfc_state)
1177#endif
1178 PKTFREE(osh, pkt, TRUE);
1179 ret = BCME_NORESOURCE;
1180 }
1181 else
1182 ret = BCME_OK;
1183 dhd_os_sdunlock_txq(bus->dhd);
1184
1185 if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
1186 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
1187
1188#ifdef DHD_DEBUG
1189 if (pktq_plen(&bus->txq, prec) > qcount[prec])
1190 qcount[prec] = pktq_plen(&bus->txq, prec);
1191#endif
1192 /* Schedule DPC if needed to send queued packet(s) */
1193 if (dhd_deferred_tx && !bus->dpc_sched) {
1194 bus->dpc_sched = TRUE;
1195 dhd_sched_dpc(bus->dhd);
1196 }
1197 } else {
1198#ifdef DHDTHREAD
1199 /* Lock: we're about to use shared data/code (and SDIO) */
1200 dhd_os_sdlock(bus->dhd);
1201#endif /* DHDTHREAD */
1202
1203 /* Otherwise, send it now */
1204 BUS_WAKE(bus);
1205 /* Make sure back plane ht clk is on, no pending allowed */
1206 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
1207#ifndef SDTEST
1208 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1209#else
1210 ret = dhdsdio_txpkt(bus, pkt,
1211 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1212#endif
1213 if (ret)
1214 bus->dhd->tx_errors++;
1215 else
1216 bus->dhd->dstats.tx_bytes += datalen;
1217
1218 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1219 bus->activity = FALSE;
1220 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1221 }
1222
1223#ifdef DHDTHREAD
1224 dhd_os_sdunlock(bus->dhd);
1225#endif /* DHDTHREAD */
1226 }
1227
1228#ifndef DHDTHREAD
1229 dhd_os_sdunlock(bus->dhd);
1230#endif /* DHDTHREAD */
1231
1232 return ret;
1233}
1234
1235static uint
1236dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
1237{
1238 void *pkt;
1239 uint32 intstatus = 0;
1240 uint retries = 0;
1241 int ret = 0, prec_out;
1242 uint cnt = 0;
1243 uint datalen;
1244 uint8 tx_prec_map;
1245
1246 dhd_pub_t *dhd = bus->dhd;
1247 sdpcmd_regs_t *regs = bus->regs;
1248
1249 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1250
1251 tx_prec_map = ~bus->flowcontrol;
1252
1253 /* Send frames until the limit or some other event */
1254 for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
1255 dhd_os_sdlock_txq(bus->dhd);
1256 if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
1257 dhd_os_sdunlock_txq(bus->dhd);
1258 break;
1259 }
1260 dhd_os_sdunlock_txq(bus->dhd);
1261 datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
1262
1263#ifndef SDTEST
1264 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1265#else
1266 ret = dhdsdio_txpkt(bus, pkt,
1267 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1268#endif
1269 if (ret)
1270 bus->dhd->tx_errors++;
1271 else
1272 bus->dhd->dstats.tx_bytes += datalen;
1273
1274 /* In poll mode, need to check for other events */
1275 if (!bus->intr && cnt)
1276 {
1277 /* Check device status, signal pending interrupt */
1278 R_SDREG(intstatus, &regs->intstatus, retries);
1279 bus->f2txdata++;
1280 if (bcmsdh_regfail(bus->sdh))
1281 break;
1282 if (intstatus & bus->hostintmask)
1283 bus->ipend = TRUE;
1284 }
1285 }
1286
1287 /* Deflow-control stack if needed */
1288 if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
1289 dhd->txoff && (pktq_len(&bus->txq) < FCLOW))
1290 dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF);
1291
1292 return cnt;
1293}
1294
1295int
1296dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1297{
1298 uint8 *frame;
1299 uint16 len;
1300 uint32 swheader;
1301 uint retries = 0;
1302 bcmsdh_info_t *sdh = bus->sdh;
1303 uint8 doff = 0;
1304 int ret = -1;
1305 int i;
1306
1307 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1308
1309 if (bus->dhd->dongle_reset)
1310 return -EIO;
1311
1312 /* Back the pointer to make a room for bus header */
1313 frame = msg - SDPCM_HDRLEN;
1314 len = (msglen += SDPCM_HDRLEN);
1315
1316 /* Add alignment padding (optional for ctl frames) */
1317 if (dhd_alignctl) {
1318 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
1319 frame -= doff;
1320 len += doff;
1321 msglen += doff;
1322 bzero(frame, doff + SDPCM_HDRLEN);
1323 }
1324 ASSERT(doff < DHD_SDALIGN);
1325 }
1326 doff += SDPCM_HDRLEN;
1327
1328 /* Round send length to next SDIO block */
1329 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1330 uint16 pad = bus->blocksize - (len % bus->blocksize);
1331 if ((pad <= bus->roundup) && (pad < bus->blocksize))
1332 len += pad;
1333 } else if (len % DHD_SDALIGN) {
1334 len += DHD_SDALIGN - (len % DHD_SDALIGN);
1335 }
1336
1337 /* Satisfy length-alignment requirements */
1338 if (forcealign && (len & (ALIGNMENT - 1)))
1339 len = ROUNDUP(len, ALIGNMENT);
1340
1341 ASSERT(ISALIGNED((uintptr)frame, 2));
1342
1343
1344 /* Need to lock here to protect txseq and SDIO tx calls */
1345 dhd_os_sdlock(bus->dhd);
1346
1347 BUS_WAKE(bus);
1348
1349 /* Make sure backplane clock is on */
1350 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1351
1352 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1353 *(uint16*)frame = htol16((uint16)msglen);
1354 *(((uint16*)frame) + 1) = htol16(~msglen);
1355
1356 /* Software tag: channel, sequence number, data offset */
1357 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
1358 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1359 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1360 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1361
1362 if (!TXCTLOK(bus)) {
1363 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
1364 __FUNCTION__, bus->tx_max, bus->tx_seq));
1365 bus->ctrl_frame_stat = TRUE;
1366 /* Send from dpc */
1367 bus->ctrl_frame_buf = frame;
1368 bus->ctrl_frame_len = len;
1369
1370 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
1371
1372 if (bus->ctrl_frame_stat == FALSE) {
1373 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
1374 ret = 0;
1375 } else {
1376 bus->dhd->txcnt_timeout++;
1377 if (!bus->dhd->hang_was_sent)
1378 DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n",
1379 __FUNCTION__, bus->dhd->txcnt_timeout));
1380 ret = -1;
1381 bus->ctrl_frame_stat = FALSE;
1382 goto done;
1383 }
1384 }
1385
1386 bus->dhd->txcnt_timeout = 0;
1387
1388 if (ret == -1) {
1389#ifdef DHD_DEBUG
1390 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
1391 prhex("Tx Frame", frame, len);
1392 } else if (DHD_HDRS_ON()) {
1393 prhex("TxHdr", frame, MIN(len, 16));
1394 }
1395#endif
1396
1397 do {
1398 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1399 frame, len, NULL, NULL, NULL);
1400 ASSERT(ret != BCME_PENDING);
1401
1402 if (ret < 0) {
1403 /* On failure, abort the command and terminate the frame */
1404 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1405 __FUNCTION__, ret));
1406 bus->tx_sderrs++;
1407
1408 bcmsdh_abort(sdh, SDIO_FUNC_2);
1409
1410 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1411 SFC_WF_TERM, NULL);
1412 bus->f1regdata++;
1413
1414 for (i = 0; i < 3; i++) {
1415 uint8 hi, lo;
1416 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1417 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1418 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1419 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1420 bus->f1regdata += 2;
1421 if ((hi == 0) && (lo == 0))
1422 break;
1423 }
1424
1425 }
1426 if (ret == 0) {
1427 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1428 }
1429 } while ((ret < 0) && retries++ < TXRETRIES);
1430 }
1431
1432done:
1433 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1434 bus->activity = FALSE;
1435 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1436 }
1437
1438 dhd_os_sdunlock(bus->dhd);
1439
1440 if (ret)
1441 bus->dhd->tx_ctlerrs++;
1442 else
1443 bus->dhd->tx_ctlpkts++;
1444
1445 if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT)
1446 return -ETIMEDOUT;
1447
1448 return ret ? -EIO : 0;
1449}
1450
1451int
1452dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1453{
1454 int timeleft;
1455 uint rxlen = 0;
1456 bool pending;
1457
1458 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1459
1460 if (bus->dhd->dongle_reset)
1461 return -EIO;
1462
1463 /* Wait until control frame is available */
1464 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
1465
1466 dhd_os_sdlock(bus->dhd);
1467 rxlen = bus->rxlen;
1468 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
1469 bus->rxlen = 0;
1470 dhd_os_sdunlock(bus->dhd);
1471
1472 if (rxlen) {
1473 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
1474 __FUNCTION__, rxlen, msglen));
1475 } else if (timeleft == 0) {
1476 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
1477#ifdef DHD_DEBUG
1478 dhd_os_sdlock(bus->dhd);
1479 dhdsdio_checkdied(bus, NULL, 0);
1480 dhd_os_sdunlock(bus->dhd);
1481#endif /* DHD_DEBUG */
1482 } else if (pending == TRUE) {
1483 DHD_CTL(("%s: canceled\n", __FUNCTION__));
1484 return -ERESTARTSYS;
1485 } else {
1486 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
1487#ifdef DHD_DEBUG
1488 dhd_os_sdlock(bus->dhd);
1489 dhdsdio_checkdied(bus, NULL, 0);
1490 dhd_os_sdunlock(bus->dhd);
1491#endif /* DHD_DEBUG */
1492 }
1493 if (timeleft == 0) {
1494 bus->dhd->rxcnt_timeout++;
1495 DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout));
1496 }
1497 else
1498 bus->dhd->rxcnt_timeout = 0;
1499
1500 if (rxlen)
1501 bus->dhd->rx_ctlpkts++;
1502 else
1503 bus->dhd->rx_ctlerrs++;
1504
1505 if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT)
1506 return -ETIMEDOUT;
1507
1508 return rxlen ? (int)rxlen : -EIO;
1509}
1510
1511/* IOVar table */
1512enum {
1513 IOV_INTR = 1,
1514 IOV_POLLRATE,
1515 IOV_SDREG,
1516 IOV_SBREG,
1517 IOV_SDCIS,
1518 IOV_MEMBYTES,
1519 IOV_MEMSIZE,
1520#ifdef DHD_DEBUG
1521 IOV_CHECKDIED,
1522 IOV_SERIALCONS,
1523#endif
1524 IOV_DOWNLOAD,
1525 IOV_SOCRAM_STATE,
1526 IOV_FORCEEVEN,
1527 IOV_SDIOD_DRIVE,
1528 IOV_READAHEAD,
1529 IOV_SDRXCHAIN,
1530 IOV_ALIGNCTL,
1531 IOV_SDALIGN,
1532 IOV_DEVRESET,
1533 IOV_CPU,
1534#ifdef SDTEST
1535 IOV_PKTGEN,
1536 IOV_EXTLOOP,
1537#endif /* SDTEST */
1538 IOV_SPROM,
1539 IOV_TXBOUND,
1540 IOV_RXBOUND,
1541 IOV_TXMINMAX,
1542 IOV_IDLETIME,
1543 IOV_IDLECLOCK,
1544 IOV_SD1IDLE,
1545 IOV_SLEEP,
1546 IOV_DONGLEISOLATION,
1547 IOV_VARS,
1548#ifdef SOFTAP
1549 IOV_FWPATH
1550#endif
1551};
1552
1553const bcm_iovar_t dhdsdio_iovars[] = {
1554 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
1555 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
1556 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
1557 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
1558 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
1559 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
1560 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
1561 {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 },
1562 {"download", IOV_DOWNLOAD, 0, IOVT_BOOL, 0 },
1563 {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 },
1564 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
1565 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
1566 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
1567 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
1568 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
1569 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
1570 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
1571#ifdef DHD_DEBUG
1572 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
1573 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
1574 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
1575 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
1576 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
1577 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
1578 {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
1579 {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
1580#ifdef DHD_DEBUG
1581 {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
1582 {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 },
1583#endif /* DHD_DEBUG */
1584#endif /* DHD_DEBUG */
1585#ifdef SDTEST
1586 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
1587 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
1588#endif /* SDTEST */
1589 {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 },
1590#ifdef SOFTAP
1591 {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 },
1592#endif
1593 {NULL, 0, 0, 0, 0 }
1594};
1595
1596static void
1597dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
1598{
1599 uint q1, q2;
1600
1601 if (!div) {
1602 bcm_bprintf(strbuf, "%s N/A", desc);
1603 } else {
1604 q1 = num / div;
1605 q2 = (100 * (num - (q1 * div))) / div;
1606 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
1607 }
1608}
1609
1610void
1611dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
1612{
1613 dhd_bus_t *bus = dhdp->bus;
1614
1615 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
1616 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
1617 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
1618 bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n",
1619 bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
1620 bus->rxlen, bus->rx_seq);
1621 bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n",
1622 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
1623 bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n",
1624 bus->pollrate, bus->pollcnt, bus->regfails);
1625
1626 bcm_bprintf(strbuf, "\nAdditional counters:\n");
1627 bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n",
1628 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
1629 bus->rxc_errors);
1630 bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n",
1631 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
1632 bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n",
1633 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
1634 bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n",
1635 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
1636 bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n",
1637 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
1638 bus->f2txdata, bus->f1regdata);
1639 {
1640 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
1641 (bus->f2rxhdrs + bus->f2rxdata));
1642 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
1643 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
1644 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1645 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
1646 bcm_bprintf(strbuf, "\n");
1647
1648 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
1649 bus->dhd->rx_packets);
1650 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
1651 bcm_bprintf(strbuf, "\n");
1652
1653 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
1654 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
1655 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
1656 (bus->f2txdata + bus->f1regdata));
1657 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
1658 bcm_bprintf(strbuf, "\n");
1659
1660 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
1661 (bus->dhd->tx_packets + bus->dhd->rx_packets),
1662 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
1663 dhd_dump_pct(strbuf, ", pkts/f1sd",
1664 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
1665 dhd_dump_pct(strbuf, ", pkts/sd",
1666 (bus->dhd->tx_packets + bus->dhd->rx_packets),
1667 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1668 dhd_dump_pct(strbuf, ", pkts/int",
1669 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
1670 bcm_bprintf(strbuf, "\n\n");
1671 }
1672
1673#ifdef SDTEST
1674 if (bus->pktgen_count) {
1675 bcm_bprintf(strbuf, "pktgen config and count:\n");
1676 bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n",
1677 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
1678 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
1679 bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n",
1680 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
1681 }
1682#endif /* SDTEST */
1683#ifdef DHD_DEBUG
1684 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
1685 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
1686 bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup);
1687#endif /* DHD_DEBUG */
1688 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
1689 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
1690}
1691
1692void
1693dhd_bus_clearcounts(dhd_pub_t *dhdp)
1694{
1695 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
1696
1697 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
1698 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
1699 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
1700 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
1701 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
1702 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
1703}
1704
1705#ifdef SDTEST
1706static int
1707dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
1708{
1709 dhd_pktgen_t pktgen;
1710
1711 pktgen.version = DHD_PKTGEN_VERSION;
1712 pktgen.freq = bus->pktgen_freq;
1713 pktgen.count = bus->pktgen_count;
1714 pktgen.print = bus->pktgen_print;
1715 pktgen.total = bus->pktgen_total;
1716 pktgen.minlen = bus->pktgen_minlen;
1717 pktgen.maxlen = bus->pktgen_maxlen;
1718 pktgen.numsent = bus->pktgen_sent;
1719 pktgen.numrcvd = bus->pktgen_rcvd;
1720 pktgen.numfail = bus->pktgen_fail;
1721 pktgen.mode = bus->pktgen_mode;
1722 pktgen.stop = bus->pktgen_stop;
1723
1724 bcopy(&pktgen, arg, sizeof(pktgen));
1725
1726 return 0;
1727}
1728
1729static int
1730dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
1731{
1732 dhd_pktgen_t pktgen;
1733 uint oldcnt, oldmode;
1734
1735 bcopy(arg, &pktgen, sizeof(pktgen));
1736 if (pktgen.version != DHD_PKTGEN_VERSION)
1737 return BCME_BADARG;
1738
1739 oldcnt = bus->pktgen_count;
1740 oldmode = bus->pktgen_mode;
1741
1742 bus->pktgen_freq = pktgen.freq;
1743 bus->pktgen_count = pktgen.count;
1744 bus->pktgen_print = pktgen.print;
1745 bus->pktgen_total = pktgen.total;
1746 bus->pktgen_minlen = pktgen.minlen;
1747 bus->pktgen_maxlen = pktgen.maxlen;
1748 bus->pktgen_mode = pktgen.mode;
1749 bus->pktgen_stop = pktgen.stop;
1750
1751 bus->pktgen_tick = bus->pktgen_ptick = 0;
1752 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
1753 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
1754
1755 /* Clear counts for a new pktgen (mode change, or was stopped) */
1756 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode))
1757 bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0;
1758
1759 return 0;
1760}
1761#endif /* SDTEST */
1762
1763static int
1764dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
1765{
1766 int bcmerror = 0;
1767 uint32 sdaddr;
1768 uint dsize;
1769
1770 /* Determine initial transfer parameters */
1771 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
1772 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
1773 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
1774 else
1775 dsize = size;
1776
1777 /* Set the backplane window to include the start address */
1778 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1779 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1780 goto xfer_done;
1781 }
1782
1783 /* Do the transfer(s) */
1784 while (size) {
1785 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
1786 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
1787 (address & SBSDIO_SBWINDOW_MASK)));
1788 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
1789 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
1790 break;
1791 }
1792
1793 /* Adjust for next transfer (if any) */
1794 if ((size -= dsize)) {
1795 data += dsize;
1796 address += dsize;
1797 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1798 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1799 break;
1800 }
1801 sdaddr = 0;
1802 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
1803 }
1804
1805 }
1806
1807xfer_done:
1808 /* Return the window to backplane enumeration space for core access */
1809 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
1810 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
1811 bcmsdh_cur_sbwad(bus->sdh)));
1812 }
1813
1814 return bcmerror;
1815}
1816
1817#ifdef DHD_DEBUG
1818static int
1819dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
1820{
1821 uint32 addr;
1822 int rv;
1823
1824 /* Read last word in memory to determine address of sdpcm_shared structure */
1825 if ((rv = dhdsdio_membytes(bus, FALSE, bus->ramsize - 4, (uint8 *)&addr, 4)) < 0)
1826 return rv;
1827
1828 addr = ltoh32(addr);
1829
1830 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
1831
1832 /*
1833 * Check if addr is valid.
1834 * NVRAM length at the end of memory should have been overwritten.
1835 */
1836 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
1837 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", __FUNCTION__, addr));
1838 return BCME_ERROR;
1839 }
1840
1841 /* Read hndrte_shared structure */
1842 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
1843 return rv;
1844
1845 /* Endianness */
1846 sh->flags = ltoh32(sh->flags);
1847 sh->trap_addr = ltoh32(sh->trap_addr);
1848 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
1849 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
1850 sh->assert_line = ltoh32(sh->assert_line);
1851 sh->console_addr = ltoh32(sh->console_addr);
1852 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
1853
1854 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1)
1855 return BCME_OK;
1856
1857 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
1858 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
1859 "is different than sdpcm_shared version %d in dongle\n",
1860 __FUNCTION__, SDPCM_SHARED_VERSION,
1861 sh->flags & SDPCM_SHARED_VERSION_MASK));
1862 return BCME_ERROR;
1863 }
1864
1865 return BCME_OK;
1866}
1867
1868
1869static int
1870dhdsdio_readconsole(dhd_bus_t *bus)
1871{
1872 dhd_console_t *c = &bus->console;
1873 uint8 line[CONSOLE_LINE_MAX], ch;
1874 uint32 n, idx, addr;
1875 int rv;
1876
1877 /* Don't do anything until FWREADY updates console address */
1878 if (bus->console_addr == 0)
1879 return 0;
1880
1881 /* Read console log struct */
1882 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
1883 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
1884 return rv;
1885
1886 /* Allocate console buffer (one time only) */
1887 if (c->buf == NULL) {
1888 c->bufsize = ltoh32(c->log.buf_size);
1889 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
1890 return BCME_NOMEM;
1891 }
1892
1893 idx = ltoh32(c->log.idx);
1894
1895 /* Protect against corrupt value */
1896 if (idx > c->bufsize)
1897 return BCME_ERROR;
1898
1899 /* Skip reading the console buffer if the index pointer has not moved */
1900 if (idx == c->last)
1901 return BCME_OK;
1902
1903 /* Read the console buffer */
1904 addr = ltoh32(c->log.buf);
1905 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
1906 return rv;
1907
1908 while (c->last != idx) {
1909 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
1910 if (c->last == idx) {
1911 /* This would output a partial line. Instead, back up
1912 * the buffer pointer and output this line next time around.
1913 */
1914 if (c->last >= n)
1915 c->last -= n;
1916 else
1917 c->last = c->bufsize - n;
1918 goto break2;
1919 }
1920 ch = c->buf[c->last];
1921 c->last = (c->last + 1) % c->bufsize;
1922 if (ch == '\n')
1923 break;
1924 line[n] = ch;
1925 }
1926
1927 if (n > 0) {
1928 if (line[n - 1] == '\r')
1929 n--;
1930 line[n] = 0;
1931 printf("CONSOLE: %s\n", line);
1932 }
1933 }
1934break2:
1935
1936 return BCME_OK;
1937}
1938
1939static int
1940dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size)
1941{
1942 int bcmerror = 0;
1943 uint msize = 512;
1944 char *mbuffer = NULL;
1945 char *console_buffer = NULL;
1946 uint maxstrlen = 256;
1947 char *str = NULL;
1948 trap_t tr;
1949 sdpcm_shared_t sdpcm_shared;
1950 struct bcmstrbuf strbuf;
1951 uint32 console_ptr, console_size, console_index;
1952 uint8 line[CONSOLE_LINE_MAX], ch;
1953 uint32 n, i, addr;
1954 int rv;
1955
1956 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1957
1958 if (data == NULL) {
1959 /*
1960 * Called after a rx ctrl timeout. "data" is NULL.
1961 * allocate memory to trace the trap or assert.
1962 */
1963 size = msize;
1964 mbuffer = data = MALLOC(bus->dhd->osh, msize);
1965 if (mbuffer == NULL) {
1966 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
1967 bcmerror = BCME_NOMEM;
1968 goto done;
1969 }
1970 }
1971
1972 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
1973 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
1974 bcmerror = BCME_NOMEM;
1975 goto done;
1976 }
1977
1978 if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
1979 goto done;
1980
1981 bcm_binit(&strbuf, data, size);
1982
1983 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
1984 sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
1985
1986 if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
1987 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
1988 * (Avoids conflict with real asserts for programmatic parsing of output.)
1989 */
1990 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
1991 }
1992
1993 if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
1994 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
1995 * (Avoids conflict with real asserts for programmatic parsing of output.)
1996 */
1997 bcm_bprintf(&strbuf, "No trap%s in dongle",
1998 (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
1999 ?"/assrt" :"");
2000 } else {
2001 if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
2002 /* Download assert */
2003 bcm_bprintf(&strbuf, "Dongle assert");
2004 if (sdpcm_shared.assert_exp_addr != 0) {
2005 str[0] = '\0';
2006 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
2007 sdpcm_shared.assert_exp_addr,
2008 (uint8 *)str, maxstrlen)) < 0)
2009 goto done;
2010
2011 str[maxstrlen - 1] = '\0';
2012 bcm_bprintf(&strbuf, " expr \"%s\"", str);
2013 }
2014
2015 if (sdpcm_shared.assert_file_addr != 0) {
2016 str[0] = '\0';
2017 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
2018 sdpcm_shared.assert_file_addr,
2019 (uint8 *)str, maxstrlen)) < 0)
2020 goto done;
2021
2022 str[maxstrlen - 1] = '\0';
2023 bcm_bprintf(&strbuf, " file \"%s\"", str);
2024 }
2025
2026 bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
2027 }
2028
2029 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
2030 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
2031 sdpcm_shared.trap_addr,
2032 (uint8*)&tr, sizeof(trap_t))) < 0)
2033 goto done;
2034
2035 bcm_bprintf(&strbuf,
2036 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
2037 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
2038 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, "
2039 "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n",
2040 ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr),
2041 ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc),
2042 ltoh32(sdpcm_shared.trap_addr),
2043 ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3),
2044 ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7));
2045
2046 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log);
2047 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
2048 (uint8 *)&console_ptr, sizeof(console_ptr))) < 0)
2049 goto printbuf;
2050
2051 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size);
2052 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
2053 (uint8 *)&console_size, sizeof(console_size))) < 0)
2054 goto printbuf;
2055
2056 addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx);
2057 if ((rv = dhdsdio_membytes(bus, FALSE, addr,
2058 (uint8 *)&console_index, sizeof(console_index))) < 0)
2059 goto printbuf;
2060
2061 console_ptr = ltoh32(console_ptr);
2062 console_size = ltoh32(console_size);
2063 console_index = ltoh32(console_index);
2064
2065 if (console_size > CONSOLE_BUFFER_MAX ||
2066 !(console_buffer = MALLOC(bus->dhd->osh, console_size)))
2067 goto printbuf;
2068
2069 if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr,
2070 (uint8 *)console_buffer, console_size)) < 0)
2071 goto printbuf;
2072
2073 for (i = 0, n = 0; i < console_size; i += n + 1) {
2074 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
2075 ch = console_buffer[(console_index + i + n) % console_size];
2076 if (ch == '\n')
2077 break;
2078 line[n] = ch;
2079 }
2080
2081
2082 if (n > 0) {
2083 if (line[n - 1] == '\r')
2084 n--;
2085 line[n] = 0;
2086 /* Don't use DHD_ERROR macro since we print
2087 * a lot of information quickly. The macro
2088 * will truncate a lot of the printfs
2089 */
2090
2091 if (dhd_msg_level & DHD_ERROR_VAL) {
2092 printf("CONSOLE: %s\n", line);
2093 DHD_BLOG(line, strlen(line) + 1);
2094 }
2095 }
2096 }
2097 }
2098 }
2099
2100printbuf:
2101 if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
2102 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
2103 }
2104
2105
2106done:
2107 if (mbuffer)
2108 MFREE(bus->dhd->osh, mbuffer, msize);
2109 if (str)
2110 MFREE(bus->dhd->osh, str, maxstrlen);
2111 if (console_buffer)
2112 MFREE(bus->dhd->osh, console_buffer, console_size);
2113
2114 return bcmerror;
2115}
2116#endif /* #ifdef DHD_DEBUG */
2117
2118
2119int
2120dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
2121{
2122 int bcmerror = BCME_OK;
2123
2124 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2125
2126 /* Basic sanity checks */
2127 if (bus->dhd->up) {
2128 bcmerror = BCME_NOTDOWN;
2129 goto err;
2130 }
2131 if (!len) {
2132 bcmerror = BCME_BUFTOOSHORT;
2133 goto err;
2134 }
2135
2136 /* Free the old ones and replace with passed variables */
2137 if (bus->vars)
2138 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
2139
2140 bus->vars = MALLOC(bus->dhd->osh, len);
2141 bus->varsz = bus->vars ? len : 0;
2142 if (bus->vars == NULL) {
2143 bcmerror = BCME_NOMEM;
2144 goto err;
2145 }
2146
2147 /* Copy the passed variables, which should include the terminating double-null */
2148 bcopy(arg, bus->vars, bus->varsz);
2149err:
2150 return bcmerror;
2151}
2152
2153#ifdef DHD_DEBUG
2154
2155#define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24)
2156static int
2157dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror)
2158{
2159 int int_val;
2160 uint32 addr, data;
2161
2162
2163 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr);
2164 data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data);
2165 *bcmerror = 0;
2166
2167 bcmsdh_reg_write(bus->sdh, addr, 4, 1);
2168 if (bcmsdh_regfail(bus->sdh)) {
2169 *bcmerror = BCME_SDIO_ERROR;
2170 return -1;
2171 }
2172 int_val = bcmsdh_reg_read(bus->sdh, data, 4);
2173 if (bcmsdh_regfail(bus->sdh)) {
2174 *bcmerror = BCME_SDIO_ERROR;
2175 return -1;
2176 }
2177 if (!set)
2178 return (int_val & CC_PLL_CHIPCTRL_SERIAL_ENAB);
2179 if (enable)
2180 int_val |= CC_PLL_CHIPCTRL_SERIAL_ENAB;
2181 else
2182 int_val &= ~CC_PLL_CHIPCTRL_SERIAL_ENAB;
2183 bcmsdh_reg_write(bus->sdh, data, 4, int_val);
2184 if (bcmsdh_regfail(bus->sdh)) {
2185 *bcmerror = BCME_SDIO_ERROR;
2186 return -1;
2187 }
2188 if (bus->sih->chip == BCM4330_CHIP_ID) {
2189 uint32 chipcontrol;
2190 addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol);
2191 chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4);
2192 chipcontrol &= ~0x8;
2193 if (enable) {
2194 chipcontrol |= 0x8;
2195 chipcontrol &= ~0x3;
2196 }
2197 bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol);
2198 }
2199
2200 return (int_val & CC_PLL_CHIPCTRL_SERIAL_ENAB);
2201}
2202#endif
2203
2204static int
2205dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
2206 void *params, int plen, void *arg, int len, int val_size)
2207{
2208 int bcmerror = 0;
2209 int32 int_val = 0;
2210 bool bool_val = 0;
2211
2212 DHD_ERROR(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
2213 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
2214
2215 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
2216 goto exit;
2217
2218 if (plen >= (int)sizeof(int_val))
2219 bcopy(params, &int_val, sizeof(int_val));
2220
2221 bool_val = (int_val != 0) ? TRUE : FALSE;
2222
2223
2224 /* Some ioctls use the bus */
2225 dhd_os_sdlock(bus->dhd);
2226
2227 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
2228 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
2229 actionid == IOV_GVAL(IOV_DEVRESET))) {
2230 bcmerror = BCME_NOTREADY;
2231 goto exit;
2232 }
2233
2234 /* Handle sleep stuff before any clock mucking */
2235 if (vi->varid == IOV_SLEEP) {
2236 if (IOV_ISSET(actionid)) {
2237 bcmerror = dhdsdio_bussleep(bus, bool_val);
2238 } else {
2239 int_val = (int32)bus->sleeping;
2240 bcopy(&int_val, arg, val_size);
2241 }
2242 goto exit;
2243 }
2244
2245 /* Request clock to allow SDIO accesses */
2246 if (!bus->dhd->dongle_reset) {
2247 BUS_WAKE(bus);
2248 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2249 }
2250
2251 switch (actionid) {
2252 case IOV_GVAL(IOV_INTR):
2253 int_val = (int32)bus->intr;
2254 bcopy(&int_val, arg, val_size);
2255 break;
2256
2257 case IOV_SVAL(IOV_INTR):
2258 bus->intr = bool_val;
2259 bus->intdis = FALSE;
2260 if (bus->dhd->up) {
2261 if (bus->intr) {
2262 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
2263 bcmsdh_intr_enable(bus->sdh);
2264 } else {
2265 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
2266 bcmsdh_intr_disable(bus->sdh);
2267 }
2268 }
2269 break;
2270
2271 case IOV_GVAL(IOV_POLLRATE):
2272 int_val = (int32)bus->pollrate;
2273 bcopy(&int_val, arg, val_size);
2274 break;
2275
2276 case IOV_SVAL(IOV_POLLRATE):
2277 bus->pollrate = (uint)int_val;
2278 bus->poll = (bus->pollrate != 0);
2279 break;
2280
2281 case IOV_GVAL(IOV_IDLETIME):
2282 int_val = bus->idletime;
2283 bcopy(&int_val, arg, val_size);
2284 break;
2285
2286 case IOV_SVAL(IOV_IDLETIME):
2287 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
2288 bcmerror = BCME_BADARG;
2289 } else {
2290 bus->idletime = int_val;
2291 }
2292 break;
2293
2294 case IOV_GVAL(IOV_IDLECLOCK):
2295 int_val = (int32)bus->idleclock;
2296 bcopy(&int_val, arg, val_size);
2297 break;
2298
2299 case IOV_SVAL(IOV_IDLECLOCK):
2300 bus->idleclock = int_val;
2301 break;
2302
2303 case IOV_GVAL(IOV_SD1IDLE):
2304 int_val = (int32)sd1idle;
2305 bcopy(&int_val, arg, val_size);
2306 break;
2307
2308 case IOV_SVAL(IOV_SD1IDLE):
2309 sd1idle = bool_val;
2310 break;
2311
2312
2313 case IOV_SVAL(IOV_MEMBYTES):
2314 case IOV_GVAL(IOV_MEMBYTES):
2315 {
2316 uint32 address;
2317 uint size, dsize;
2318 uint8 *data;
2319
2320 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
2321
2322 ASSERT(plen >= 2*sizeof(int));
2323
2324 address = (uint32)int_val;
2325 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
2326 size = (uint)int_val;
2327
2328 /* Do some validation */
2329 dsize = set ? plen - (2 * sizeof(int)) : len;
2330 if (dsize < size) {
2331 DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
2332 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
2333 bcmerror = BCME_BADARG;
2334 break;
2335 }
2336
2337 DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
2338 (set ? "write" : "read"), size, address));
2339
2340 /* If we know about SOCRAM, check for a fit */
2341 if ((bus->orig_ramsize) &&
2342 ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize)))
2343 {
2344 uint8 enable, protect;
2345 si_socdevram(bus->sih, FALSE, &enable, &protect);
2346 if (!enable || protect) {
2347 DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
2348 __FUNCTION__, bus->orig_ramsize, size, address));
2349 DHD_ERROR(("%s: socram enable %d, protect %d\n",
2350 __FUNCTION__, enable, protect));
2351 bcmerror = BCME_BADARG;
2352 break;
2353 }
2354 if (enable && (bus->sih->chip == BCM4330_CHIP_ID)) {
2355 uint32 devramsize = si_socdevram_size(bus->sih);
2356 if ((address < SOCDEVRAM_4330_ARM_ADDR) ||
2357 (address + size > (SOCDEVRAM_4330_ARM_ADDR + devramsize))) {
2358 DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n",
2359 __FUNCTION__, address, size));
2360 DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n",
2361 __FUNCTION__, SOCDEVRAM_4330_ARM_ADDR, devramsize));
2362 bcmerror = BCME_BADARG;
2363 break;
2364 }
2365 /* move it such that address is real now */
2366 address -= SOCDEVRAM_4330_ARM_ADDR;
2367 address += SOCDEVRAM_4330_BP_ADDR;
2368 DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n",
2369 __FUNCTION__, (set ? "write" : "read"), size, address));
2370 }
2371 }
2372
2373 /* Generate the actual data pointer */
2374 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
2375
2376 /* Call to do the transfer */
2377 bcmerror = dhdsdio_membytes(bus, set, address, data, size);
2378
2379 break;
2380 }
2381
2382 case IOV_GVAL(IOV_MEMSIZE):
2383 int_val = (int32)bus->ramsize;
2384 bcopy(&int_val, arg, val_size);
2385 break;
2386
2387 case IOV_GVAL(IOV_SDIOD_DRIVE):
2388 int_val = (int32)dhd_sdiod_drive_strength;
2389 bcopy(&int_val, arg, val_size);
2390 break;
2391
2392 case IOV_SVAL(IOV_SDIOD_DRIVE):
2393 dhd_sdiod_drive_strength = int_val;
2394 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
2395 break;
2396
2397 case IOV_SVAL(IOV_DOWNLOAD):
2398 bcmerror = dhdsdio_download_state(bus, bool_val);
2399 break;
2400
2401 case IOV_SVAL(IOV_SOCRAM_STATE):
2402 bcmerror = dhdsdio_download_state(bus, bool_val);
2403 break;
2404
2405 case IOV_SVAL(IOV_VARS):
2406 bcmerror = dhdsdio_downloadvars(bus, arg, len);
2407 break;
2408
2409 case IOV_GVAL(IOV_READAHEAD):
2410 int_val = (int32)dhd_readahead;
2411 bcopy(&int_val, arg, val_size);
2412 break;
2413
2414 case IOV_SVAL(IOV_READAHEAD):
2415 if (bool_val && !dhd_readahead)
2416 bus->nextlen = 0;
2417 dhd_readahead = bool_val;
2418 break;
2419
2420 case IOV_GVAL(IOV_SDRXCHAIN):
2421 int_val = (int32)bus->use_rxchain;
2422 bcopy(&int_val, arg, val_size);
2423 break;
2424
2425 case IOV_SVAL(IOV_SDRXCHAIN):
2426 if (bool_val && !bus->sd_rxchain)
2427 bcmerror = BCME_UNSUPPORTED;
2428 else
2429 bus->use_rxchain = bool_val;
2430 break;
2431 case IOV_GVAL(IOV_ALIGNCTL):
2432 int_val = (int32)dhd_alignctl;
2433 bcopy(&int_val, arg, val_size);
2434 break;
2435
2436 case IOV_SVAL(IOV_ALIGNCTL):
2437 dhd_alignctl = bool_val;
2438 break;
2439
2440 case IOV_GVAL(IOV_SDALIGN):
2441 int_val = DHD_SDALIGN;
2442 bcopy(&int_val, arg, val_size);
2443 break;
2444
2445#ifdef DHD_DEBUG
2446 case IOV_GVAL(IOV_VARS):
2447 if (bus->varsz < (uint)len)
2448 bcopy(bus->vars, arg, bus->varsz);
2449 else
2450 bcmerror = BCME_BUFTOOSHORT;
2451 break;
2452#endif /* DHD_DEBUG */
2453
2454#ifdef DHD_DEBUG
2455 case IOV_GVAL(IOV_SDREG):
2456 {
2457 sdreg_t *sd_ptr;
2458 uint32 addr, size;
2459
2460 sd_ptr = (sdreg_t *)params;
2461
2462 addr = (uintptr)bus->regs + sd_ptr->offset;
2463 size = sd_ptr->func;
2464 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
2465 if (bcmsdh_regfail(bus->sdh))
2466 bcmerror = BCME_SDIO_ERROR;
2467 bcopy(&int_val, arg, sizeof(int32));
2468 break;
2469 }
2470
2471 case IOV_SVAL(IOV_SDREG):
2472 {
2473 sdreg_t *sd_ptr;
2474 uint32 addr, size;
2475
2476 sd_ptr = (sdreg_t *)params;
2477
2478 addr = (uintptr)bus->regs + sd_ptr->offset;
2479 size = sd_ptr->func;
2480 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
2481 if (bcmsdh_regfail(bus->sdh))
2482 bcmerror = BCME_SDIO_ERROR;
2483 break;
2484 }
2485
2486 /* Same as above, but offset is not backplane (not SDIO core) */
2487 case IOV_GVAL(IOV_SBREG):
2488 {
2489 sdreg_t sdreg;
2490 uint32 addr, size;
2491
2492 bcopy(params, &sdreg, sizeof(sdreg));
2493
2494 addr = SI_ENUM_BASE + sdreg.offset;
2495 size = sdreg.func;
2496 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
2497 if (bcmsdh_regfail(bus->sdh))
2498 bcmerror = BCME_SDIO_ERROR;
2499 bcopy(&int_val, arg, sizeof(int32));
2500 break;
2501 }
2502
2503 case IOV_SVAL(IOV_SBREG):
2504 {
2505 sdreg_t sdreg;
2506 uint32 addr, size;
2507
2508 bcopy(params, &sdreg, sizeof(sdreg));
2509
2510 addr = SI_ENUM_BASE + sdreg.offset;
2511 size = sdreg.func;
2512 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
2513 if (bcmsdh_regfail(bus->sdh))
2514 bcmerror = BCME_SDIO_ERROR;
2515 break;
2516 }
2517
2518 case IOV_GVAL(IOV_SDCIS):
2519 {
2520 *(char *)arg = 0;
2521
2522 bcmstrcat(arg, "\nFunc 0\n");
2523 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2524 bcmstrcat(arg, "\nFunc 1\n");
2525 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2526 bcmstrcat(arg, "\nFunc 2\n");
2527 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2528 break;
2529 }
2530
2531 case IOV_GVAL(IOV_FORCEEVEN):
2532 int_val = (int32)forcealign;
2533 bcopy(&int_val, arg, val_size);
2534 break;
2535
2536 case IOV_SVAL(IOV_FORCEEVEN):
2537 forcealign = bool_val;
2538 break;
2539
2540 case IOV_GVAL(IOV_TXBOUND):
2541 int_val = (int32)dhd_txbound;
2542 bcopy(&int_val, arg, val_size);
2543 break;
2544
2545 case IOV_SVAL(IOV_TXBOUND):
2546 dhd_txbound = (uint)int_val;
2547 break;
2548
2549 case IOV_GVAL(IOV_RXBOUND):
2550 int_val = (int32)dhd_rxbound;
2551 bcopy(&int_val, arg, val_size);
2552 break;
2553
2554 case IOV_SVAL(IOV_RXBOUND):
2555 dhd_rxbound = (uint)int_val;
2556 break;
2557
2558 case IOV_GVAL(IOV_TXMINMAX):
2559 int_val = (int32)dhd_txminmax;
2560 bcopy(&int_val, arg, val_size);
2561 break;
2562
2563 case IOV_SVAL(IOV_TXMINMAX):
2564 dhd_txminmax = (uint)int_val;
2565 break;
2566
2567 case IOV_GVAL(IOV_SERIALCONS):
2568 int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror);
2569 if (bcmerror != 0)
2570 break;
2571
2572 bcopy(&int_val, arg, val_size);
2573 break;
2574
2575 case IOV_SVAL(IOV_SERIALCONS):
2576 dhd_serialconsole(bus, TRUE, bool_val, &bcmerror);
2577 break;
2578
2579
2580
2581#endif /* DHD_DEBUG */
2582
2583
2584#ifdef SDTEST
2585 case IOV_GVAL(IOV_EXTLOOP):
2586 int_val = (int32)bus->ext_loop;
2587 bcopy(&int_val, arg, val_size);
2588 break;
2589
2590 case IOV_SVAL(IOV_EXTLOOP):
2591 bus->ext_loop = bool_val;
2592 break;
2593
2594 case IOV_GVAL(IOV_PKTGEN):
2595 bcmerror = dhdsdio_pktgen_get(bus, arg);
2596 break;
2597
2598 case IOV_SVAL(IOV_PKTGEN):
2599 bcmerror = dhdsdio_pktgen_set(bus, arg);
2600 break;
2601#endif /* SDTEST */
2602
2603
2604 case IOV_GVAL(IOV_DONGLEISOLATION):
2605 int_val = bus->dhd->dongle_isolation;
2606 bcopy(&int_val, arg, val_size);
2607 break;
2608
2609 case IOV_SVAL(IOV_DONGLEISOLATION):
2610 bus->dhd->dongle_isolation = bool_val;
2611 break;
2612
2613 case IOV_SVAL(IOV_DEVRESET):
2614 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
2615 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
2616 bus->dhd->busstate));
2617
2618 ASSERT(bus->dhd->osh);
2619 /* ASSERT(bus->cl_devid); */
2620
2621 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
2622
2623 break;
2624#ifdef SOFTAP
2625 case IOV_GVAL(IOV_FWPATH):
2626 {
2627 uint32 fw_path_len;
2628
2629 fw_path_len = strlen(bus->fw_path);
2630 DHD_INFO(("[softap] get fwpath, l=%d\n", len));
2631
2632 if (fw_path_len > len-1) {
2633 bcmerror = BCME_BUFTOOSHORT;
2634 break;
2635 }
2636
2637 if (fw_path_len) {
2638 bcopy(bus->fw_path, arg, fw_path_len);
2639 ((uchar*)arg)[fw_path_len] = 0;
2640 }
2641 break;
2642 }
2643
2644 case IOV_SVAL(IOV_FWPATH):
2645 DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val));
2646
2647 switch (int_val) {
2648 case 1:
2649 bus->fw_path = fw_path; /* ordinary one */
2650 break;
2651 case 2:
2652 bus->fw_path = fw_path2;
2653 break;
2654 default:
2655 bcmerror = BCME_BADARG;
2656 break;
2657 }
2658
2659 DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL")));
2660 break;
2661
2662#endif /* SOFTAP */
2663 case IOV_GVAL(IOV_DEVRESET):
2664 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
2665
2666 /* Get its status */
2667 int_val = (bool) bus->dhd->dongle_reset;
2668 bcopy(&int_val, arg, val_size);
2669
2670 break;
2671
2672 default:
2673 bcmerror = BCME_UNSUPPORTED;
2674 break;
2675 }
2676
2677exit:
2678 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2679 bus->activity = FALSE;
2680 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2681 }
2682
2683 dhd_os_sdunlock(bus->dhd);
2684
2685 if (actionid == IOV_SVAL(IOV_DEVRESET) && bool_val == FALSE)
2686 dhd_preinit_ioctls((dhd_pub_t *) bus->dhd);
2687
2688 return bcmerror;
2689}
2690
2691static int
2692dhdsdio_write_vars(dhd_bus_t *bus)
2693{
2694 int bcmerror = 0;
2695 uint32 varsize;
2696 uint32 varaddr;
2697 uint8 *vbuffer;
2698 uint32 varsizew;
2699#ifdef DHD_DEBUG
2700 uint8 *nvram_ularray;
2701#endif /* DHD_DEBUG */
2702
2703 /* Even if there are no vars are to be written, we still need to set the ramsize. */
2704 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
2705 varaddr = (bus->ramsize - 4) - varsize;
2706
2707 if (bus->vars) {
2708 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) {
2709 if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) {
2710 DHD_ERROR(("PR85623WAR in place\n"));
2711 varsize += 4;
2712 varaddr -= 4;
2713 }
2714 }
2715
2716 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
2717 if (!vbuffer)
2718 return BCME_NOMEM;
2719
2720 bzero(vbuffer, varsize);
2721 bcopy(bus->vars, vbuffer, bus->varsz);
2722
2723 /* Write the vars list */
2724 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
2725#ifdef DHD_DEBUG
2726 /* Verify NVRAM bytes */
2727 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
2728 nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize);
2729 if (!nvram_ularray)
2730 return BCME_NOMEM;
2731
2732 /* Upload image to verify downloaded contents. */
2733 memset(nvram_ularray, 0xaa, varsize);
2734
2735 /* Read the vars list to temp buffer for comparison */
2736 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
2737 if (bcmerror) {
2738 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
2739 __FUNCTION__, bcmerror, varsize, varaddr));
2740 }
2741 /* Compare the org NVRAM with the one read from RAM */
2742 if (memcmp(vbuffer, nvram_ularray, varsize)) {
2743 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
2744 } else
2745 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
2746 __FUNCTION__));
2747
2748 MFREE(bus->dhd->osh, nvram_ularray, varsize);
2749#endif /* DHD_DEBUG */
2750
2751 MFREE(bus->dhd->osh, vbuffer, varsize);
2752 }
2753
2754 /* adjust to the user specified RAM */
2755 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
2756 bus->orig_ramsize, bus->ramsize));
2757 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
2758 varaddr, varsize));
2759 varsize = ((bus->orig_ramsize - 4) - varaddr);
2760
2761 /*
2762 * Determine the length token:
2763 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
2764 */
2765 if (bcmerror) {
2766 varsizew = 0;
2767 } else {
2768 varsizew = varsize / 4;
2769 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
2770 varsizew = htol32(varsizew);
2771 }
2772
2773 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
2774
2775 /* Write the length token to the last word */
2776 bcmerror = dhdsdio_membytes(bus, TRUE, (bus->orig_ramsize - 4),
2777 (uint8*)&varsizew, 4);
2778
2779 return bcmerror;
2780}
2781
2782static int
2783dhdsdio_download_state(dhd_bus_t *bus, bool enter)
2784{
2785 uint retries;
2786 int bcmerror = 0;
2787
2788 /* To enter download state, disable ARM and reset SOCRAM.
2789 * To exit download state, simply reset ARM (default is RAM boot).
2790 */
2791 if (enter) {
2792 bus->alp_only = TRUE;
2793
2794 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2795 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2796 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2797 bcmerror = BCME_ERROR;
2798 goto fail;
2799 }
2800
2801 si_core_disable(bus->sih, 0);
2802 if (bcmsdh_regfail(bus->sdh)) {
2803 bcmerror = BCME_SDIO_ERROR;
2804 goto fail;
2805 }
2806
2807 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2808 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2809 bcmerror = BCME_ERROR;
2810 goto fail;
2811 }
2812
2813 si_core_reset(bus->sih, 0, 0);
2814 if (bcmsdh_regfail(bus->sdh)) {
2815 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__));
2816 bcmerror = BCME_SDIO_ERROR;
2817 goto fail;
2818 }
2819
2820 /* Clear the top bit of memory */
2821 if (bus->ramsize) {
2822 uint32 zeros = 0;
2823 if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) {
2824 bcmerror = BCME_SDIO_ERROR;
2825 goto fail;
2826 }
2827 }
2828 } else {
2829 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2830 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2831 bcmerror = BCME_ERROR;
2832 goto fail;
2833 }
2834
2835 if (!si_iscoreup(bus->sih)) {
2836 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
2837 bcmerror = BCME_ERROR;
2838 goto fail;
2839 }
2840
2841 if ((bcmerror = dhdsdio_write_vars(bus))) {
2842 DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__));
2843 goto fail;
2844 }
2845
2846 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
2847 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
2848 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
2849 bcmerror = BCME_ERROR;
2850 goto fail;
2851 }
2852 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
2853
2854
2855 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2856 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2857 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2858 bcmerror = BCME_ERROR;
2859 goto fail;
2860 }
2861
2862 si_core_reset(bus->sih, 0, 0);
2863 if (bcmsdh_regfail(bus->sdh)) {
2864 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
2865 bcmerror = BCME_SDIO_ERROR;
2866 goto fail;
2867 }
2868
2869 /* Allow HT Clock now that the ARM is running. */
2870 bus->alp_only = FALSE;
2871
2872 bus->dhd->busstate = DHD_BUS_LOAD;
2873 }
2874
2875fail:
2876 /* Always return to SDIOD core */
2877 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
2878 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
2879
2880 return bcmerror;
2881}
2882
2883int
2884dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
2885 void *params, int plen, void *arg, int len, bool set)
2886{
2887 dhd_bus_t *bus = dhdp->bus;
2888 const bcm_iovar_t *vi = NULL;
2889 int bcmerror = 0;
2890 int val_size;
2891 uint32 actionid;
2892
2893 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2894
2895 ASSERT(name);
2896 ASSERT(len >= 0);
2897
2898 /* Get MUST have return space */
2899 ASSERT(set || (arg && len));
2900
2901 /* Set does NOT take qualifiers */
2902 ASSERT(!set || (!params && !plen));
2903
2904 /* Look up var locally; if not found pass to host driver */
2905 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
2906 dhd_os_sdlock(bus->dhd);
2907
2908 BUS_WAKE(bus);
2909
2910 /* Turn on clock in case SD command needs backplane */
2911 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2912
2913 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
2914
2915 /* Check for bus configuration changes of interest */
2916
2917 /* If it was divisor change, read the new one */
2918 if (set && strcmp(name, "sd_divisor") == 0) {
2919 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
2920 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
2921 bus->sd_divisor = -1;
2922 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2923 } else {
2924 DHD_INFO(("%s: noted %s update, value now %d\n",
2925 __FUNCTION__, name, bus->sd_divisor));
2926 }
2927 }
2928 /* If it was a mode change, read the new one */
2929 if (set && strcmp(name, "sd_mode") == 0) {
2930 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
2931 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
2932 bus->sd_mode = -1;
2933 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2934 } else {
2935 DHD_INFO(("%s: noted %s update, value now %d\n",
2936 __FUNCTION__, name, bus->sd_mode));
2937 }
2938 }
2939 /* Similar check for blocksize change */
2940 if (set && strcmp(name, "sd_blocksize") == 0) {
2941 int32 fnum = 2;
2942 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
2943 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
2944 bus->blocksize = 0;
2945 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
2946 } else {
2947 DHD_INFO(("%s: noted %s update, value now %d\n",
2948 __FUNCTION__, "sd_blocksize", bus->blocksize));
2949 }
2950 }
2951 bus->roundup = MIN(max_roundup, bus->blocksize);
2952
2953 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2954 bus->activity = FALSE;
2955 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2956 }
2957
2958 dhd_os_sdunlock(bus->dhd);
2959 goto exit;
2960 }
2961
2962 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
2963 name, (set ? "set" : "get"), len, plen));
2964
2965 /* set up 'params' pointer in case this is a set command so that
2966 * the convenience int and bool code can be common to set and get
2967 */
2968 if (params == NULL) {
2969 params = arg;
2970 plen = len;
2971 }
2972
2973 if (vi->type == IOVT_VOID)
2974 val_size = 0;
2975 else if (vi->type == IOVT_BUFFER)
2976 val_size = len;
2977 else
2978 /* all other types are integer sized */
2979 val_size = sizeof(int);
2980
2981 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
2982 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
2983
2984exit:
2985 return bcmerror;
2986}
2987
2988void
2989dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
2990{
2991 osl_t *osh;
2992 uint32 local_hostintmask;
2993 uint8 saveclk;
2994 uint retries;
2995 int err;
2996 if (!bus->dhd)
2997 return;
2998
2999 osh = bus->dhd->osh;
3000 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3001
3002 bcmsdh_waitlockfree(NULL);
3003
3004 if (enforce_mutex)
3005 dhd_os_sdlock(bus->dhd);
3006
3007 BUS_WAKE(bus);
3008
3009 /* Change our idea of bus state */
3010 bus->dhd->busstate = DHD_BUS_DOWN;
3011
3012 /* Enable clock for device interrupts */
3013 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3014
3015 /* Disable and clear interrupts at the chip level also */
3016 W_SDREG(0, &bus->regs->hostintmask, retries);
3017 local_hostintmask = bus->hostintmask;
3018 bus->hostintmask = 0;
3019
3020 /* Force clocks on backplane to be sure F2 interrupt propagates */
3021 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
3022 if (!err) {
3023 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
3024 (saveclk | SBSDIO_FORCE_HT), &err);
3025 }
3026 if (err) {
3027 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
3028 }
3029
3030 /* Turn off the bus (F2), free any pending packets */
3031 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3032 bcmsdh_intr_disable(bus->sdh);
3033 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
3034
3035 /* Clear any pending interrupts now that F2 is disabled */
3036 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
3037
3038 /* Turn off the backplane clock (only) */
3039 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
3040
3041 /* Clear the data packet queues */
3042 pktq_flush(osh, &bus->txq, TRUE, NULL, 0);
3043
3044 /* Clear any held glomming stuff */
3045 if (bus->glomd)
3046 PKTFREE(osh, bus->glomd, FALSE);
3047
3048 if (bus->glom)
3049 PKTFREE(osh, bus->glom, FALSE);
3050
3051 bus->glom = bus->glomd = NULL;
3052
3053 /* Clear rx control and wake any waiters */
3054 bus->rxlen = 0;
3055 dhd_os_ioctl_resp_wake(bus->dhd);
3056
3057 /* Reset some F2 state stuff */
3058 bus->rxskip = FALSE;
3059 bus->tx_seq = bus->rx_seq = 0;
3060
3061 if (enforce_mutex)
3062 dhd_os_sdunlock(bus->dhd);
3063}
3064
3065
3066int
3067dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
3068{
3069 dhd_bus_t *bus = dhdp->bus;
3070 dhd_timeout_t tmo;
3071 uint retries = 0;
3072 uint8 ready, enable;
3073 int err, ret = 0;
3074 uint8 saveclk;
3075
3076 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3077
3078 ASSERT(bus->dhd);
3079 if (!bus->dhd)
3080 return 0;
3081
3082 if (enforce_mutex)
3083 dhd_os_sdlock(bus->dhd);
3084
3085 /* Make sure backplane clock is on, needed to generate F2 interrupt */
3086 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
3087 if (bus->clkstate != CLK_AVAIL) {
3088 DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate));
3089 goto exit;
3090 }
3091
3092
3093 /* Force clocks on backplane to be sure F2 interrupt propagates */
3094 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
3095 if (!err) {
3096 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
3097 (saveclk | SBSDIO_FORCE_HT), &err);
3098 }
3099 if (err) {
3100 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
3101 goto exit;
3102 }
3103
3104 /* Enable function 2 (frame transfers) */
3105 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
3106 &bus->regs->tosbmailboxdata, retries);
3107 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
3108
3109 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
3110
3111 /* Give the dongle some time to do its thing and set IOR2 */
3112 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
3113
3114 ready = 0;
3115 while (ready != enable && !dhd_timeout_expired(&tmo))
3116 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
3117
3118
3119 DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
3120 __FUNCTION__, enable, ready, tmo.elapsed));
3121
3122
3123 /* If F2 successfully enabled, set core and enable interrupts */
3124 if (ready == enable) {
3125 /* Make sure we're talking to the core. */
3126 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
3127 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
3128 ASSERT(bus->regs != NULL);
3129
3130 /* Set up the interrupt mask and enable interrupts */
3131 bus->hostintmask = HOSTINTMASK;
3132 /* corerev 4 could use the newer interrupt logic to detect the frames */
3133 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) &&
3134 (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) {
3135 bus->hostintmask &= ~I_HMB_FRAME_IND;
3136 bus->hostintmask |= I_XMTDATA_AVAIL;
3137 }
3138 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
3139
3140 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err);
3141
3142 /* Set bus state according to enable result */
3143 dhdp->busstate = DHD_BUS_DATA;
3144
3145 /* bcmsdh_intr_unmask(bus->sdh); */
3146
3147 bus->intdis = FALSE;
3148 if (bus->intr) {
3149 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
3150 bcmsdh_intr_enable(bus->sdh);
3151 } else {
3152 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
3153 bcmsdh_intr_disable(bus->sdh);
3154 }
3155
3156 }
3157
3158
3159 else {
3160 /* Disable F2 again */
3161 enable = SDIO_FUNC_ENABLE_1;
3162 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
3163 }
3164
3165 /* Restore previous clock setting */
3166 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
3167
3168
3169 /* If we didn't come up, turn off backplane clock */
3170 if (dhdp->busstate != DHD_BUS_DATA)
3171 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
3172
3173exit:
3174 if (enforce_mutex)
3175 dhd_os_sdunlock(bus->dhd);
3176
3177 return ret;
3178}
3179
3180static void
3181dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
3182{
3183 bcmsdh_info_t *sdh = bus->sdh;
3184 sdpcmd_regs_t *regs = bus->regs;
3185 uint retries = 0;
3186 uint16 lastrbc;
3187 uint8 hi, lo;
3188 int err;
3189
3190 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
3191 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
3192
3193 if (abort) {
3194 bcmsdh_abort(sdh, SDIO_FUNC_2);
3195 }
3196
3197 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
3198 bus->f1regdata++;
3199
3200 /* Wait until the packet has been flushed (device/FIFO stable) */
3201 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
3202 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
3203 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL);
3204 bus->f1regdata += 2;
3205
3206 if ((hi == 0) && (lo == 0))
3207 break;
3208
3209 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
3210 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
3211 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
3212 }
3213 lastrbc = (hi << 8) + lo;
3214 }
3215
3216 if (!retries) {
3217 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
3218 } else {
3219 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
3220 }
3221
3222 if (rtx) {
3223 bus->rxrtx++;
3224 W_SDREG(SMB_NAK, &regs->tosbmailbox, retries);
3225 bus->f1regdata++;
3226 if (retries <= retry_limit) {
3227 bus->rxskip = TRUE;
3228 }
3229 }
3230
3231 /* Clear partial in any case */
3232 bus->nextlen = 0;
3233
3234 /* If we can't reach the device, signal failure */
3235 if (err || bcmsdh_regfail(sdh))
3236 bus->dhd->busstate = DHD_BUS_DOWN;
3237}
3238
3239static void
3240dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
3241{
3242 bcmsdh_info_t *sdh = bus->sdh;
3243 uint rdlen, pad;
3244
3245 int sdret;
3246
3247 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3248
3249 /* Control data already received in aligned rxctl */
3250 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
3251 goto gotpkt;
3252
3253 ASSERT(bus->rxbuf);
3254 /* Set rxctl for frame (w/optional alignment) */
3255 bus->rxctl = bus->rxbuf;
3256 if (dhd_alignctl) {
3257 bus->rxctl += firstread;
3258 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
3259 bus->rxctl += (DHD_SDALIGN - pad);
3260 bus->rxctl -= firstread;
3261 }
3262 ASSERT(bus->rxctl >= bus->rxbuf);
3263
3264 /* Copy the already-read portion over */
3265 bcopy(hdr, bus->rxctl, firstread);
3266 if (len <= firstread)
3267 goto gotpkt;
3268
3269 /* Copy the full data pkt in gSPI case and process ioctl. */
3270 if (bus->bus == SPI_BUS) {
3271 bcopy(hdr, bus->rxctl, len);
3272 goto gotpkt;
3273 }
3274
3275 /* Raise rdlen to next SDIO block to avoid tail command */
3276 rdlen = len - firstread;
3277 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3278 pad = bus->blocksize - (rdlen % bus->blocksize);
3279 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3280 ((len + pad) < bus->dhd->maxctl))
3281 rdlen += pad;
3282 } else if (rdlen % DHD_SDALIGN) {
3283 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3284 }
3285
3286 /* Satisfy length-alignment requirements */
3287 if (forcealign && (rdlen & (ALIGNMENT - 1)))
3288 rdlen = ROUNDUP(rdlen, ALIGNMENT);
3289
3290 /* Drop if the read is too big or it exceeds our maximum */
3291 if ((rdlen + firstread) > bus->dhd->maxctl) {
3292 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
3293 __FUNCTION__, rdlen, bus->dhd->maxctl));
3294 bus->dhd->rx_errors++;
3295 dhdsdio_rxfail(bus, FALSE, FALSE);
3296 goto done;
3297 }
3298
3299 if ((len - doff) > bus->dhd->maxctl) {
3300 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
3301 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
3302 bus->dhd->rx_errors++; bus->rx_toolong++;
3303 dhdsdio_rxfail(bus, FALSE, FALSE);
3304 goto done;
3305 }
3306
3307
3308 /* Read remainder of frame body into the rxctl buffer */
3309 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3310 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
3311 bus->f2rxdata++;
3312 ASSERT(sdret != BCME_PENDING);
3313
3314 /* Control frame failures need retransmission */
3315 if (sdret < 0) {
3316 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
3317 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
3318 dhdsdio_rxfail(bus, TRUE, TRUE);
3319 goto done;
3320 }
3321
3322gotpkt:
3323
3324#ifdef DHD_DEBUG
3325 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
3326 prhex("RxCtrl", bus->rxctl, len);
3327 }
3328#endif
3329
3330 /* Point to valid data and indicate its length */
3331 bus->rxctl += doff;
3332 bus->rxlen = len - doff;
3333
3334done:
3335 /* Awake any waiters */
3336 dhd_os_ioctl_resp_wake(bus->dhd);
3337}
3338
3339static uint8
3340dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
3341{
3342 uint16 dlen, totlen;
3343 uint8 *dptr, num = 0;
3344
3345 uint16 sublen, check;
3346 void *pfirst, *plast, *pnext, *save_pfirst;
3347 osl_t *osh = bus->dhd->osh;
3348
3349 int errcode;
3350 uint8 chan, seq, doff, sfdoff;
3351 uint8 txmax;
3352
3353 int ifidx = 0;
3354 bool usechain = bus->use_rxchain;
3355
3356 /* If packets, issue read(s) and send up packet chain */
3357 /* Return sequence numbers consumed? */
3358
3359 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
3360
3361 /* If there's a descriptor, generate the packet chain */
3362 if (bus->glomd) {
3363 dhd_os_sdlock_rxq(bus->dhd);
3364
3365 pfirst = plast = pnext = NULL;
3366 dlen = (uint16)PKTLEN(osh, bus->glomd);
3367 dptr = PKTDATA(osh, bus->glomd);
3368 if (!dlen || (dlen & 1)) {
3369 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
3370 __FUNCTION__, dlen));
3371 dlen = 0;
3372 }
3373
3374 for (totlen = num = 0; dlen; num++) {
3375 /* Get (and move past) next length */
3376 sublen = ltoh16_ua(dptr);
3377 dlen -= sizeof(uint16);
3378 dptr += sizeof(uint16);
3379 if ((sublen < SDPCM_HDRLEN) ||
3380 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
3381 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
3382 __FUNCTION__, num, sublen));
3383 pnext = NULL;
3384 break;
3385 }
3386 if (sublen % DHD_SDALIGN) {
3387 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
3388 __FUNCTION__, sublen, DHD_SDALIGN));
3389 usechain = FALSE;
3390 }
3391 totlen += sublen;
3392
3393 /* For last frame, adjust read len so total is a block multiple */
3394 if (!dlen) {
3395 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
3396 totlen = ROUNDUP(totlen, bus->blocksize);
3397 }
3398
3399 /* Allocate/chain packet for next subframe */
3400 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
3401 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
3402 __FUNCTION__, num, sublen));
3403 break;
3404 }
3405 ASSERT(!PKTLINK(pnext));
3406 if (!pfirst) {
3407 ASSERT(!plast);
3408 pfirst = plast = pnext;
3409 } else {
3410 ASSERT(plast);
3411 PKTSETNEXT(osh, plast, pnext);
3412 plast = pnext;
3413 }
3414
3415 /* Adhere to start alignment requirements */
3416 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
3417 }
3418
3419 /* If all allocations succeeded, save packet chain in bus structure */
3420 if (pnext) {
3421 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
3422 __FUNCTION__, totlen, num));
3423 if (DHD_GLOM_ON() && bus->nextlen) {
3424 if (totlen != bus->nextlen) {
3425 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
3426 "rxseq %d\n", __FUNCTION__, bus->nextlen,
3427 totlen, rxseq));
3428 }
3429 }
3430 bus->glom = pfirst;
3431 pfirst = pnext = NULL;
3432 } else {
3433 if (pfirst)
3434 PKTFREE(osh, pfirst, FALSE);
3435 bus->glom = NULL;
3436 num = 0;
3437 }
3438
3439 /* Done with descriptor packet */
3440 PKTFREE(osh, bus->glomd, FALSE);
3441 bus->glomd = NULL;
3442 bus->nextlen = 0;
3443
3444 dhd_os_sdunlock_rxq(bus->dhd);
3445 }
3446
3447 /* Ok -- either we just generated a packet chain, or had one from before */
3448 if (bus->glom) {
3449 if (DHD_GLOM_ON()) {
3450 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
3451 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
3452 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
3453 pnext, (uint8*)PKTDATA(osh, pnext),
3454 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
3455 }
3456 }
3457
3458 pfirst = bus->glom;
3459 dlen = (uint16)pkttotlen(osh, pfirst);
3460
3461 /* Do an SDIO read for the superframe. Configurable iovar to
3462 * read directly into the chained packet, or allocate a large
3463 * packet and and copy into the chain.
3464 */
3465 if (usechain) {
3466 errcode = dhd_bcmsdh_recv_buf(bus,
3467 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
3468 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
3469 dlen, pfirst, NULL, NULL);
3470 } else if (bus->dataptr) {
3471 errcode = dhd_bcmsdh_recv_buf(bus,
3472 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
3473 F2SYNC, bus->dataptr,
3474 dlen, NULL, NULL, NULL);
3475 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
3476 if (sublen != dlen) {
3477 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
3478 __FUNCTION__, dlen, sublen));
3479 errcode = -1;
3480 }
3481 pnext = NULL;
3482 } else {
3483 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
3484 errcode = -1;
3485 }
3486 bus->f2rxdata++;
3487 ASSERT(errcode != BCME_PENDING);
3488
3489 /* On failure, kill the superframe, allow a couple retries */
3490 if (errcode < 0) {
3491 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
3492 __FUNCTION__, dlen, errcode));
3493 bus->dhd->rx_errors++;
3494
3495 if (bus->glomerr++ < 3) {
3496 dhdsdio_rxfail(bus, TRUE, TRUE);
3497 } else {
3498 bus->glomerr = 0;
3499 dhdsdio_rxfail(bus, TRUE, FALSE);
3500 dhd_os_sdlock_rxq(bus->dhd);
3501 PKTFREE(osh, bus->glom, FALSE);
3502 dhd_os_sdunlock_rxq(bus->dhd);
3503 bus->rxglomfail++;
3504 bus->glom = NULL;
3505 }
3506 return 0;
3507 }
3508
3509#ifdef DHD_DEBUG
3510 if (DHD_GLOM_ON()) {
3511 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
3512 MIN(PKTLEN(osh, pfirst), 48));
3513 }
3514#endif
3515
3516
3517 /* Validate the superframe header */
3518 dptr = (uint8 *)PKTDATA(osh, pfirst);
3519 sublen = ltoh16_ua(dptr);
3520 check = ltoh16_ua(dptr + sizeof(uint16));
3521
3522 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3523 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3524 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3525 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3526 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
3527 __FUNCTION__, bus->nextlen, seq));
3528 bus->nextlen = 0;
3529 }
3530 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3531 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3532
3533 errcode = 0;
3534 if ((uint16)~(sublen^check)) {
3535 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
3536 __FUNCTION__, sublen, check));
3537 errcode = -1;
3538 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
3539 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
3540 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
3541 errcode = -1;
3542 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
3543 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
3544 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
3545 errcode = -1;
3546 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
3547 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
3548 errcode = -1;
3549 } else if ((doff < SDPCM_HDRLEN) ||
3550 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
3551 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
3552 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), SDPCM_HDRLEN));
3553 errcode = -1;
3554 }
3555
3556 /* Check sequence number of superframe SW header */
3557 if (rxseq != seq) {
3558 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
3559 __FUNCTION__, seq, rxseq));
3560 bus->rx_badseq++;
3561 rxseq = seq;
3562 }
3563
3564 /* Check window for sanity */
3565 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3566 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3567 __FUNCTION__, txmax, bus->tx_seq));
3568 txmax = bus->tx_seq;
3569 }
3570 bus->tx_max = txmax;
3571
3572 /* Remove superframe header, remember offset */
3573 PKTPULL(osh, pfirst, doff);
3574 sfdoff = doff;
3575
3576 /* Validate all the subframe headers */
3577 for (num = 0, pnext = pfirst; pnext && !errcode;
3578 num++, pnext = PKTNEXT(osh, pnext)) {
3579 dptr = (uint8 *)PKTDATA(osh, pnext);
3580 dlen = (uint16)PKTLEN(osh, pnext);
3581 sublen = ltoh16_ua(dptr);
3582 check = ltoh16_ua(dptr + sizeof(uint16));
3583 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3584 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3585#ifdef DHD_DEBUG
3586 if (DHD_GLOM_ON()) {
3587 prhex("subframe", dptr, 32);
3588 }
3589#endif
3590
3591 if ((uint16)~(sublen^check)) {
3592 DHD_ERROR(("%s (subframe %d): HW hdr error: "
3593 "len/check 0x%04x/0x%04x\n",
3594 __FUNCTION__, num, sublen, check));
3595 errcode = -1;
3596 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
3597 DHD_ERROR(("%s (subframe %d): length mismatch: "
3598 "len 0x%04x, expect 0x%04x\n",
3599 __FUNCTION__, num, sublen, dlen));
3600 errcode = -1;
3601 } else if ((chan != SDPCM_DATA_CHANNEL) &&
3602 (chan != SDPCM_EVENT_CHANNEL)) {
3603 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
3604 __FUNCTION__, num, chan));
3605 errcode = -1;
3606 } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
3607 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
3608 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
3609 errcode = -1;
3610 }
3611 }
3612
3613 if (errcode) {
3614 /* Terminate frame on error, request a couple retries */
3615 if (bus->glomerr++ < 3) {
3616 /* Restore superframe header space */
3617 PKTPUSH(osh, pfirst, sfdoff);
3618 dhdsdio_rxfail(bus, TRUE, TRUE);
3619 } else {
3620 bus->glomerr = 0;
3621 dhdsdio_rxfail(bus, TRUE, FALSE);
3622 dhd_os_sdlock_rxq(bus->dhd);
3623 PKTFREE(osh, bus->glom, FALSE);
3624 dhd_os_sdunlock_rxq(bus->dhd);
3625 bus->rxglomfail++;
3626 bus->glom = NULL;
3627 }
3628 bus->nextlen = 0;
3629 return 0;
3630 }
3631
3632 /* Basic SD framing looks ok - process each packet (header) */
3633 save_pfirst = pfirst;
3634 bus->glom = NULL;
3635 plast = NULL;
3636
3637 dhd_os_sdlock_rxq(bus->dhd);
3638 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
3639 pnext = PKTNEXT(osh, pfirst);
3640 PKTSETNEXT(osh, pfirst, NULL);
3641
3642 dptr = (uint8 *)PKTDATA(osh, pfirst);
3643 sublen = ltoh16_ua(dptr);
3644 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3645 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3646 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3647
3648 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
3649 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
3650 PKTLEN(osh, pfirst), sublen, chan, seq));
3651
3652 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
3653
3654 if (rxseq != seq) {
3655 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
3656 __FUNCTION__, seq, rxseq));
3657 bus->rx_badseq++;
3658 rxseq = seq;
3659 }
3660
3661#ifdef DHD_DEBUG
3662 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3663 prhex("Rx Subframe Data", dptr, dlen);
3664 }
3665#endif
3666
3667 PKTSETLEN(osh, pfirst, sublen);
3668 PKTPULL(osh, pfirst, doff);
3669
3670 if (PKTLEN(osh, pfirst) == 0) {
3671 PKTFREE(bus->dhd->osh, pfirst, FALSE);
3672 if (plast) {
3673 PKTSETNEXT(osh, plast, pnext);
3674 } else {
3675 ASSERT(save_pfirst == pfirst);
3676 save_pfirst = pnext;
3677 }
3678 continue;
3679 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst) != 0) {
3680 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
3681 bus->dhd->rx_errors++;
3682 PKTFREE(osh, pfirst, FALSE);
3683 if (plast) {
3684 PKTSETNEXT(osh, plast, pnext);
3685 } else {
3686 ASSERT(save_pfirst == pfirst);
3687 save_pfirst = pnext;
3688 }
3689 continue;
3690 }
3691
3692 /* this packet will go up, link back into chain and count it */
3693 PKTSETNEXT(osh, pfirst, pnext);
3694 plast = pfirst;
3695 num++;
3696
3697#ifdef DHD_DEBUG
3698 if (DHD_GLOM_ON()) {
3699 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
3700 __FUNCTION__, num, pfirst,
3701 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
3702 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
3703 prhex("", (uint8 *)PKTDATA(osh, pfirst),
3704 MIN(PKTLEN(osh, pfirst), 32));
3705 }
3706#endif /* DHD_DEBUG */
3707 }
3708 dhd_os_sdunlock_rxq(bus->dhd);
3709 if (num) {
3710 dhd_os_sdunlock(bus->dhd);
3711 dhd_rx_frame(bus->dhd, ifidx, save_pfirst, num, 0);
3712 dhd_os_sdlock(bus->dhd);
3713 }
3714
3715 bus->rxglomframes++;
3716 bus->rxglompkts += num;
3717 }
3718 return num;
3719}
3720
3721/* Return TRUE if there may be more frames to read */
3722static uint
3723dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
3724{
3725 osl_t *osh = bus->dhd->osh;
3726 bcmsdh_info_t *sdh = bus->sdh;
3727
3728 uint16 len, check; /* Extracted hardware header fields */
3729 uint8 chan, seq, doff; /* Extracted software header fields */
3730 uint8 fcbits; /* Extracted fcbits from software header */
3731 uint8 delta;
3732
3733 void *pkt; /* Packet for event or data frames */
3734 uint16 pad; /* Number of pad bytes to read */
3735 uint16 rdlen; /* Total number of bytes to read */
3736 uint8 rxseq; /* Next sequence number to expect */
3737 uint rxleft = 0; /* Remaining number of frames allowed */
3738 int sdret; /* Return code from bcmsdh calls */
3739 uint8 txmax; /* Maximum tx sequence offered */
3740 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
3741 uint8 *rxbuf;
3742 int ifidx = 0;
3743 uint rxcount = 0; /* Total frames read */
3744
3745#if defined(DHD_DEBUG) || defined(SDTEST)
3746 bool sdtest = FALSE; /* To limit message spew from test mode */
3747#endif
3748
3749 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3750
3751 ASSERT(maxframes);
3752
3753#ifdef SDTEST
3754 /* Allow pktgen to override maxframes */
3755 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
3756 maxframes = bus->pktgen_count;
3757 sdtest = TRUE;
3758 }
3759#endif
3760
3761 /* Not finished unless we encounter no more frames indication */
3762 *finished = FALSE;
3763
3764
3765 for (rxseq = bus->rx_seq, rxleft = maxframes;
3766 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
3767 rxseq++, rxleft--) {
3768
3769 /* Handle glomming separately */
3770 if (bus->glom || bus->glomd) {
3771 uint8 cnt;
3772 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
3773 __FUNCTION__, bus->glomd, bus->glom));
3774 cnt = dhdsdio_rxglom(bus, rxseq);
3775 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
3776 rxseq += cnt - 1;
3777 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
3778 continue;
3779 }
3780
3781 /* Try doing single read if we can */
3782 if (dhd_readahead && bus->nextlen) {
3783 uint16 nextlen = bus->nextlen;
3784 bus->nextlen = 0;
3785
3786 if (bus->bus == SPI_BUS) {
3787 rdlen = len = nextlen;
3788 }
3789 else {
3790 rdlen = len = nextlen << 4;
3791
3792 /* Pad read to blocksize for efficiency */
3793 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3794 pad = bus->blocksize - (rdlen % bus->blocksize);
3795 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3796 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
3797 rdlen += pad;
3798 } else if (rdlen % DHD_SDALIGN) {
3799 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3800 }
3801 }
3802
3803 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
3804 * Later we use buffer-poll for data as well as control packets.
3805 * This is required because dhd receives full frame in gSPI unlike SDIO.
3806 * After the frame is received we have to distinguish whether it is data
3807 * or non-data frame.
3808 */
3809 /* Allocate a packet buffer */
3810 dhd_os_sdlock_rxq(bus->dhd);
3811 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
3812 if (bus->bus == SPI_BUS) {
3813 bus->usebufpool = FALSE;
3814 bus->rxctl = bus->rxbuf;
3815 if (dhd_alignctl) {
3816 bus->rxctl += firstread;
3817 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
3818 bus->rxctl += (DHD_SDALIGN - pad);
3819 bus->rxctl -= firstread;
3820 }
3821 ASSERT(bus->rxctl >= bus->rxbuf);
3822 rxbuf = bus->rxctl;
3823 /* Read the entire frame */
3824 sdret = dhd_bcmsdh_recv_buf(bus,
3825 bcmsdh_cur_sbwad(sdh),
3826 SDIO_FUNC_2,
3827 F2SYNC, rxbuf, rdlen,
3828 NULL, NULL, NULL);
3829 bus->f2rxdata++;
3830 ASSERT(sdret != BCME_PENDING);
3831
3832
3833 /* Control frame failures need retransmission */
3834 if (sdret < 0) {
3835 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
3836 __FUNCTION__, rdlen, sdret));
3837 /* dhd.rx_ctlerrs is higher level */
3838 bus->rxc_errors++;
3839 dhd_os_sdunlock_rxq(bus->dhd);
3840 dhdsdio_rxfail(bus, TRUE,
3841 (bus->bus == SPI_BUS) ? FALSE : TRUE);
3842 continue;
3843 }
3844 } else {
3845 /* Give up on data, request rtx of events */
3846 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
3847 "expected rxseq %d\n",
3848 __FUNCTION__, len, rdlen, rxseq));
3849 /* Just go try again w/normal header read */
3850 dhd_os_sdunlock_rxq(bus->dhd);
3851 continue;
3852 }
3853 } else {
3854 if (bus->bus == SPI_BUS)
3855 bus->usebufpool = TRUE;
3856
3857 ASSERT(!PKTLINK(pkt));
3858 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
3859 rxbuf = (uint8 *)PKTDATA(osh, pkt);
3860 /* Read the entire frame */
3861 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
3862 SDIO_FUNC_2,
3863 F2SYNC, rxbuf, rdlen,
3864 pkt, NULL, NULL);
3865 bus->f2rxdata++;
3866 ASSERT(sdret != BCME_PENDING);
3867
3868 if (sdret < 0) {
3869 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
3870 __FUNCTION__, rdlen, sdret));
3871 PKTFREE(bus->dhd->osh, pkt, FALSE);
3872 bus->dhd->rx_errors++;
3873 dhd_os_sdunlock_rxq(bus->dhd);
3874 /* Force retry w/normal header read. Don't attempt NAK for
3875 * gSPI
3876 */
3877 dhdsdio_rxfail(bus, TRUE,
3878 (bus->bus == SPI_BUS) ? FALSE : TRUE);
3879 continue;
3880 }
3881 }
3882 dhd_os_sdunlock_rxq(bus->dhd);
3883
3884 /* Now check the header */
3885 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
3886
3887 /* Extract hardware header fields */
3888 len = ltoh16_ua(bus->rxhdr);
3889 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
3890
3891 /* All zeros means readahead info was bad */
3892 if (!(len|check)) {
3893 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
3894 __FUNCTION__));
3895 dhd_os_sdlock_rxq(bus->dhd);
3896 PKTFREE2();
3897 dhd_os_sdunlock_rxq(bus->dhd);
3898 GSPI_PR55150_BAILOUT;
3899 continue;
3900 }
3901
3902 /* Validate check bytes */
3903 if ((uint16)~(len^check)) {
3904 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
3905 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
3906 len, check));
3907 dhd_os_sdlock_rxq(bus->dhd);
3908 PKTFREE2();
3909 dhd_os_sdunlock_rxq(bus->dhd);
3910 bus->rx_badhdr++;
3911 dhdsdio_rxfail(bus, FALSE, FALSE);
3912 GSPI_PR55150_BAILOUT;
3913 continue;
3914 }
3915
3916 /* Validate frame length */
3917 if (len < SDPCM_HDRLEN) {
3918 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
3919 __FUNCTION__, len));
3920 dhd_os_sdlock_rxq(bus->dhd);
3921 PKTFREE2();
3922 dhd_os_sdunlock_rxq(bus->dhd);
3923 GSPI_PR55150_BAILOUT;
3924 continue;
3925 }
3926
3927 /* Check for consistency with readahead info */
3928 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
3929 if (len_consistent) {
3930 /* Mismatch, force retry w/normal header (may be >4K) */
3931 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
3932 "expected rxseq %d\n",
3933 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
3934 dhd_os_sdlock_rxq(bus->dhd);
3935 PKTFREE2();
3936 dhd_os_sdunlock_rxq(bus->dhd);
3937 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
3938 GSPI_PR55150_BAILOUT;
3939 continue;
3940 }
3941
3942
3943 /* Extract software header fields */
3944 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3945 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3946 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3947 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3948
3949 bus->nextlen =
3950 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3951 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3952 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
3953 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
3954 seq));
3955 bus->nextlen = 0;
3956 }
3957
3958 bus->dhd->rx_readahead_cnt ++;
3959 /* Handle Flow Control */
3960 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3961
3962 delta = 0;
3963 if (~bus->flowcontrol & fcbits) {
3964 bus->fc_xoff++;
3965 delta = 1;
3966 }
3967 if (bus->flowcontrol & ~fcbits) {
3968 bus->fc_xon++;
3969 delta = 1;
3970 }
3971
3972 if (delta) {
3973 bus->fc_rcvd++;
3974 bus->flowcontrol = fcbits;
3975 }
3976
3977 /* Check and update sequence number */
3978 if (rxseq != seq) {
3979 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
3980 __FUNCTION__, seq, rxseq));
3981 bus->rx_badseq++;
3982 rxseq = seq;
3983 }
3984
3985 /* Check window for sanity */
3986 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3987 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3988 __FUNCTION__, txmax, bus->tx_seq));
3989 txmax = bus->tx_seq;
3990 }
3991 bus->tx_max = txmax;
3992
3993#ifdef DHD_DEBUG
3994 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3995 prhex("Rx Data", rxbuf, len);
3996 } else if (DHD_HDRS_ON()) {
3997 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
3998 }
3999#endif
4000
4001 if (chan == SDPCM_CONTROL_CHANNEL) {
4002 if (bus->bus == SPI_BUS) {
4003 dhdsdio_read_control(bus, rxbuf, len, doff);
4004 if (bus->usebufpool) {
4005 dhd_os_sdlock_rxq(bus->dhd);
4006 PKTFREE(bus->dhd->osh, pkt, FALSE);
4007 dhd_os_sdunlock_rxq(bus->dhd);
4008 }
4009 continue;
4010 } else {
4011 DHD_ERROR(("%s (nextlen): readahead on control"
4012 " packet %d?\n", __FUNCTION__, seq));
4013 /* Force retry w/normal header read */
4014 bus->nextlen = 0;
4015 dhdsdio_rxfail(bus, FALSE, TRUE);
4016 dhd_os_sdlock_rxq(bus->dhd);
4017 PKTFREE2();
4018 dhd_os_sdunlock_rxq(bus->dhd);
4019 continue;
4020 }
4021 }
4022
4023 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
4024 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
4025 "rx pktbuf's or not yet malloced.\n", len, chan));
4026 continue;
4027 }
4028
4029 /* Validate data offset */
4030 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
4031 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
4032 __FUNCTION__, doff, len, SDPCM_HDRLEN));
4033 dhd_os_sdlock_rxq(bus->dhd);
4034 PKTFREE2();
4035 dhd_os_sdunlock_rxq(bus->dhd);
4036 ASSERT(0);
4037 dhdsdio_rxfail(bus, FALSE, FALSE);
4038 continue;
4039 }
4040
4041 /* All done with this one -- now deliver the packet */
4042 goto deliver;
4043 }
4044 /* gSPI frames should not be handled in fractions */
4045 if (bus->bus == SPI_BUS) {
4046 break;
4047 }
4048
4049 /* Read frame header (hardware and software) */
4050 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4051 bus->rxhdr, firstread, NULL, NULL, NULL);
4052 bus->f2rxhdrs++;
4053 ASSERT(sdret != BCME_PENDING);
4054
4055 if (sdret < 0) {
4056 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
4057 bus->rx_hdrfail++;
4058 dhdsdio_rxfail(bus, TRUE, TRUE);
4059 continue;
4060 }
4061
4062#ifdef DHD_DEBUG
4063 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
4064 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
4065 }
4066#endif
4067
4068 /* Extract hardware header fields */
4069 len = ltoh16_ua(bus->rxhdr);
4070 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
4071
4072 /* All zeros means no more frames */
4073 if (!(len|check)) {
4074 *finished = TRUE;
4075 break;
4076 }
4077
4078 /* Validate check bytes */
4079 if ((uint16)~(len^check)) {
4080 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
4081 __FUNCTION__, len, check));
4082 bus->rx_badhdr++;
4083 dhdsdio_rxfail(bus, FALSE, FALSE);
4084 continue;
4085 }
4086
4087 /* Validate frame length */
4088 if (len < SDPCM_HDRLEN) {
4089 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
4090 continue;
4091 }
4092
4093 /* Extract software header fields */
4094 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4095 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4096 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4097 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4098
4099 /* Validate data offset */
4100 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
4101 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
4102 __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
4103 bus->rx_badhdr++;
4104 ASSERT(0);
4105 dhdsdio_rxfail(bus, FALSE, FALSE);
4106 continue;
4107 }
4108
4109 /* Save the readahead length if there is one */
4110 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
4111 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
4112 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
4113 __FUNCTION__, bus->nextlen, seq));
4114 bus->nextlen = 0;
4115 }
4116
4117 /* Handle Flow Control */
4118 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
4119
4120 delta = 0;
4121 if (~bus->flowcontrol & fcbits) {
4122 bus->fc_xoff++;
4123 delta = 1;
4124 }
4125 if (bus->flowcontrol & ~fcbits) {
4126 bus->fc_xon++;
4127 delta = 1;
4128 }
4129
4130 if (delta) {
4131 bus->fc_rcvd++;
4132 bus->flowcontrol = fcbits;
4133 }
4134
4135 /* Check and update sequence number */
4136 if (rxseq != seq) {
4137 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
4138 bus->rx_badseq++;
4139 rxseq = seq;
4140 }
4141
4142 /* Check window for sanity */
4143 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
4144 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
4145 __FUNCTION__, txmax, bus->tx_seq));
4146 txmax = bus->tx_seq;
4147 }
4148 bus->tx_max = txmax;
4149
4150 /* Call a separate function for control frames */
4151 if (chan == SDPCM_CONTROL_CHANNEL) {
4152 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
4153 continue;
4154 }
4155
4156 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
4157 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
4158
4159 /* Length to read */
4160 rdlen = (len > firstread) ? (len - firstread) : 0;
4161
4162 /* May pad read to blocksize for efficiency */
4163 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
4164 pad = bus->blocksize - (rdlen % bus->blocksize);
4165 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
4166 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
4167 rdlen += pad;
4168 } else if (rdlen % DHD_SDALIGN) {
4169 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
4170 }
4171
4172 /* Satisfy length-alignment requirements */
4173 if (forcealign && (rdlen & (ALIGNMENT - 1)))
4174 rdlen = ROUNDUP(rdlen, ALIGNMENT);
4175
4176 if ((rdlen + firstread) > MAX_RX_DATASZ) {
4177 /* Too long -- skip this frame */
4178 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
4179 bus->dhd->rx_errors++; bus->rx_toolong++;
4180 dhdsdio_rxfail(bus, FALSE, FALSE);
4181 continue;
4182 }
4183
4184 dhd_os_sdlock_rxq(bus->dhd);
4185 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
4186 /* Give up on data, request rtx of events */
4187 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
4188 __FUNCTION__, rdlen, chan));
4189 bus->dhd->rx_dropped++;
4190 dhd_os_sdunlock_rxq(bus->dhd);
4191 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
4192 continue;
4193 }
4194 dhd_os_sdunlock_rxq(bus->dhd);
4195
4196 ASSERT(!PKTLINK(pkt));
4197
4198 /* Leave room for what we already read, and align remainder */
4199 ASSERT(firstread < (PKTLEN(osh, pkt)));
4200 PKTPULL(osh, pkt, firstread);
4201 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
4202
4203 /* Read the remaining frame data */
4204 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4205 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
4206 bus->f2rxdata++;
4207 ASSERT(sdret != BCME_PENDING);
4208
4209 if (sdret < 0) {
4210 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
4211 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
4212 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
4213 dhd_os_sdlock_rxq(bus->dhd);
4214 PKTFREE(bus->dhd->osh, pkt, FALSE);
4215 dhd_os_sdunlock_rxq(bus->dhd);
4216 bus->dhd->rx_errors++;
4217 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
4218 continue;
4219 }
4220
4221 /* Copy the already-read portion */
4222 PKTPUSH(osh, pkt, firstread);
4223 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
4224
4225#ifdef DHD_DEBUG
4226 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4227 prhex("Rx Data", PKTDATA(osh, pkt), len);
4228 }
4229#endif
4230
4231deliver:
4232 /* Save superframe descriptor and allocate packet frame */
4233 if (chan == SDPCM_GLOM_CHANNEL) {
4234 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
4235 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
4236 __FUNCTION__, len));
4237#ifdef DHD_DEBUG
4238 if (DHD_GLOM_ON()) {
4239 prhex("Glom Data", PKTDATA(osh, pkt), len);
4240 }
4241#endif
4242 PKTSETLEN(osh, pkt, len);
4243 ASSERT(doff == SDPCM_HDRLEN);
4244 PKTPULL(osh, pkt, SDPCM_HDRLEN);
4245 bus->glomd = pkt;
4246 } else {
4247 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
4248 dhdsdio_rxfail(bus, FALSE, FALSE);
4249 }
4250 continue;
4251 }
4252
4253 /* Fill in packet len and prio, deliver upward */
4254 PKTSETLEN(osh, pkt, len);
4255 PKTPULL(osh, pkt, doff);
4256
4257#ifdef SDTEST
4258 /* Test channel packets are processed separately */
4259 if (chan == SDPCM_TEST_CHANNEL) {
4260 dhdsdio_testrcv(bus, pkt, seq);
4261 continue;
4262 }
4263#endif /* SDTEST */
4264
4265 if (PKTLEN(osh, pkt) == 0) {
4266 dhd_os_sdlock_rxq(bus->dhd);
4267 PKTFREE(bus->dhd->osh, pkt, FALSE);
4268 dhd_os_sdunlock_rxq(bus->dhd);
4269 continue;
4270 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt) != 0) {
4271 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
4272 dhd_os_sdlock_rxq(bus->dhd);
4273 PKTFREE(bus->dhd->osh, pkt, FALSE);
4274 dhd_os_sdunlock_rxq(bus->dhd);
4275 bus->dhd->rx_errors++;
4276 continue;
4277 }
4278
4279
4280 /* Unlock during rx call */
4281 dhd_os_sdunlock(bus->dhd);
4282 dhd_rx_frame(bus->dhd, ifidx, pkt, 1, chan);
4283 dhd_os_sdlock(bus->dhd);
4284 }
4285 rxcount = maxframes - rxleft;
4286#ifdef DHD_DEBUG
4287 /* Message if we hit the limit */
4288 if (!rxleft && !sdtest)
4289 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
4290 else
4291#endif /* DHD_DEBUG */
4292 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
4293 /* Back off rxseq if awaiting rtx, update rx_seq */
4294 if (bus->rxskip)
4295 rxseq--;
4296 bus->rx_seq = rxseq;
4297
4298 return rxcount;
4299}
4300
4301static uint32
4302dhdsdio_hostmail(dhd_bus_t *bus)
4303{
4304 sdpcmd_regs_t *regs = bus->regs;
4305 uint32 intstatus = 0;
4306 uint32 hmb_data;
4307 uint8 fcbits;
4308 uint retries = 0;
4309
4310 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4311
4312 /* Read mailbox data and ack that we did so */
4313 R_SDREG(hmb_data, &regs->tohostmailboxdata, retries);
4314 if (retries <= retry_limit)
4315 W_SDREG(SMB_INT_ACK, &regs->tosbmailbox, retries);
4316 bus->f1regdata += 2;
4317
4318 /* Dongle recomposed rx frames, accept them again */
4319 if (hmb_data & HMB_DATA_NAKHANDLED) {
4320 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
4321 if (!bus->rxskip) {
4322 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
4323 }
4324 bus->rxskip = FALSE;
4325 intstatus |= FRAME_AVAIL_MASK(bus);
4326 }
4327
4328 /*
4329 * DEVREADY does not occur with gSPI.
4330 */
4331 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
4332 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
4333 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
4334 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
4335 bus->sdpcm_ver, SDPCM_PROT_VERSION));
4336 else
4337 DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
4338 /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */
4339 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
4340 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) {
4341 uint32 val;
4342
4343 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
4344 val &= ~CC_XMTDATAAVAIL_MODE;
4345 val |= CC_XMTDATAAVAIL_CTRL;
4346 W_REG(bus->dhd->osh, &bus->regs->corecontrol, val);
4347
4348 val = R_REG(bus->dhd->osh, &bus->regs->corecontrol);
4349 }
4350
4351#ifdef DHD_DEBUG
4352 /* Retrieve console state address now that firmware should have updated it */
4353 {
4354 sdpcm_shared_t shared;
4355 if (dhdsdio_readshared(bus, &shared) == 0)
4356 bus->console_addr = shared.console_addr;
4357 }
4358#endif /* DHD_DEBUG */
4359 }
4360
4361 /*
4362 * Flow Control has been moved into the RX headers and this out of band
4363 * method isn't used any more. Leave this here for possibly remaining backward
4364 * compatible with older dongles
4365 */
4366 if (hmb_data & HMB_DATA_FC) {
4367 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
4368
4369 if (fcbits & ~bus->flowcontrol)
4370 bus->fc_xoff++;
4371 if (bus->flowcontrol & ~fcbits)
4372 bus->fc_xon++;
4373
4374 bus->fc_rcvd++;
4375 bus->flowcontrol = fcbits;
4376 }
4377
4378#ifdef DHD_DEBUG
4379 /* At least print a message if FW halted */
4380 if (hmb_data & HMB_DATA_FWHALT) {
4381 DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED\n"));
4382 dhdsdio_checkdied(bus, NULL, 0);
4383 }
4384#endif /* DHD_DEBUG */
4385
4386 /* Shouldn't be any others */
4387 if (hmb_data & ~(HMB_DATA_DEVREADY |
4388 HMB_DATA_FWHALT |
4389 HMB_DATA_NAKHANDLED |
4390 HMB_DATA_FC |
4391 HMB_DATA_FWREADY |
4392 HMB_DATA_FCDATA_MASK |
4393 HMB_DATA_VERSION_MASK)) {
4394 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
4395 }
4396
4397 return intstatus;
4398}
4399
4400static bool
4401dhdsdio_dpc(dhd_bus_t *bus)
4402{
4403 bcmsdh_info_t *sdh = bus->sdh;
4404 sdpcmd_regs_t *regs = bus->regs;
4405 uint32 intstatus, newstatus = 0;
4406 uint retries = 0;
4407 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
4408 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
4409 uint framecnt = 0; /* Temporary counter of tx/rx frames */
4410 bool rxdone = TRUE; /* Flag for no more read data */
4411 bool resched = FALSE; /* Flag indicating resched wanted */
4412
4413 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4414
4415 if (bus->dhd->busstate == DHD_BUS_DOWN) {
4416 DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__));
4417 bus->intstatus = 0;
4418 return 0;
4419 }
4420
4421 /* Start with leftover status bits */
4422 intstatus = bus->intstatus;
4423
4424 dhd_os_sdlock(bus->dhd);
4425
4426 /* If waiting for HTAVAIL, check status */
4427 if (bus->clkstate == CLK_PENDING) {
4428 int err;
4429 uint8 clkctl, devctl = 0;
4430
4431#ifdef DHD_DEBUG
4432 /* Check for inconsistent device control */
4433 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
4434 if (err) {
4435 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
4436 bus->dhd->busstate = DHD_BUS_DOWN;
4437 } else {
4438 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
4439 }
4440#endif /* DHD_DEBUG */
4441
4442 /* Read CSR, if clock on switch to AVAIL, else ignore */
4443 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4444 if (err) {
4445 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
4446 bus->dhd->busstate = DHD_BUS_DOWN;
4447 }
4448
4449 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
4450
4451 if (SBSDIO_HTAV(clkctl)) {
4452 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
4453 if (err) {
4454 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
4455 __FUNCTION__, err));
4456 bus->dhd->busstate = DHD_BUS_DOWN;
4457 }
4458 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
4459 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
4460 if (err) {
4461 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
4462 __FUNCTION__, err));
4463 bus->dhd->busstate = DHD_BUS_DOWN;
4464 }
4465 bus->clkstate = CLK_AVAIL;
4466 } else {
4467 goto clkwait;
4468 }
4469 }
4470
4471 BUS_WAKE(bus);
4472
4473 /* Make sure backplane clock is on */
4474 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
4475 if (bus->clkstate != CLK_AVAIL)
4476 goto clkwait;
4477
4478 /* Pending interrupt indicates new device status */
4479 if (bus->ipend) {
4480 bus->ipend = FALSE;
4481 R_SDREG(newstatus, &regs->intstatus, retries);
4482 bus->f1regdata++;
4483 if (bcmsdh_regfail(bus->sdh))
4484 newstatus = 0;
4485 newstatus &= bus->hostintmask;
4486 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
4487 if (newstatus) {
4488 bus->f1regdata++;
4489 if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) &&
4490 (newstatus == I_XMTDATA_AVAIL)) {
4491 }
4492 else
4493 W_SDREG(newstatus, &regs->intstatus, retries);
4494 }
4495 }
4496
4497 /* Merge new bits with previous */
4498 intstatus |= newstatus;
4499 bus->intstatus = 0;
4500
4501 /* Handle flow-control change: read new state in case our ack
4502 * crossed another change interrupt. If change still set, assume
4503 * FC ON for safety, let next loop through do the debounce.
4504 */
4505 if (intstatus & I_HMB_FC_CHANGE) {
4506 intstatus &= ~I_HMB_FC_CHANGE;
4507 W_SDREG(I_HMB_FC_CHANGE, &regs->intstatus, retries);
4508 R_SDREG(newstatus, &regs->intstatus, retries);
4509 bus->f1regdata += 2;
4510 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
4511 intstatus |= (newstatus & bus->hostintmask);
4512 }
4513
4514 /* Just being here means nothing more to do for chipactive */
4515 if (intstatus & I_CHIPACTIVE) {
4516 /* ASSERT(bus->clkstate == CLK_AVAIL); */
4517 intstatus &= ~I_CHIPACTIVE;
4518 }
4519
4520 /* Handle host mailbox indication */
4521 if (intstatus & I_HMB_HOST_INT) {
4522 intstatus &= ~I_HMB_HOST_INT;
4523 intstatus |= dhdsdio_hostmail(bus);
4524 }
4525
4526 /* Generally don't ask for these, can get CRC errors... */
4527 if (intstatus & I_WR_OOSYNC) {
4528 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
4529 intstatus &= ~I_WR_OOSYNC;
4530 }
4531
4532 if (intstatus & I_RD_OOSYNC) {
4533 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
4534 intstatus &= ~I_RD_OOSYNC;
4535 }
4536
4537 if (intstatus & I_SBINT) {
4538 DHD_ERROR(("Dongle reports SBINT\n"));
4539 intstatus &= ~I_SBINT;
4540 }
4541
4542 /* Would be active due to wake-wlan in gSPI */
4543 if (intstatus & I_CHIPACTIVE) {
4544 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
4545 intstatus &= ~I_CHIPACTIVE;
4546 }
4547
4548 /* Ignore frame indications if rxskip is set */
4549 if (bus->rxskip) {
4550 intstatus &= ~FRAME_AVAIL_MASK(bus);
4551 }
4552
4553 /* On frame indication, read available frames */
4554 if (PKT_AVAILABLE(bus, intstatus)) {
4555 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
4556 if (rxdone || bus->rxskip)
4557 intstatus &= ~FRAME_AVAIL_MASK(bus);
4558 rxlimit -= MIN(framecnt, rxlimit);
4559 }
4560
4561 /* Keep still-pending events for next scheduling */
4562 bus->intstatus = intstatus;
4563
4564clkwait:
4565 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
4566 * or clock availability. (Allows tx loop to check ipend if desired.)
4567 * (Unless register access seems hosed, as we may not be able to ACK...)
4568 */
4569 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
4570 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
4571 __FUNCTION__, rxdone, framecnt));
4572 bus->intdis = FALSE;
4573#if defined(OOB_INTR_ONLY)
4574 bcmsdh_oob_intr_set(1);
4575#endif /* (OOB_INTR_ONLY) */
4576 bcmsdh_intr_enable(sdh);
4577 }
4578
4579 if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
4580 int ret, i;
4581
4582 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4583 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
4584 NULL, NULL, NULL);
4585 ASSERT(ret != BCME_PENDING);
4586
4587 if (ret < 0) {
4588 /* On failure, abort the command and terminate the frame */
4589 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
4590 __FUNCTION__, ret));
4591 bus->tx_sderrs++;
4592
4593 bcmsdh_abort(sdh, SDIO_FUNC_2);
4594
4595 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
4596 SFC_WF_TERM, NULL);
4597 bus->f1regdata++;
4598
4599 for (i = 0; i < 3; i++) {
4600 uint8 hi, lo;
4601 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4602 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
4603 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4604 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
4605 bus->f1regdata += 2;
4606 if ((hi == 0) && (lo == 0))
4607 break;
4608 }
4609 }
4610 if (ret == 0) {
4611 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
4612 }
4613
4614 bus->ctrl_frame_stat = FALSE;
4615 dhd_wait_event_wakeup(bus->dhd);
4616 }
4617 /* Send queued frames (limit 1 if rx may still be pending) */
4618 else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
4619 pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
4620 framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
4621 framecnt = dhdsdio_sendfromq(bus, framecnt);
4622 txlimit -= framecnt;
4623 }
4624 /* Resched the DPC if ctrl cmd is pending on bus credit */
4625 if (bus->ctrl_frame_stat)
4626 resched = TRUE;
4627
4628 /* Resched if events or tx frames are pending, else await next interrupt */
4629 /* On failed register access, all bets are off: no resched or interrupts */
4630 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
4631 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation %d \n",
4632 __FUNCTION__, bcmsdh_regfail(sdh)));
4633 bus->dhd->busstate = DHD_BUS_DOWN;
4634 bus->intstatus = 0;
4635 } else if (bus->clkstate == CLK_PENDING) {
4636 /* Awaiting I_CHIPACTIVE; don't resched */
4637 } else if (bus->intstatus || bus->ipend ||
4638 (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
4639 PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */
4640 resched = TRUE;
4641 }
4642
4643 bus->dpc_sched = resched;
4644
4645 /* If we're done for now, turn off clock request. */
4646 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) {
4647 bus->activity = FALSE;
4648 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4649 }
4650
4651 dhd_os_sdunlock(bus->dhd);
4652 return resched;
4653}
4654
4655bool
4656dhd_bus_dpc(struct dhd_bus *bus)
4657{
4658 bool resched;
4659
4660 /* Call the DPC directly. */
4661 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
4662 resched = dhdsdio_dpc(bus);
4663
4664 return resched;
4665}
4666
4667void
4668dhdsdio_isr(void *arg)
4669{
4670 dhd_bus_t *bus = (dhd_bus_t*)arg;
4671 bcmsdh_info_t *sdh;
4672
4673 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4674
4675 if (!bus) {
4676 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
4677 return;
4678 }
4679 sdh = bus->sdh;
4680
4681 if (bus->dhd->busstate == DHD_BUS_DOWN) {
4682 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
4683 return;
4684 }
4685
4686 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4687
4688 /* Count the interrupt call */
4689 bus->intrcount++;
4690 bus->ipend = TRUE;
4691
4692 /* Shouldn't get this interrupt if we're sleeping? */
4693 if (bus->sleeping) {
4694 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
4695 return;
4696 }
4697
4698 /* Disable additional interrupts (is this needed now)? */
4699 if (bus->intr) {
4700 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4701 } else {
4702 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
4703 }
4704
4705 bcmsdh_intr_disable(sdh);
4706 bus->intdis = TRUE;
4707
4708#if defined(SDIO_ISR_THREAD)
4709 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
4710 DHD_OS_WAKE_LOCK(bus->dhd);
4711 while (dhdsdio_dpc(bus));
4712 DHD_OS_WAKE_UNLOCK(bus->dhd);
4713#else
4714 bus->dpc_sched = TRUE;
4715 dhd_sched_dpc(bus->dhd);
4716#endif
4717
4718}
4719
4720#ifdef SDTEST
4721static void
4722dhdsdio_pktgen_init(dhd_bus_t *bus)
4723{
4724 /* Default to specified length, or full range */
4725 if (dhd_pktgen_len) {
4726 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
4727 bus->pktgen_minlen = bus->pktgen_maxlen;
4728 } else {
4729 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
4730 bus->pktgen_minlen = 0;
4731 }
4732 bus->pktgen_len = (uint16)bus->pktgen_minlen;
4733
4734 /* Default to per-watchdog burst with 10s print time */
4735 bus->pktgen_freq = 1;
4736 bus->pktgen_print = 10000 / dhd_watchdog_ms;
4737 bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
4738
4739 /* Default to echo mode */
4740 bus->pktgen_mode = DHD_PKTGEN_ECHO;
4741 bus->pktgen_stop = 1;
4742}
4743
4744static void
4745dhdsdio_pktgen(dhd_bus_t *bus)
4746{
4747 void *pkt;
4748 uint8 *data;
4749 uint pktcount;
4750 uint fillbyte;
4751 osl_t *osh = bus->dhd->osh;
4752 uint16 len;
4753
4754 /* Display current count if appropriate */
4755 if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
4756 bus->pktgen_ptick = 0;
4757 printf("%s: send attempts %d rcvd %d\n",
4758 __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd);
4759 }
4760
4761 /* For recv mode, just make sure dongle has started sending */
4762 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
4763 if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) {
4764 bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING;
4765 dhdsdio_sdtest_set(bus, (uint8)bus->pktgen_total);
4766 }
4767 return;
4768 }
4769
4770 /* Otherwise, generate or request the specified number of packets */
4771 for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
4772 /* Stop if total has been reached */
4773 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
4774 bus->pktgen_count = 0;
4775 break;
4776 }
4777
4778 /* Allocate an appropriate-sized packet */
4779 len = bus->pktgen_len;
4780 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
4781 TRUE))) {;
4782 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
4783 break;
4784 }
4785 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
4786 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4787
4788 /* Write test header cmd and extra based on mode */
4789 switch (bus->pktgen_mode) {
4790 case DHD_PKTGEN_ECHO:
4791 *data++ = SDPCM_TEST_ECHOREQ;
4792 *data++ = (uint8)bus->pktgen_sent;
4793 break;
4794
4795 case DHD_PKTGEN_SEND:
4796 *data++ = SDPCM_TEST_DISCARD;
4797 *data++ = (uint8)bus->pktgen_sent;
4798 break;
4799
4800 case DHD_PKTGEN_RXBURST:
4801 *data++ = SDPCM_TEST_BURST;
4802 *data++ = (uint8)bus->pktgen_count;
4803 break;
4804
4805 default:
4806 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
4807 PKTFREE(osh, pkt, TRUE);
4808 bus->pktgen_count = 0;
4809 return;
4810 }
4811
4812 /* Write test header length field */
4813 *data++ = (len >> 0);
4814 *data++ = (len >> 8);
4815
4816 /* Then fill in the remainder -- N/A for burst, but who cares... */
4817 for (fillbyte = 0; fillbyte < len; fillbyte++)
4818 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
4819
4820#ifdef DHD_DEBUG
4821 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4822 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4823 prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
4824 }
4825#endif
4826
4827 /* Send it */
4828 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE)) {
4829 bus->pktgen_fail++;
4830 if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
4831 bus->pktgen_count = 0;
4832 }
4833 bus->pktgen_sent++;
4834
4835 /* Bump length if not fixed, wrap at max */
4836 if (++bus->pktgen_len > bus->pktgen_maxlen)
4837 bus->pktgen_len = (uint16)bus->pktgen_minlen;
4838
4839 /* Special case for burst mode: just send one request! */
4840 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
4841 break;
4842 }
4843}
4844
4845static void
4846dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count)
4847{
4848 void *pkt;
4849 uint8 *data;
4850 osl_t *osh = bus->dhd->osh;
4851
4852 /* Allocate the packet */
4853 if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, TRUE))) {
4854 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
4855 return;
4856 }
4857 PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
4858 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4859
4860 /* Fill in the test header */
4861 *data++ = SDPCM_TEST_SEND;
4862 *data++ = count;
4863 *data++ = (bus->pktgen_maxlen >> 0);
4864 *data++ = (bus->pktgen_maxlen >> 8);
4865
4866 /* Send it */
4867 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE))
4868 bus->pktgen_fail++;
4869}
4870
4871
4872static void
4873dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
4874{
4875 osl_t *osh = bus->dhd->osh;
4876 uint8 *data;
4877 uint pktlen;
4878
4879 uint8 cmd;
4880 uint8 extra;
4881 uint16 len;
4882 uint16 offset;
4883
4884 /* Check for min length */
4885 if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
4886 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
4887 PKTFREE(osh, pkt, FALSE);
4888 return;
4889 }
4890
4891 /* Extract header fields */
4892 data = PKTDATA(osh, pkt);
4893 cmd = *data++;
4894 extra = *data++;
4895 len = *data++; len += *data++ << 8;
4896 DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len));
4897 /* Check length for relevant commands */
4898 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
4899 if (pktlen != len + SDPCM_TEST_HDRLEN) {
4900 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
4901 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
4902 PKTFREE(osh, pkt, FALSE);
4903 return;
4904 }
4905 }
4906
4907 /* Process as per command */
4908 switch (cmd) {
4909 case SDPCM_TEST_ECHOREQ:
4910 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
4911 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
4912 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE) == 0) {
4913 bus->pktgen_sent++;
4914 } else {
4915 bus->pktgen_fail++;
4916 PKTFREE(osh, pkt, FALSE);
4917 }
4918 bus->pktgen_rcvd++;
4919 break;
4920
4921 case SDPCM_TEST_ECHORSP:
4922 if (bus->ext_loop) {
4923 PKTFREE(osh, pkt, FALSE);
4924 bus->pktgen_rcvd++;
4925 break;
4926 }
4927
4928 for (offset = 0; offset < len; offset++, data++) {
4929 if (*data != SDPCM_TEST_FILL(offset, extra)) {
4930 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
4931 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
4932 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
4933 break;
4934 }
4935 }
4936 PKTFREE(osh, pkt, FALSE);
4937 bus->pktgen_rcvd++;
4938 break;
4939
4940 case SDPCM_TEST_DISCARD:
4941 {
4942 int i = 0;
4943 uint8 *prn = data;
4944 uint8 testval = extra;
4945 for (i = 0; i < len; i++) {
4946 if (*prn != testval) {
4947 DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n",
4948 i, bus->pktgen_rcvd_rcvsession, testval, *prn));
4949 prn++; testval++;
4950 }
4951 }
4952 }
4953 PKTFREE(osh, pkt, FALSE);
4954 bus->pktgen_rcvd++;
4955 break;
4956
4957 case SDPCM_TEST_BURST:
4958 case SDPCM_TEST_SEND:
4959 default:
4960 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
4961 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
4962 PKTFREE(osh, pkt, FALSE);
4963 break;
4964 }
4965
4966 /* For recv mode, stop at limit (and tell dongle to stop sending) */
4967 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
4968 if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) {
4969 bus->pktgen_rcvd_rcvsession++;
4970
4971 if (bus->pktgen_total &&
4972 (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) {
4973 bus->pktgen_count = 0;
4974 DHD_ERROR(("Pktgen:rcv test complete!\n"));
4975 bus->pktgen_rcv_state = PKTGEN_RCV_IDLE;
4976 dhdsdio_sdtest_set(bus, FALSE);
4977 bus->pktgen_rcvd_rcvsession = 0;
4978 }
4979 }
4980 }
4981}
4982#endif /* SDTEST */
4983
4984extern void
4985dhd_disable_intr(dhd_pub_t *dhdp)
4986{
4987 dhd_bus_t *bus;
4988 bus = dhdp->bus;
4989 bcmsdh_intr_disable(bus->sdh);
4990}
4991
4992extern bool
4993dhd_bus_watchdog(dhd_pub_t *dhdp)
4994{
4995 dhd_bus_t *bus;
4996
4997 DHD_TIMER(("%s: Enter\n", __FUNCTION__));
4998
4999 bus = dhdp->bus;
5000
5001 if (bus->dhd->dongle_reset)
5002 return FALSE;
5003
5004 /* Ignore the timer if simulating bus down */
5005 if (bus->sleeping)
5006 return FALSE;
5007
5008 if (dhdp->busstate == DHD_BUS_DOWN)
5009 return FALSE;
5010
5011 /* Poll period: check device if appropriate. */
5012 if (bus->poll && (++bus->polltick >= bus->pollrate)) {
5013 uint32 intstatus = 0;
5014
5015 /* Reset poll tick */
5016 bus->polltick = 0;
5017
5018 /* Check device if no interrupts */
5019 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
5020
5021 if (!bus->dpc_sched) {
5022 uint8 devpend;
5023 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
5024 SDIOD_CCCR_INTPEND, NULL);
5025 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
5026 }
5027
5028 /* If there is something, make like the ISR and schedule the DPC */
5029 if (intstatus) {
5030 bus->pollcnt++;
5031 bus->ipend = TRUE;
5032 if (bus->intr) {
5033 bcmsdh_intr_disable(bus->sdh);
5034 }
5035 bus->dpc_sched = TRUE;
5036 dhd_sched_dpc(bus->dhd);
5037
5038 }
5039 }
5040
5041 /* Update interrupt tracking */
5042 bus->lastintrs = bus->intrcount;
5043 }
5044
5045#ifdef DHD_DEBUG
5046 /* Poll for console output periodically */
5047 if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
5048 bus->console.count += dhd_watchdog_ms;
5049 if (bus->console.count >= dhd_console_ms) {
5050 bus->console.count -= dhd_console_ms;
5051 /* Make sure backplane clock is on */
5052 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5053 if (dhdsdio_readconsole(bus) < 0)
5054 dhd_console_ms = 0; /* On error, stop trying */
5055 }
5056 }
5057#endif /* DHD_DEBUG */
5058
5059#ifdef SDTEST
5060 /* Generate packets if configured */
5061 if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
5062 /* Make sure backplane clock is on */
5063 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5064 bus->pktgen_tick = 0;
5065 dhdsdio_pktgen(bus);
5066 }
5067#endif
5068
5069 /* On idle timeout clear activity flag and/or turn off clock */
5070 if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
5071 if (++bus->idlecount >= bus->idletime) {
5072 bus->idlecount = 0;
5073 if (bus->activity) {
5074 bus->activity = FALSE;
5075 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
5076 }
5077 }
5078 }
5079
5080 return bus->ipend;
5081}
5082
5083#ifdef DHD_DEBUG
5084extern int
5085dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
5086{
5087 dhd_bus_t *bus = dhdp->bus;
5088 uint32 addr, val;
5089 int rv;
5090 void *pkt;
5091
5092 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
5093 if (bus->console_addr == 0)
5094 return BCME_UNSUPPORTED;
5095
5096 /* Exclusive bus access */
5097 dhd_os_sdlock(bus->dhd);
5098
5099 /* Don't allow input if dongle is in reset */
5100 if (bus->dhd->dongle_reset) {
5101 dhd_os_sdunlock(bus->dhd);
5102 return BCME_NOTREADY;
5103 }
5104
5105 /* Request clock to allow SDIO accesses */
5106 BUS_WAKE(bus);
5107 /* No pend allowed since txpkt is called later, ht clk has to be on */
5108 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5109
5110 /* Zero cbuf_index */
5111 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx);
5112 val = htol32(0);
5113 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
5114 goto done;
5115
5116 /* Write message into cbuf */
5117 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf);
5118 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
5119 goto done;
5120
5121 /* Write length into vcons_in */
5122 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in);
5123 val = htol32(msglen);
5124 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
5125 goto done;
5126
5127 /* Bump dongle by sending an empty packet on the event channel.
5128 * sdpcm_sendup (RX) checks for virtual console input.
5129 */
5130 if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL)
5131 dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE);
5132
5133done:
5134 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
5135 bus->activity = FALSE;
5136 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
5137 }
5138
5139 dhd_os_sdunlock(bus->dhd);
5140
5141 return rv;
5142}
5143#endif /* DHD_DEBUG */
5144
5145#ifdef DHD_DEBUG
5146static void
5147dhd_dump_cis(uint fn, uint8 *cis)
5148{
5149 uint byte, tag, tdata;
5150 DHD_INFO(("Function %d CIS:\n", fn));
5151
5152 for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
5153 if ((byte % 16) == 0)
5154 DHD_INFO((" "));
5155 DHD_INFO(("%02x ", cis[byte]));
5156 if ((byte % 16) == 15)
5157 DHD_INFO(("\n"));
5158 if (!tdata--) {
5159 tag = cis[byte];
5160 if (tag == 0xff)
5161 break;
5162 else if (!tag)
5163 tdata = 0;
5164 else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
5165 tdata = cis[byte + 1] + 1;
5166 else
5167 DHD_INFO(("]"));
5168 }
5169 }
5170 if ((byte % 16) != 15)
5171 DHD_INFO(("\n"));
5172}
5173#endif /* DHD_DEBUG */
5174
5175static bool
5176dhdsdio_chipmatch(uint16 chipid)
5177{
5178 if (chipid == BCM4325_CHIP_ID)
5179 return TRUE;
5180 if (chipid == BCM4329_CHIP_ID)
5181 return TRUE;
5182 if (chipid == BCM4315_CHIP_ID)
5183 return TRUE;
5184 if (chipid == BCM4319_CHIP_ID)
5185 return TRUE;
5186 if (chipid == BCM4336_CHIP_ID)
5187 return TRUE;
5188 if (chipid == BCM4330_CHIP_ID)
5189 return TRUE;
5190 if (chipid == BCM43237_CHIP_ID)
5191 return TRUE;
5192 if (chipid == BCM43362_CHIP_ID)
5193 return TRUE;
5194 if (chipid == BCM43239_CHIP_ID)
5195 return TRUE;
5196 return FALSE;
5197}
5198
5199static void *
5200dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
5201 uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh, void *dev)
5202{
5203 int ret;
5204 dhd_bus_t *bus;
5205 dhd_cmn_t *cmn;
5206#ifdef GET_CUSTOM_MAC_ENABLE
5207 struct ether_addr ea_addr;
5208#endif /* GET_CUSTOM_MAC_ENABLE */
5209#ifdef PROP_TXSTATUS
5210 uint up = 0;
5211#endif
5212
5213 /* Init global variables at run-time, not as part of the declaration.
5214 * This is required to support init/de-init of the driver. Initialization
5215 * of globals as part of the declaration results in non-deterministic
5216 * behavior since the value of the globals may be different on the
5217 * first time that the driver is initialized vs subsequent initializations.
5218 */
5219 dhd_txbound = DHD_TXBOUND;
5220 dhd_rxbound = DHD_RXBOUND;
5221 dhd_alignctl = TRUE;
5222 sd1idle = TRUE;
5223 dhd_readahead = TRUE;
5224 retrydata = FALSE;
5225 dhd_doflow = FALSE;
5226 dhd_dongle_memsize = 0;
5227 dhd_txminmax = DHD_TXMINMAX;
5228
5229 forcealign = TRUE;
5230
5231
5232 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5233 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
5234
5235 /* We make assumptions about address window mappings */
5236 ASSERT((uintptr)regsva == SI_ENUM_BASE);
5237
5238 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
5239 * means early parse could fail, so here we should get either an ID
5240 * we recognize OR (-1) indicating we must request power first.
5241 */
5242 /* Check the Vendor ID */
5243 switch (venid) {
5244 case 0x0000:
5245 case VENDOR_BROADCOM:
5246 break;
5247 default:
5248 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
5249 __FUNCTION__, venid));
5250 return NULL;
5251 }
5252
5253 /* Check the Device ID and make sure it's one that we support */
5254 switch (devid) {
5255 case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
5256 case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
5257 case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
5258 DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
5259 break;
5260 case BCM4329_D11N_ID: /* 4329 802.11n dualband device */
5261 case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
5262 case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
5263 case 0x4329:
5264 DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
5265 break;
5266 case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
5267 case BCM4315_D11G_ID: /* 4315 802.11g id */
5268 case BCM4315_D11A_ID: /* 4315 802.11a id */
5269 DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
5270 break;
5271 case BCM4319_D11N_ID: /* 4319 802.11n id */
5272 case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
5273 case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
5274 DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
5275 break;
5276 case 0:
5277 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
5278 __FUNCTION__));
5279 break;
5280
5281 default:
5282 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
5283 __FUNCTION__, venid, devid));
5284 return NULL;
5285 }
5286
5287 if (osh == NULL) {
5288 /* Ask the OS interface part for an OSL handle */
5289 if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) {
5290 DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__));
5291 return NULL;
5292 }
5293 }
5294
5295 /* Allocate private bus interface state */
5296 if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
5297 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
5298 goto fail;
5299 }
5300 bzero(bus, sizeof(dhd_bus_t));
5301 bus->sdh = sdh;
5302 bus->cl_devid = (uint16)devid;
5303 bus->bus = DHD_BUS;
5304 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
5305 bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
5306
5307 /* attach the common module */
5308 if (!(cmn = dhd_common_init(bus->cl_devid, osh))) {
5309 DHD_ERROR(("%s: dhd_common_init failed\n", __FUNCTION__));
5310 goto fail;
5311 }
5312
5313 /* attempt to attach to the dongle */
5314 if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
5315 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
5316 dhd_common_deinit(NULL, cmn);
5317 goto fail;
5318 }
5319
5320 /* Attach to the dhd/OS/network interface */
5321 if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE, dev))) {
5322 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
5323 goto fail;
5324 }
5325
5326 bus->dhd->cmn = cmn;
5327 cmn->dhd = bus->dhd;
5328
5329 /* Allocate buffers */
5330 if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
5331 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
5332 goto fail;
5333 }
5334
5335 if (!(dhdsdio_probe_init(bus, osh, sdh))) {
5336 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
5337 goto fail;
5338 }
5339
5340 if (bus->intr) {
5341 /* Register interrupt callback, but mask it (not operational yet). */
5342 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
5343 bcmsdh_intr_disable(sdh);
5344 if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
5345 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
5346 __FUNCTION__, ret));
5347 goto fail;
5348 }
5349 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
5350 } else {
5351 DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n",
5352 __FUNCTION__));
5353 }
5354
5355 DHD_INFO(("%s: completed!!\n", __FUNCTION__));
5356
5357#ifdef GET_CUSTOM_MAC_ENABLE
5358 /* Read MAC address from external customer place */
5359 memset(&ea_addr, 0, sizeof(ea_addr));
5360 ret = dhd_custom_get_mac_address(ea_addr.octet);
5361 if (!ret) {
5362 memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
5363 }
5364#endif /* GET_CUSTOM_MAC_ENABLE */
5365
5366 /* if firmware path present try to download and bring up bus */
5367 if (dhd_download_fw_on_driverload && (ret = dhd_bus_start(bus->dhd)) != 0) {
5368 DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__));
5369 if (ret == BCME_NOTUP)
5370 goto fail;
5371 }
5372 /* Ok, have the per-port tell the stack we're open for business */
5373 if (dhd_net_attach(bus->dhd, 0) != 0) {
5374 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
5375 goto fail;
5376 }
5377
5378#ifdef PROP_TXSTATUS
5379 if (dhd_download_fw_on_driverload)
5380 dhd_wl_ioctl_cmd(bus->dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0);
5381#endif
5382 return bus;
5383
5384fail:
5385 dhdsdio_release(bus, osh);
5386 return NULL;
5387}
5388
5389static bool
5390dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
5391 uint16 devid)
5392{
5393 int err = 0;
5394 uint8 clkctl = 0;
5395
5396 bus->alp_only = TRUE;
5397
5398 /* Return the window to backplane enumeration space for core access */
5399 if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
5400 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
5401 }
5402
5403#ifdef DHD_DEBUG
5404 DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n",
5405 bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4)));
5406
5407#endif /* DHD_DEBUG */
5408
5409
5410 /* Force PLL off until si_attach() programs PLL control regs */
5411
5412
5413
5414 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
5415 if (!err)
5416 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
5417
5418 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
5419 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
5420 err, DHD_INIT_CLKCTL1, clkctl));
5421 goto fail;
5422 }
5423
5424
5425#ifdef DHD_DEBUG
5426 if (DHD_INFO_ON()) {
5427 uint fn, numfn;
5428 uint8 *cis[SDIOD_MAX_IOFUNCS];
5429 int err = 0;
5430
5431 numfn = bcmsdh_query_iofnum(sdh);
5432 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
5433
5434 /* Make sure ALP is available before trying to read CIS */
5435 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
5436 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
5437 !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
5438
5439 /* Now request ALP be put on the bus */
5440 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
5441 DHD_INIT_CLKCTL2, &err);
5442 OSL_DELAY(65);
5443
5444 for (fn = 0; fn <= numfn; fn++) {
5445 if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
5446 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
5447 break;
5448 }
5449 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
5450
5451 if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
5452 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
5453 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
5454 break;
5455 }
5456 dhd_dump_cis(fn, cis[fn]);
5457 }
5458
5459 while (fn-- > 0) {
5460 ASSERT(cis[fn]);
5461 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
5462 }
5463
5464 if (err) {
5465 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
5466 goto fail;
5467 }
5468 }
5469#endif /* DHD_DEBUG */
5470
5471 /* si_attach() will provide an SI handle and scan the backplane */
5472 if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
5473 &bus->vars, &bus->varsz))) {
5474 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
5475 goto fail;
5476 }
5477
5478 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
5479
5480 if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
5481 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
5482 __FUNCTION__, bus->sih->chip));
5483 goto fail;
5484 }
5485
5486
5487 si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
5488
5489
5490 /* Get info on the ARM and SOCRAM cores... */
5491 if (!DHD_NOPMU(bus)) {
5492 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
5493 (si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
5494 bus->armrev = si_corerev(bus->sih);
5495 } else {
5496 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
5497 goto fail;
5498 }
5499 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
5500 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
5501 goto fail;
5502 }
5503 bus->ramsize = bus->orig_ramsize;
5504 if (dhd_dongle_memsize)
5505 dhd_dongle_setmemsize(bus, dhd_dongle_memsize);
5506
5507 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n",
5508 bus->ramsize, bus->orig_ramsize));
5509 }
5510
5511 /* ...but normally deal with the SDPCMDEV core */
5512 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
5513 !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
5514 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
5515 goto fail;
5516 }
5517 bus->sdpcmrev = si_corerev(bus->sih);
5518
5519 /* Set core control so an SDIO reset does a backplane reset */
5520 OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
5521 bus->rxint_mode = SDIO_DEVICE_HMB_RXINT;
5522
5523 if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) &&
5524 (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1))
5525 {
5526 uint32 val;
5527
5528 val = R_REG(osh, &bus->regs->corecontrol);
5529 val &= ~CC_XMTDATAAVAIL_MODE;
5530 val |= CC_XMTDATAAVAIL_CTRL;
5531 W_REG(osh, &bus->regs->corecontrol, val);
5532 }
5533
5534
5535 pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
5536
5537 /* Locate an appropriately-aligned portion of hdrbuf */
5538 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
5539
5540 /* Set the poll and/or interrupt flags */
5541 bus->intr = (bool)dhd_intr;
5542 if ((bus->poll = (bool)dhd_poll))
5543 bus->pollrate = 1;
5544
5545 return TRUE;
5546
5547fail:
5548 if (bus->sih != NULL)
5549 si_detach(bus->sih);
5550 return FALSE;
5551}
5552
5553static bool
5554dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
5555{
5556 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5557
5558 if (bus->dhd->maxctl) {
5559 bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
5560 if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) {
5561 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
5562 __FUNCTION__, bus->rxblen));
5563 goto fail;
5564 }
5565 }
5566 /* Allocate buffer to receive glomed packet */
5567 if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
5568 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
5569 __FUNCTION__, MAX_DATA_BUF));
5570 /* release rxbuf which was already located as above */
5571 if (!bus->rxblen)
5572 DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen);
5573 goto fail;
5574 }
5575
5576 /* Align the buffer */
5577 if ((uintptr)bus->databuf % DHD_SDALIGN)
5578 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
5579 else
5580 bus->dataptr = bus->databuf;
5581
5582 return TRUE;
5583
5584fail:
5585 return FALSE;
5586}
5587
5588static bool
5589dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
5590{
5591 int32 fnum;
5592
5593 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5594
5595#ifdef SDTEST
5596 dhdsdio_pktgen_init(bus);
5597#endif /* SDTEST */
5598
5599 /* Disable F2 to clear any intermediate frame state on the dongle */
5600 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
5601
5602 bus->dhd->busstate = DHD_BUS_DOWN;
5603 bus->sleeping = FALSE;
5604 bus->rxflow = FALSE;
5605 bus->prev_rxlim_hit = 0;
5606
5607
5608 /* Done with backplane-dependent accesses, can drop clock... */
5609 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
5610
5611 /* ...and initialize clock/power states */
5612 bus->clkstate = CLK_SDONLY;
5613 bus->idletime = (int32)dhd_idletime;
5614 bus->idleclock = DHD_IDLE_ACTIVE;
5615
5616 /* Query the SD clock speed */
5617 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
5618 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
5619 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
5620 bus->sd_divisor = -1;
5621 } else {
5622 DHD_INFO(("%s: Initial value for %s is %d\n",
5623 __FUNCTION__, "sd_divisor", bus->sd_divisor));
5624 }
5625
5626 /* Query the SD bus mode */
5627 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
5628 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
5629 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
5630 bus->sd_mode = -1;
5631 } else {
5632 DHD_INFO(("%s: Initial value for %s is %d\n",
5633 __FUNCTION__, "sd_mode", bus->sd_mode));
5634 }
5635
5636 /* Query the F2 block size, set roundup accordingly */
5637 fnum = 2;
5638 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
5639 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
5640 bus->blocksize = 0;
5641 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
5642 } else {
5643 DHD_INFO(("%s: Initial value for %s is %d\n",
5644 __FUNCTION__, "sd_blocksize", bus->blocksize));
5645 }
5646 bus->roundup = MIN(max_roundup, bus->blocksize);
5647
5648 /* Query if bus module supports packet chaining, default to use if supported */
5649 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
5650 &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
5651 bus->sd_rxchain = FALSE;
5652 } else {
5653 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
5654 __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
5655 }
5656 bus->use_rxchain = (bool)bus->sd_rxchain;
5657
5658 return TRUE;
5659}
5660
5661bool
5662dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
5663 char *pfw_path, char *pnv_path)
5664{
5665 bool ret;
5666 bus->fw_path = pfw_path;
5667 bus->nv_path = pnv_path;
5668
5669 ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
5670
5671
5672 return ret;
5673}
5674
5675static bool
5676dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
5677{
5678 bool ret;
5679
5680 /* Download the firmware */
5681 DHD_OS_WAKE_LOCK(bus->dhd);
5682 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5683
5684 ret = _dhdsdio_download_firmware(bus) == 0;
5685
5686 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
5687 DHD_OS_WAKE_UNLOCK(bus->dhd);
5688 return ret;
5689}
5690
5691/* Detach and free everything */
5692static void
5693dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
5694{
5695 bool dongle_isolation = FALSE;
5696 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5697
5698 if (bus) {
5699 ASSERT(osh);
5700
5701 /* De-register interrupt handler */
5702 bcmsdh_intr_disable(bus->sdh);
5703 bcmsdh_intr_dereg(bus->sdh);
5704
5705 if (bus->dhd) {
5706 dhd_common_deinit(bus->dhd, NULL);
5707 dongle_isolation = bus->dhd->dongle_isolation;
5708 dhd_detach(bus->dhd);
5709 dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE);
5710 dhd_free(bus->dhd);
5711 bus->dhd = NULL;
5712 }
5713
5714 dhdsdio_release_malloc(bus, osh);
5715
5716#ifdef DHD_DEBUG
5717 if (bus->console.buf != NULL)
5718 MFREE(osh, bus->console.buf, bus->console.bufsize);
5719#endif
5720
5721 MFREE(osh, bus, sizeof(dhd_bus_t));
5722 }
5723
5724 if (osh)
5725 dhd_osl_detach(osh);
5726
5727 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
5728}
5729
5730static void
5731dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
5732{
5733 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5734
5735 if (bus->dhd && bus->dhd->dongle_reset)
5736 return;
5737
5738 if (bus->rxbuf) {
5739#ifndef DHD_USE_STATIC_BUF
5740 MFREE(osh, bus->rxbuf, bus->rxblen);
5741#endif
5742 bus->rxctl = bus->rxbuf = NULL;
5743 bus->rxlen = 0;
5744 }
5745
5746 if (bus->databuf) {
5747#ifndef DHD_USE_STATIC_BUF
5748 MFREE(osh, bus->databuf, MAX_DATA_BUF);
5749#endif
5750 bus->databuf = NULL;
5751 }
5752
5753 if (bus->vars && bus->varsz) {
5754 MFREE(osh, bus->vars, bus->varsz);
5755 bus->vars = NULL;
5756 }
5757
5758}
5759
5760
5761static void
5762dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag)
5763{
5764 DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__,
5765 bus->dhd, bus->dhd->dongle_reset));
5766
5767 if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
5768 return;
5769
5770 if (bus->sih) {
5771 if (bus->dhd) {
5772 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5773 }
5774#if !defined(BCMLXSDMMC)
5775 if (dongle_isolation == FALSE)
5776 si_watchdog(bus->sih, 4);
5777#endif /* !defined(BCMLXSDMMC) */
5778 if (bus->dhd) {
5779 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
5780 }
5781 si_detach(bus->sih);
5782 if (bus->vars && bus->varsz)
5783 MFREE(osh, bus->vars, bus->varsz);
5784 bus->vars = NULL;
5785 }
5786
5787 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
5788}
5789
5790static void
5791dhdsdio_disconnect(void *ptr)
5792{
5793 dhd_bus_t *bus = (dhd_bus_t *)ptr;
5794
5795 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5796
5797 if (bus) {
5798 ASSERT(bus->dhd);
5799 dhdsdio_release(bus, bus->dhd->osh);
5800 }
5801
5802 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
5803}
5804
5805
5806/* Register/Unregister functions are called by the main DHD entry
5807 * point (e.g. module insertion) to link with the bus driver, in
5808 * order to look for or await the device.
5809 */
5810
5811static bcmsdh_driver_t dhd_sdio = {
5812 dhdsdio_probe,
5813 dhdsdio_disconnect
5814};
5815
5816int
5817dhd_bus_register(void)
5818{
5819 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5820
5821 return bcmsdh_register(&dhd_sdio);
5822}
5823
5824void
5825dhd_bus_unregister(void)
5826{
5827 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5828
5829 bcmsdh_unregister();
5830}
5831
5832#ifdef BCMEMBEDIMAGE
5833static int
5834dhdsdio_download_code_array(struct dhd_bus *bus)
5835{
5836 int bcmerror = -1;
5837 int offset = 0;
5838 unsigned char *ularray = NULL;
5839
5840 DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
5841
5842 /* Download image */
5843 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
5844 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
5845 (uint8 *) (dlarray + offset), MEMBLOCK);
5846 if (bcmerror) {
5847 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5848 __FUNCTION__, bcmerror, MEMBLOCK, offset));
5849 goto err;
5850 }
5851
5852 offset += MEMBLOCK;
5853 }
5854
5855 if (offset < sizeof(dlarray)) {
5856 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
5857 (uint8 *) (dlarray + offset), sizeof(dlarray) - offset);
5858 if (bcmerror) {
5859 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5860 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
5861 goto err;
5862 }
5863 }
5864
5865#ifdef DHD_DEBUG
5866 /* Upload and compare the downloaded code */
5867 {
5868 ularray = MALLOC(bus->dhd->osh, bus->ramsize);
5869 /* Upload image to verify downloaded contents. */
5870 offset = 0;
5871 memset(ularray, 0xaa, bus->ramsize);
5872 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
5873 bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
5874 if (bcmerror) {
5875 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
5876 __FUNCTION__, bcmerror, MEMBLOCK, offset));
5877 goto err;
5878 }
5879
5880 offset += MEMBLOCK;
5881 }
5882
5883 if (offset < sizeof(dlarray)) {
5884 bcmerror = dhdsdio_membytes(bus, FALSE, offset,
5885 ularray + offset, sizeof(dlarray) - offset);
5886 if (bcmerror) {
5887 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
5888 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
5889 goto err;
5890 }
5891 }
5892
5893 if (memcmp(dlarray, ularray, sizeof(dlarray))) {
5894 DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n",
5895 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
5896 goto err;
5897 } else
5898 DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n",
5899 __FUNCTION__, dlimagename, dlimagever, dlimagedate));
5900
5901 }
5902#endif /* DHD_DEBUG */
5903
5904err:
5905 if (ularray)
5906 MFREE(bus->dhd->osh, ularray, bus->ramsize);
5907 return bcmerror;
5908}
5909#endif /* BCMEMBEDIMAGE */
5910
5911static int
5912dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path)
5913{
5914 int bcmerror = -1;
5915 int offset = 0;
5916 uint len;
5917 void *image = NULL;
5918 uint8 *memblock = NULL, *memptr;
5919
5920 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path));
5921
5922 image = dhd_os_open_image(pfw_path);
5923 if (image == NULL)
5924 goto err;
5925
5926 memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
5927 if (memblock == NULL) {
5928 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
5929 goto err;
5930 }
5931 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
5932 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
5933
5934 /* Download image */
5935 while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
5936 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
5937 if (bcmerror) {
5938 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5939 __FUNCTION__, bcmerror, MEMBLOCK, offset));
5940 goto err;
5941 }
5942
5943 offset += MEMBLOCK;
5944 }
5945
5946err:
5947 if (memblock)
5948 MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
5949
5950 if (image)
5951 dhd_os_close_image(image);
5952
5953 return bcmerror;
5954}
5955
5956/*
5957 EXAMPLE: nvram_array
5958 nvram_arry format:
5959 name=value
5960 Use carriage return at the end of each assignment, and an empty string with
5961 carriage return at the end of array.
5962
5963 For example:
5964 unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
5965 Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
5966
5967 Search "EXAMPLE: nvram_array" to see how the array is activated.
5968*/
5969
5970void
5971dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
5972{
5973 bus->nvram_params = nvram_params;
5974}
5975
5976static int
5977dhdsdio_download_nvram(struct dhd_bus *bus)
5978{
5979 int bcmerror = -1;
5980 uint len;
5981 void * image = NULL;
5982 char * memblock = NULL;
5983 char *bufp;
5984 char *pnv_path;
5985 bool nvram_file_exists;
5986
5987 pnv_path = bus->nv_path;
5988
5989 nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0'));
5990 if (!nvram_file_exists && (bus->nvram_params == NULL))
5991 return (0);
5992
5993 if (nvram_file_exists) {
5994 image = dhd_os_open_image(pnv_path);
5995 if (image == NULL)
5996 goto err;
5997 }
5998
5999 memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE);
6000 if (memblock == NULL) {
6001 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
6002 __FUNCTION__, MAX_NVRAMBUF_SIZE));
6003 goto err;
6004 }
6005
6006 /* Download variables */
6007 if (nvram_file_exists) {
6008 len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image);
6009 }
6010 else {
6011 len = strlen(bus->nvram_params);
6012 ASSERT(len <= MAX_NVRAMBUF_SIZE);
6013 memcpy(memblock, bus->nvram_params, len);
6014 }
6015 if (len > 0 && len < MAX_NVRAMBUF_SIZE) {
6016 bufp = (char *)memblock;
6017 bufp[len] = 0;
6018 len = process_nvram_vars(bufp, len);
6019 if (len % 4) {
6020 len += 4 - (len % 4);
6021 }
6022 bufp += len;
6023 *bufp++ = 0;
6024 if (len)
6025 bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
6026 if (bcmerror) {
6027 DHD_ERROR(("%s: error downloading vars: %d\n",
6028 __FUNCTION__, bcmerror));
6029 }
6030 }
6031 else {
6032 DHD_ERROR(("%s: error reading nvram file: %d\n",
6033 __FUNCTION__, len));
6034 bcmerror = BCME_SDIO_ERROR;
6035 }
6036
6037err:
6038 if (memblock)
6039 MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE);
6040
6041 if (image)
6042 dhd_os_close_image(image);
6043
6044 return bcmerror;
6045}
6046
6047static int
6048_dhdsdio_download_firmware(struct dhd_bus *bus)
6049{
6050 int bcmerror = -1;
6051 char *p;
6052
6053 bool embed = FALSE; /* download embedded firmware */
6054 bool dlok = FALSE; /* download firmware succeeded */
6055
6056 /* Out immediately if no image to download */
6057 if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
6058#ifdef BCMEMBEDIMAGE
6059 embed = TRUE;
6060#else
6061 return 0;
6062#endif
6063 }
6064
6065 /* Keep arm in reset */
6066 if (dhdsdio_download_state(bus, TRUE)) {
6067 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
6068 goto err;
6069 }
6070
6071 /* External image takes precedence if specified */
6072 if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
6073
6074 /* replace bcm43xx with bcm4330 or bcm4329 */
6075 if ((p = strstr(bus->fw_path, "bcm43xx"))) {
6076 if (bus->cl_devid == 0x4329) {
6077 *(p + 5)='2';
6078 *(p + 6)='9';
6079 }
6080 if (bus->cl_devid == 0x4330) {
6081 *(p + 5)='3';
6082 *(p + 6)='0';
6083 }
6084 }
6085
6086 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
6087 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
6088#ifdef BCMEMBEDIMAGE
6089 embed = TRUE;
6090#else
6091 goto err;
6092#endif
6093 }
6094 else {
6095 embed = FALSE;
6096 dlok = TRUE;
6097 }
6098 }
6099#ifdef BCMEMBEDIMAGE
6100 if (embed) {
6101 if (dhdsdio_download_code_array(bus)) {
6102 DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
6103 goto err;
6104 }
6105 else {
6106 dlok = TRUE;
6107 }
6108 }
6109#endif
6110 if (!dlok) {
6111 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
6112 goto err;
6113 }
6114
6115 /* EXAMPLE: nvram_array */
6116 /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
6117 /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
6118
6119 /* External nvram takes precedence if specified */
6120 if (dhdsdio_download_nvram(bus)) {
6121 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
6122 goto err;
6123 }
6124
6125 /* Take arm out of reset */
6126 if (dhdsdio_download_state(bus, FALSE)) {
6127 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
6128 goto err;
6129 }
6130
6131 bcmerror = 0;
6132
6133err:
6134 return bcmerror;
6135}
6136
6137static int
6138dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
6139 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
6140{
6141 int status;
6142
6143 status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
6144
6145 return status;
6146}
6147
6148static int
6149dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
6150 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
6151{
6152 return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle));
6153}
6154
6155uint
6156dhd_bus_chip(struct dhd_bus *bus)
6157{
6158 ASSERT(bus->sih != NULL);
6159 return bus->sih->chip;
6160}
6161
6162void *
6163dhd_bus_pub(struct dhd_bus *bus)
6164{
6165 return bus->dhd;
6166}
6167
6168void *
6169dhd_bus_txq(struct dhd_bus *bus)
6170{
6171 return &bus->txq;
6172}
6173
6174uint
6175dhd_bus_hdrlen(struct dhd_bus *bus)
6176{
6177 return SDPCM_HDRLEN;
6178}
6179
6180int
6181dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
6182{
6183 int bcmerror = 0;
6184 dhd_bus_t *bus;
6185
6186 bus = dhdp->bus;
6187
6188 if (flag == TRUE) {
6189 if (!bus->dhd->dongle_reset) {
6190 dhd_os_sdlock(dhdp);
6191 dhd_os_wd_timer(dhdp, 0);
6192#if !defined(IGNORE_ETH0_DOWN)
6193 /* Force flow control as protection when stop come before ifconfig_down */
6194 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON);
6195#endif /* !defined(IGNORE_ETH0_DOWN) */
6196 /* Expect app to have torn down any connection before calling */
6197 /* Stop the bus, disable F2 */
6198 dhd_bus_stop(bus, FALSE);
6199
6200#if defined(OOB_INTR_ONLY)
6201 /* Clean up any pending IRQ */
6202 bcmsdh_set_irq(FALSE);
6203#endif /* defined(OOB_INTR_ONLY) */
6204
6205 /* Clean tx/rx buffer pointers, detach from the dongle */
6206 dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE);
6207
6208 bus->dhd->dongle_reset = TRUE;
6209 bus->dhd->up = FALSE;
6210 dhd_os_sdunlock(dhdp);
6211
6212 DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__));
6213 /* App can now remove power from device */
6214 } else
6215 bcmerror = BCME_SDIO_ERROR;
6216 } else {
6217 /* App must have restored power to device before calling */
6218
6219 DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__));
6220
6221 if (bus->dhd->dongle_reset) {
6222 /* Turn on WLAN */
6223#ifdef DHDTHREAD
6224 dhd_os_sdlock(dhdp);
6225#endif /* DHDTHREAD */
6226 /* Reset SD client */
6227 bcmsdh_reset(bus->sdh);
6228
6229 /* Attempt to re-attach & download */
6230 if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
6231 (uint32 *)SI_ENUM_BASE,
6232 bus->cl_devid)) {
6233 /* Attempt to download binary to the dongle */
6234 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
6235 dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) {
6236
6237 /* Re-init bus, enable F2 transfer */
6238 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
6239 if (bcmerror == BCME_OK) {
6240#if defined(OOB_INTR_ONLY)
6241 bcmsdh_set_irq(TRUE);
6242 dhd_enable_oob_intr(bus, TRUE);
6243#endif /* defined(OOB_INTR_ONLY) */
6244
6245 bus->dhd->dongle_reset = FALSE;
6246 bus->dhd->up = TRUE;
6247
6248#if !defined(IGNORE_ETH0_DOWN)
6249 /* Restore flow control */
6250 dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF);
6251#endif
6252 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
6253
6254 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
6255 } else {
6256 dhd_bus_stop(bus, FALSE);
6257 dhdsdio_release_dongle(bus, bus->dhd->osh,
6258 TRUE, FALSE);
6259 }
6260 } else
6261 bcmerror = BCME_SDIO_ERROR;
6262 } else
6263 bcmerror = BCME_SDIO_ERROR;
6264
6265#ifdef DHDTHREAD
6266 dhd_os_sdunlock(dhdp);
6267#endif /* DHDTHREAD */
6268 } else {
6269 bcmerror = BCME_SDIO_ERROR;
6270 DHD_INFO(("%s called when dongle is not in reset\n",
6271 __FUNCTION__));
6272 DHD_INFO(("Will call dhd_bus_start instead\n"));
6273 sdioh_start(NULL, 1);
6274 if ((bcmerror = dhd_bus_start(dhdp)) != 0)
6275 DHD_ERROR(("%s: dhd_bus_start fail with %d\n",
6276 __FUNCTION__, bcmerror));
6277 }
6278 }
6279 return bcmerror;
6280}
6281
6282int
6283dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size)
6284{
6285 dhd_bus_t *bus;
6286
6287 bus = dhdp->bus;
6288 return dhdsdio_membytes(bus, set, address, data, size);
6289}
diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/dhd_wlfc.h
new file mode 100644
index 00000000000..59d018b64c6
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.h
@@ -0,0 +1,266 @@
1/*
2* Copyright (C) 1999-2011, Broadcom Corporation
3*
4* Unless you and Broadcom execute a separate written software license
5* agreement governing use of this software, this software is licensed to you
6* under the terms of the GNU General Public License version 2 (the "GPL"),
7* available at http://www.broadcom.com/licenses/GPLv2.php, with the
8* following added to such license:
9*
10* As a special exception, the copyright holders of this software give you
11* permission to link this software with independent modules, and to copy and
12* distribute the resulting executable under terms of your choice, provided that
13* you also meet, for each linked independent module, the terms and conditions of
14* the license of that module. An independent module is a module which is not
15* derived from this software. The special exception does not apply to any
16* modifications of the software.
17*
18* Notwithstanding the above, under no circumstances may you combine this
19* software in any way with any other Broadcom software provided under a license
20* other than the GPL, without Broadcom's express prior written consent.
21* $Id: dhd_wlfc.h,v 1.1.8.1 2010-09-09 22:41:08 Exp $
22*
23*/
24#ifndef __wlfc_host_driver_definitions_h__
25#define __wlfc_host_driver_definitions_h__
26
27/* 16 bits will provide an absolute max of 65536 slots */
28#define WLFC_HANGER_MAXITEMS 1024
29
30#define WLFC_HANGER_ITEM_STATE_FREE 1
31#define WLFC_HANGER_ITEM_STATE_INUSE 2
32
33#define WLFC_PKTID_HSLOT_MASK 0xffff /* allow 16 bits only */
34#define WLFC_PKTID_HSLOT_SHIFT 8
35
36/* x -> TXSTATUS TAG to/from firmware */
37#define WLFC_PKTID_HSLOT_GET(x) \
38 (((x) >> WLFC_PKTID_HSLOT_SHIFT) & WLFC_PKTID_HSLOT_MASK)
39#define WLFC_PKTID_HSLOT_SET(var, slot) \
40 ((var) = ((var) & ~(WLFC_PKTID_HSLOT_MASK << WLFC_PKTID_HSLOT_SHIFT)) | \
41 (((slot) & WLFC_PKTID_HSLOT_MASK) << WLFC_PKTID_HSLOT_SHIFT))
42
43#define WLFC_PKTID_FREERUNCTR_MASK 0xff
44
45#define WLFC_PKTID_FREERUNCTR_GET(x) ((x) & WLFC_PKTID_FREERUNCTR_MASK)
46#define WLFC_PKTID_FREERUNCTR_SET(var, ctr) \
47 ((var) = (((var) & ~WLFC_PKTID_FREERUNCTR_MASK) | \
48 (((ctr) & WLFC_PKTID_FREERUNCTR_MASK))))
49
50#define WLFC_PKTQ_PENQ(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec)))? \
51 NULL : pktq_penq((pq), (prec), (p)))
52#define WLFC_PKTQ_PENQ_HEAD(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec))) ? \
53 NULL : pktq_penq_head((pq), (prec), (p)))
54
55typedef enum ewlfc_packet_state {
56 eWLFC_PKTTYPE_NEW,
57 eWLFC_PKTTYPE_DELAYED,
58 eWLFC_PKTTYPE_SUPPRESSED,
59 eWLFC_PKTTYPE_MAX
60} ewlfc_packet_state_t;
61
62typedef enum ewlfc_mac_entry_action {
63 eWLFC_MAC_ENTRY_ACTION_ADD,
64 eWLFC_MAC_ENTRY_ACTION_DEL,
65 eWLFC_MAC_ENTRY_ACTION_MAX
66} ewlfc_mac_entry_action_t;
67
68typedef struct wlfc_hanger_item {
69 uint8 state;
70 uint8 pad[3];
71 uint32 identifier;
72 void* pkt;
73#ifdef PROP_TXSTATUS_DEBUG
74 uint32 push_time;
75#endif
76} wlfc_hanger_item_t;
77
78typedef struct wlfc_hanger {
79 int max_items;
80 uint32 pushed;
81 uint32 popped;
82 uint32 failed_to_push;
83 uint32 failed_to_pop;
84 uint32 failed_slotfind;
85 wlfc_hanger_item_t items[1];
86} wlfc_hanger_t;
87
88#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \
89 sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t)))
90
91#define WLFC_STATE_OPEN 1
92#define WLFC_STATE_CLOSE 2
93
94#define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /* 2 for each AC traffic and bc/mc */
95#define WLFC_PSQ_LEN 64
96#define WLFC_SENDQ_LEN 256
97
98#define WLFC_FLOWCONTROL_DELTA 8
99#define WLFC_FLOWCONTROL_HIWATER (WLFC_PSQ_LEN - WLFC_FLOWCONTROL_DELTA)
100#define WLFC_FLOWCONTROL_LOWATER (WLFC_FLOWCONTROL_HIWATER - WLFC_FLOWCONTROL_DELTA)
101
102typedef struct wlfc_mac_descriptor {
103 uint8 occupied;
104 uint8 interface_id;
105 uint8 iftype;
106 uint8 state;
107 uint8 ac_bitmap; /* for APSD */
108 uint8 requested_credit;
109 uint8 requested_packet;
110 uint8 ea[ETHER_ADDR_LEN];
111 /*
112 maintain (MAC,AC) based seq count for
113 packets going to the device. As well as bc/mc.
114 */
115 uint8 seq[AC_COUNT + 1];
116 uint8 generation;
117 struct pktq psq;
118 /* The AC pending bitmap that was reported to the fw at last change */
119 uint8 traffic_lastreported_bmp;
120 /* The new AC pending bitmap */
121 uint8 traffic_pending_bmp;
122 /* 1= send on next opportunity */
123 uint8 send_tim_signal;
124 uint8 mac_handle;
125#ifdef PROP_TXSTATUS_DEBUG
126 uint32 dstncredit_sent_packets;
127 uint32 dstncredit_acks;
128 uint32 opened_ct;
129 uint32 closed_ct;
130#endif
131} wlfc_mac_descriptor_t;
132
133#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\
134 entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0)
135
136#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++
137#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)]
138
139typedef struct athost_wl_stat_counters {
140 uint32 pktin;
141 uint32 pkt2bus;
142 uint32 pktdropped;
143 uint32 tlv_parse_failed;
144 uint32 rollback;
145 uint32 rollback_failed;
146 uint32 sendq_full_error;
147 uint32 delayq_full_error;
148 uint32 credit_request_failed;
149 uint32 packet_request_failed;
150 uint32 mac_update_failed;
151 uint32 psmode_update_failed;
152 uint32 interface_update_failed;
153 uint32 wlfc_header_only_pkt;
154 uint32 txstatus_in;
155 uint32 d11_suppress;
156 uint32 wl_suppress;
157 uint32 bad_suppress;
158 uint32 pkt_freed;
159 uint32 pkt_free_err;
160 uint32 psq_wlsup_retx;
161 uint32 psq_wlsup_enq;
162 uint32 psq_d11sup_retx;
163 uint32 psq_d11sup_enq;
164 uint32 psq_hostq_retx;
165 uint32 psq_hostq_enq;
166 uint32 mac_handle_notfound;
167 uint32 wlc_tossed_pkts;
168 uint32 dhd_hdrpulls;
169 uint32 generic_error;
170 /* an extra one for bc/mc traffic */
171 uint32 sendq_pkts[AC_COUNT + 1];
172#ifdef PROP_TXSTATUS_DEBUG
173 /* all pkt2bus -> txstatus latency accumulated */
174 uint32 latency_sample_count;
175 uint32 total_status_latency;
176 uint32 latency_most_recent;
177 int idx_delta;
178 uint32 deltas[10];
179 uint32 fifo_credits_sent[6];
180 uint32 fifo_credits_back[6];
181 uint32 dropped_qfull[6];
182 uint32 signal_only_pkts_sent;
183 uint32 signal_only_pkts_freed;
184#endif
185} athost_wl_stat_counters_t;
186
187#ifdef PROP_TXSTATUS_DEBUG
188#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \
189 (ctx)->stats.fifo_credits_sent[(ac)]++;} while (0)
190#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \
191 (ctx)->stats.fifo_credits_back[(ac)]++;} while (0)
192#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \
193 (ctx)->stats.dropped_qfull[(ac)]++;} while (0)
194#else
195#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0)
196#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0)
197#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0)
198#endif
199
200#define WLFC_FCMODE_NONE 0
201#define WLFC_FCMODE_IMPLIED_CREDIT 1
202#define WLFC_FCMODE_EXPLICIT_CREDIT 2
203
204#define WLFC_BORROW_DEFER_PERIOD_MS 100
205
206/* Mask to represent available ACs (note: BC/MC is ignored */
207#define WLFC_AC_MASK 0xF
208
209/* Mask to check for only on-going AC_BE traffic */
210#define WLFC_AC_BE_TRAFFIC_ONLY 0xD
211
212typedef struct athost_wl_status_info {
213 uint8 last_seqid_to_wlc;
214
215 /* OSL handle */
216 osl_t* osh;
217 /* dhd pub */
218 void* dhdp;
219
220 /* stats */
221 athost_wl_stat_counters_t stats;
222
223 /* the additional ones are for bc/mc and ATIM FIFO */
224 int FIFO_credit[AC_COUNT + 2];
225
226 /* Credit borrow counts for each FIFO from each of the other FIFOs */
227 int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2];
228
229 struct pktq SENDQ;
230
231 /* packet hanger and MAC->handle lookup table */
232 void* hanger;
233 struct {
234 /* table for individual nodes */
235 wlfc_mac_descriptor_t nodes[WLFC_MAC_DESC_TABLE_SIZE];
236 /* table for interfaces */
237 wlfc_mac_descriptor_t interfaces[WLFC_MAX_IFNUM];
238 /* OS may send packets to unknown (unassociated) destinations */
239 /* A place holder for bc/mc and packets to unknown destinations */
240 wlfc_mac_descriptor_t other;
241 } destination_entries;
242 /* token position for different priority packets */
243 uint8 token_pos[AC_COUNT+1];
244 /* ON/OFF state for flow control to the host network interface */
245 uint8 hostif_flow_state[WLFC_MAX_IFNUM];
246 uint8 host_ifidx;
247 /* to flow control an OS interface */
248 uint8 toggle_host_if;
249
250 /*
251 Mode in which the dhd flow control shall operate. Must be set before
252 traffic starts to the device.
253 0 - Do not do any proptxtstatus flow control
254 1 - Use implied credit from a packet status
255 2 - Use explicit credit
256 */
257 uint8 proptxstatus_mode;
258
259 /* To borrow credits */
260 uint8 allow_credit_borrow;
261
262 /* Timestamp to compute how long to defer borrowing for */
263 uint32 borrow_defer_timestamp;
264} athost_wl_status_info_t;
265
266#endif /* __wlfc_host_driver_definitions_h__ */
diff --git a/drivers/net/wireless/bcmdhd/dngl_stats.h b/drivers/net/wireless/bcmdhd/dngl_stats.h
new file mode 100644
index 00000000000..9cdf718b399
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dngl_stats.h
@@ -0,0 +1,43 @@
1/*
2 * Common stats definitions for clients of dongle
3 * ports
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: dngl_stats.h,v 1.5 2008-06-02 16:56:20 Exp $
26 */
27
28#ifndef _dngl_stats_h_
29#define _dngl_stats_h_
30
31typedef struct {
32 unsigned long rx_packets; /* total packets received */
33 unsigned long tx_packets; /* total packets transmitted */
34 unsigned long rx_bytes; /* total bytes received */
35 unsigned long tx_bytes; /* total bytes transmitted */
36 unsigned long rx_errors; /* bad packets received */
37 unsigned long tx_errors; /* packet transmit problems */
38 unsigned long rx_dropped; /* packets dropped by dongle */
39 unsigned long tx_dropped; /* packets dropped by dongle */
40 unsigned long multicast; /* multicast packets received */
41} dngl_stats_t;
42
43#endif /* _dngl_stats_h_ */
diff --git a/drivers/net/wireless/bcmdhd/dngl_wlhdr.h b/drivers/net/wireless/bcmdhd/dngl_wlhdr.h
new file mode 100644
index 00000000000..8b39b9ecb58
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/dngl_wlhdr.h
@@ -0,0 +1,40 @@
1/*
2 * Dongle WL Header definitions
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: dngl_wlhdr.h,v 1.1 2009-01-08 01:21:12 Exp $
25 */
26
27#ifndef _dngl_wlhdr_h_
28#define _dngl_wlhdr_h_
29
30typedef struct wl_header {
31 uint8 type; /* Header type */
32 uint8 version; /* Header version */
33 int8 rssi; /* RSSI */
34 uint8 pad; /* Unused */
35} wl_header_t;
36
37#define WL_HEADER_LEN sizeof(wl_header_t)
38#define WL_HEADER_TYPE 0
39#define WL_HEADER_VER 1
40#endif /* _dngl_wlhdr_h_ */
diff --git a/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd/hndpmu.c
new file mode 100644
index 00000000000..b9586e40d0c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/hndpmu.c
@@ -0,0 +1,222 @@
1/*
2 * Misc utility routines for accessing PMU corerev specific features
3 * of the SiliconBackplane-based Broadcom chips.
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: hndpmu.c,v 1.228.2.56 2011-02-11 22:49:07 Exp $
26 */
27
28#include <typedefs.h>
29#include <bcmdefs.h>
30#include <osl.h>
31#include <bcmutils.h>
32#include <siutils.h>
33#include <bcmdevs.h>
34#include <hndsoc.h>
35#include <sbchipc.h>
36#include <hndpmu.h>
37
38#define PMU_ERROR(args)
39
40#define PMU_MSG(args)
41
42/* To check in verbose debugging messages not intended
43 * to be on except on private builds.
44 */
45#define PMU_NONE(args)
46
47
48/* SDIO Pad drive strength to select value mappings.
49 * The last strength value in each table must be 0 (the tri-state value).
50 */
51typedef struct {
52 uint8 strength; /* Pad Drive Strength in mA */
53 uint8 sel; /* Chip-specific select value */
54} sdiod_drive_str_t;
55
56/* SDIO Drive Strength to sel value table for PMU Rev 1 */
57static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = {
58 {4, 0x2},
59 {2, 0x3},
60 {1, 0x0},
61 {0, 0x0} };
62
63/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
64static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = {
65 {12, 0x7},
66 {10, 0x6},
67 {8, 0x5},
68 {6, 0x4},
69 {4, 0x2},
70 {2, 0x1},
71 {0, 0x0} };
72
73/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
74static const sdiod_drive_str_t sdiod_drive_strength_tab3[] = {
75 {32, 0x7},
76 {26, 0x6},
77 {22, 0x5},
78 {16, 0x4},
79 {12, 0x3},
80 {8, 0x2},
81 {4, 0x1},
82 {0, 0x0} };
83
84/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.8v) */
85static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = {
86 {32, 0x6},
87 {26, 0x7},
88 {22, 0x4},
89 {16, 0x5},
90 {12, 0x2},
91 {8, 0x3},
92 {4, 0x0},
93 {0, 0x1} };
94
95/* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */
96static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v2[] = {
97 {16, 0x3},
98 {13, 0x2},
99 {11, 0x1},
100 {8, 0x0},
101 {6, 0x7},
102 {4, 0x6},
103 {2, 0x5},
104 {0, 0x4} };
105
106/* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */
107static const sdiod_drive_str_t sdiod_drive_strength_tab4_2v5[] = {
108 {80, 0x5},
109 {65, 0x4},
110 {55, 0x7},
111 {40, 0x6},
112 {30, 0x1},
113 {20, 0x0},
114 {10, 0x3},
115 {0, 0x2} };
116
117/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
118static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = {
119 {6, 0x7},
120 {5, 0x6},
121 {4, 0x5},
122 {3, 0x4},
123 {2, 0x2},
124 {1, 0x1},
125 {0, 0x0} };
126
127/* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */
128static const sdiod_drive_str_t sdiod_drive_strength_tab5_3v3[] = {
129 {12, 0x7},
130 {10, 0x6},
131 {8, 0x5},
132 {6, 0x4},
133 {4, 0x2},
134 {2, 0x1},
135 {0, 0x0} };
136
137
138#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
139
140void
141si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength)
142{
143 chipcregs_t *cc;
144 uint origidx, intr_val = 0;
145 sdiod_drive_str_t *str_tab = NULL;
146 uint32 str_mask = 0;
147 uint32 str_shift = 0;
148
149 if (!(sih->cccaps & CC_CAP_PMU)) {
150 return;
151 }
152
153 /* Remember original core before switch to chipc */
154 cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
155
156 switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) {
157 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
158 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1;
159 str_mask = 0x30000000;
160 str_shift = 28;
161 break;
162 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
163 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
164 case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4):
165 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2;
166 str_mask = 0x00003800;
167 str_shift = 11;
168 break;
169 case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
170 case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11):
171 if (sih->pmurev == 8) {
172 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3;
173 }
174 else if (sih->pmurev == 11) {
175 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8;
176 }
177 str_mask = 0x00003800;
178 str_shift = 11;
179 break;
180 case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12):
181 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8;
182 str_mask = 0x00003800;
183 str_shift = 11;
184 break;
185 case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
186 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8;
187 str_mask = 0x00003800;
188 str_shift = 11;
189 break;
190 default:
191 PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
192 bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev));
193
194 break;
195 }
196
197 if (str_tab != NULL) {
198 uint32 cc_data_temp;
199 int i;
200
201 /* Pick the lowest available drive strength equal or greater than the
202 * requested strength. Drive strength of 0 requests tri-state.
203 */
204 for (i = 0; drivestrength < str_tab[i].strength; i++)
205 ;
206
207 if (i > 0 && drivestrength > str_tab[i].strength)
208 i--;
209
210 W_REG(osh, &cc->chipcontrol_addr, 1);
211 cc_data_temp = R_REG(osh, &cc->chipcontrol_data);
212 cc_data_temp &= ~str_mask;
213 cc_data_temp |= str_tab[i].sel << str_shift;
214 W_REG(osh, &cc->chipcontrol_data, cc_data_temp);
215
216 PMU_MSG(("SDIO: %dmA drive strength requested; set to %dmA\n",
217 drivestrength, str_tab[i].strength));
218 }
219
220 /* Return to original core */
221 si_restore_core(sih, origidx, intr_val);
222}
diff --git a/drivers/net/wireless/bcmdhd/include/Makefile b/drivers/net/wireless/bcmdhd/include/Makefile
new file mode 100644
index 00000000000..c07266fd6fd
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/Makefile
@@ -0,0 +1,53 @@
1#!/bin/bash
2#
3# This script serves following purpose:
4#
5# 1. It generates native version information by querying
6# automerger maintained database to see where src/include
7# came from
8# 2. For select components, as listed in compvers.sh
9# it generates component version files
10#
11# Copyright 2005, Broadcom, Inc.
12#
13# $Id: Makefile 241702 2011-02-19 00:41:03Z automrgr $
14#
15
16SRCBASE := ..
17
18TARGETS := epivers.h
19
20ifdef VERBOSE
21export VERBOSE
22endif
23
24all release: epivers compvers
25
26# Generate epivers.h for native branch version
27epivers:
28 bash epivers.sh
29
30# Generate epivers.h for native branch version
31compvers:
32 @if [ -s "compvers.sh" ]; then \
33 echo "Generating component versions, if any"; \
34 bash compvers.sh; \
35 else \
36 echo "Skipping component version generation"; \
37 fi
38
39# Generate epivers.h for native branch version
40clean_compvers:
41 @if [ -s "compvers.sh" ]; then \
42 echo "bash compvers.sh clean"; \
43 bash compvers.sh clean; \
44 else \
45 echo "Skipping component version clean"; \
46 fi
47
48clean:
49 rm -f $(TARGETS) *.prev
50
51clean_all: clean clean_compvers
52
53.PHONY: all release clean epivers compvers clean_compvers
diff --git a/drivers/net/wireless/bcmdhd/include/aidmp.h b/drivers/net/wireless/bcmdhd/include/aidmp.h
new file mode 100644
index 00000000000..375df443a29
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/aidmp.h
@@ -0,0 +1,377 @@
1/*
2 * Broadcom AMBA Interconnect definitions.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: aidmp.h,v 13.4.14.1 2010-03-09 18:40:06 Exp $
25 */
26
27
28#ifndef _AIDMP_H
29#define _AIDMP_H
30
31
32#define MFGID_ARM 0x43b
33#define MFGID_BRCM 0x4bf
34#define MFGID_MIPS 0x4a7
35
36
37#define CC_SIM 0
38#define CC_EROM 1
39#define CC_CORESIGHT 9
40#define CC_VERIF 0xb
41#define CC_OPTIMO 0xd
42#define CC_GEN 0xe
43#define CC_PRIMECELL 0xf
44
45
46#define ER_EROMENTRY 0x000
47#define ER_REMAPCONTROL 0xe00
48#define ER_REMAPSELECT 0xe04
49#define ER_MASTERSELECT 0xe10
50#define ER_ITCR 0xf00
51#define ER_ITIP 0xf04
52
53
54#define ER_TAG 0xe
55#define ER_TAG1 0x6
56#define ER_VALID 1
57#define ER_CI 0
58#define ER_MP 2
59#define ER_ADD 4
60#define ER_END 0xe
61#define ER_BAD 0xffffffff
62
63
64#define CIA_MFG_MASK 0xfff00000
65#define CIA_MFG_SHIFT 20
66#define CIA_CID_MASK 0x000fff00
67#define CIA_CID_SHIFT 8
68#define CIA_CCL_MASK 0x000000f0
69#define CIA_CCL_SHIFT 4
70
71
72#define CIB_REV_MASK 0xff000000
73#define CIB_REV_SHIFT 24
74#define CIB_NSW_MASK 0x00f80000
75#define CIB_NSW_SHIFT 19
76#define CIB_NMW_MASK 0x0007c000
77#define CIB_NMW_SHIFT 14
78#define CIB_NSP_MASK 0x00003e00
79#define CIB_NSP_SHIFT 9
80#define CIB_NMP_MASK 0x000001f0
81#define CIB_NMP_SHIFT 4
82
83
84#define MPD_MUI_MASK 0x0000ff00
85#define MPD_MUI_SHIFT 8
86#define MPD_MP_MASK 0x000000f0
87#define MPD_MP_SHIFT 4
88
89
90#define AD_ADDR_MASK 0xfffff000
91#define AD_SP_MASK 0x00000f00
92#define AD_SP_SHIFT 8
93#define AD_ST_MASK 0x000000c0
94#define AD_ST_SHIFT 6
95#define AD_ST_SLAVE 0x00000000
96#define AD_ST_BRIDGE 0x00000040
97#define AD_ST_SWRAP 0x00000080
98#define AD_ST_MWRAP 0x000000c0
99#define AD_SZ_MASK 0x00000030
100#define AD_SZ_SHIFT 4
101#define AD_SZ_4K 0x00000000
102#define AD_SZ_8K 0x00000010
103#define AD_SZ_16K 0x00000020
104#define AD_SZ_SZD 0x00000030
105#define AD_AG32 0x00000008
106#define AD_ADDR_ALIGN 0x00000fff
107#define AD_SZ_BASE 0x00001000
108
109
110#define SD_SZ_MASK 0xfffff000
111#define SD_SG32 0x00000008
112#define SD_SZ_ALIGN 0x00000fff
113
114
115#ifndef _LANGUAGE_ASSEMBLY
116
117typedef volatile struct _aidmp {
118 uint32 oobselina30;
119 uint32 oobselina74;
120 uint32 PAD[6];
121 uint32 oobselinb30;
122 uint32 oobselinb74;
123 uint32 PAD[6];
124 uint32 oobselinc30;
125 uint32 oobselinc74;
126 uint32 PAD[6];
127 uint32 oobselind30;
128 uint32 oobselind74;
129 uint32 PAD[38];
130 uint32 oobselouta30;
131 uint32 oobselouta74;
132 uint32 PAD[6];
133 uint32 oobseloutb30;
134 uint32 oobseloutb74;
135 uint32 PAD[6];
136 uint32 oobseloutc30;
137 uint32 oobseloutc74;
138 uint32 PAD[6];
139 uint32 oobseloutd30;
140 uint32 oobseloutd74;
141 uint32 PAD[38];
142 uint32 oobsynca;
143 uint32 oobseloutaen;
144 uint32 PAD[6];
145 uint32 oobsyncb;
146 uint32 oobseloutben;
147 uint32 PAD[6];
148 uint32 oobsyncc;
149 uint32 oobseloutcen;
150 uint32 PAD[6];
151 uint32 oobsyncd;
152 uint32 oobseloutden;
153 uint32 PAD[38];
154 uint32 oobaextwidth;
155 uint32 oobainwidth;
156 uint32 oobaoutwidth;
157 uint32 PAD[5];
158 uint32 oobbextwidth;
159 uint32 oobbinwidth;
160 uint32 oobboutwidth;
161 uint32 PAD[5];
162 uint32 oobcextwidth;
163 uint32 oobcinwidth;
164 uint32 oobcoutwidth;
165 uint32 PAD[5];
166 uint32 oobdextwidth;
167 uint32 oobdinwidth;
168 uint32 oobdoutwidth;
169 uint32 PAD[37];
170 uint32 ioctrlset;
171 uint32 ioctrlclear;
172 uint32 ioctrl;
173 uint32 PAD[61];
174 uint32 iostatus;
175 uint32 PAD[127];
176 uint32 ioctrlwidth;
177 uint32 iostatuswidth;
178 uint32 PAD[62];
179 uint32 resetctrl;
180 uint32 resetstatus;
181 uint32 resetreadid;
182 uint32 resetwriteid;
183 uint32 PAD[60];
184 uint32 errlogctrl;
185 uint32 errlogdone;
186 uint32 errlogstatus;
187 uint32 errlogaddrlo;
188 uint32 errlogaddrhi;
189 uint32 errlogid;
190 uint32 errloguser;
191 uint32 errlogflags;
192 uint32 PAD[56];
193 uint32 intstatus;
194 uint32 PAD[127];
195 uint32 config;
196 uint32 PAD[63];
197 uint32 itcr;
198 uint32 PAD[3];
199 uint32 itipooba;
200 uint32 itipoobb;
201 uint32 itipoobc;
202 uint32 itipoobd;
203 uint32 PAD[4];
204 uint32 itipoobaout;
205 uint32 itipoobbout;
206 uint32 itipoobcout;
207 uint32 itipoobdout;
208 uint32 PAD[4];
209 uint32 itopooba;
210 uint32 itopoobb;
211 uint32 itopoobc;
212 uint32 itopoobd;
213 uint32 PAD[4];
214 uint32 itopoobain;
215 uint32 itopoobbin;
216 uint32 itopoobcin;
217 uint32 itopoobdin;
218 uint32 PAD[4];
219 uint32 itopreset;
220 uint32 PAD[15];
221 uint32 peripherialid4;
222 uint32 peripherialid5;
223 uint32 peripherialid6;
224 uint32 peripherialid7;
225 uint32 peripherialid0;
226 uint32 peripherialid1;
227 uint32 peripherialid2;
228 uint32 peripherialid3;
229 uint32 componentid0;
230 uint32 componentid1;
231 uint32 componentid2;
232 uint32 componentid3;
233} aidmp_t;
234
235#endif
236
237
238#define OOB_BUSCONFIG 0x020
239#define OOB_STATUSA 0x100
240#define OOB_STATUSB 0x104
241#define OOB_STATUSC 0x108
242#define OOB_STATUSD 0x10c
243#define OOB_ENABLEA0 0x200
244#define OOB_ENABLEA1 0x204
245#define OOB_ENABLEA2 0x208
246#define OOB_ENABLEA3 0x20c
247#define OOB_ENABLEB0 0x280
248#define OOB_ENABLEB1 0x284
249#define OOB_ENABLEB2 0x288
250#define OOB_ENABLEB3 0x28c
251#define OOB_ENABLEC0 0x300
252#define OOB_ENABLEC1 0x304
253#define OOB_ENABLEC2 0x308
254#define OOB_ENABLEC3 0x30c
255#define OOB_ENABLED0 0x380
256#define OOB_ENABLED1 0x384
257#define OOB_ENABLED2 0x388
258#define OOB_ENABLED3 0x38c
259#define OOB_ITCR 0xf00
260#define OOB_ITIPOOBA 0xf10
261#define OOB_ITIPOOBB 0xf14
262#define OOB_ITIPOOBC 0xf18
263#define OOB_ITIPOOBD 0xf1c
264#define OOB_ITOPOOBA 0xf30
265#define OOB_ITOPOOBB 0xf34
266#define OOB_ITOPOOBC 0xf38
267#define OOB_ITOPOOBD 0xf3c
268
269
270#define AI_OOBSELINA30 0x000
271#define AI_OOBSELINA74 0x004
272#define AI_OOBSELINB30 0x020
273#define AI_OOBSELINB74 0x024
274#define AI_OOBSELINC30 0x040
275#define AI_OOBSELINC74 0x044
276#define AI_OOBSELIND30 0x060
277#define AI_OOBSELIND74 0x064
278#define AI_OOBSELOUTA30 0x100
279#define AI_OOBSELOUTA74 0x104
280#define AI_OOBSELOUTB30 0x120
281#define AI_OOBSELOUTB74 0x124
282#define AI_OOBSELOUTC30 0x140
283#define AI_OOBSELOUTC74 0x144
284#define AI_OOBSELOUTD30 0x160
285#define AI_OOBSELOUTD74 0x164
286#define AI_OOBSYNCA 0x200
287#define AI_OOBSELOUTAEN 0x204
288#define AI_OOBSYNCB 0x220
289#define AI_OOBSELOUTBEN 0x224
290#define AI_OOBSYNCC 0x240
291#define AI_OOBSELOUTCEN 0x244
292#define AI_OOBSYNCD 0x260
293#define AI_OOBSELOUTDEN 0x264
294#define AI_OOBAEXTWIDTH 0x300
295#define AI_OOBAINWIDTH 0x304
296#define AI_OOBAOUTWIDTH 0x308
297#define AI_OOBBEXTWIDTH 0x320
298#define AI_OOBBINWIDTH 0x324
299#define AI_OOBBOUTWIDTH 0x328
300#define AI_OOBCEXTWIDTH 0x340
301#define AI_OOBCINWIDTH 0x344
302#define AI_OOBCOUTWIDTH 0x348
303#define AI_OOBDEXTWIDTH 0x360
304#define AI_OOBDINWIDTH 0x364
305#define AI_OOBDOUTWIDTH 0x368
306
307
308#define AI_IOCTRLSET 0x400
309#define AI_IOCTRLCLEAR 0x404
310#define AI_IOCTRL 0x408
311#define AI_IOSTATUS 0x500
312#define AI_RESETCTRL 0x800
313#define AI_RESETSTATUS 0x804
314
315
316#define AI_IOCTRLWIDTH 0x700
317#define AI_IOSTATUSWIDTH 0x704
318
319#define AI_RESETREADID 0x808
320#define AI_RESETWRITEID 0x80c
321#define AI_ERRLOGCTRL 0xa00
322#define AI_ERRLOGDONE 0xa04
323#define AI_ERRLOGSTATUS 0xa08
324#define AI_ERRLOGADDRLO 0xa0c
325#define AI_ERRLOGADDRHI 0xa10
326#define AI_ERRLOGID 0xa14
327#define AI_ERRLOGUSER 0xa18
328#define AI_ERRLOGFLAGS 0xa1c
329#define AI_INTSTATUS 0xa00
330#define AI_CONFIG 0xe00
331#define AI_ITCR 0xf00
332#define AI_ITIPOOBA 0xf10
333#define AI_ITIPOOBB 0xf14
334#define AI_ITIPOOBC 0xf18
335#define AI_ITIPOOBD 0xf1c
336#define AI_ITIPOOBAOUT 0xf30
337#define AI_ITIPOOBBOUT 0xf34
338#define AI_ITIPOOBCOUT 0xf38
339#define AI_ITIPOOBDOUT 0xf3c
340#define AI_ITOPOOBA 0xf50
341#define AI_ITOPOOBB 0xf54
342#define AI_ITOPOOBC 0xf58
343#define AI_ITOPOOBD 0xf5c
344#define AI_ITOPOOBAIN 0xf70
345#define AI_ITOPOOBBIN 0xf74
346#define AI_ITOPOOBCIN 0xf78
347#define AI_ITOPOOBDIN 0xf7c
348#define AI_ITOPRESET 0xf90
349#define AI_PERIPHERIALID4 0xfd0
350#define AI_PERIPHERIALID5 0xfd4
351#define AI_PERIPHERIALID6 0xfd8
352#define AI_PERIPHERIALID7 0xfdc
353#define AI_PERIPHERIALID0 0xfe0
354#define AI_PERIPHERIALID1 0xfe4
355#define AI_PERIPHERIALID2 0xfe8
356#define AI_PERIPHERIALID3 0xfec
357#define AI_COMPONENTID0 0xff0
358#define AI_COMPONENTID1 0xff4
359#define AI_COMPONENTID2 0xff8
360#define AI_COMPONENTID3 0xffc
361
362
363#define AIRC_RESET 1
364
365
366#define AICFG_OOB 0x00000020
367#define AICFG_IOS 0x00000010
368#define AICFG_IOC 0x00000008
369#define AICFG_TO 0x00000004
370#define AICFG_ERRL 0x00000002
371#define AICFG_RST 0x00000001
372
373
374#define OOB_SEL_OUTEN_B_5 15
375#define OOB_SEL_OUTEN_B_6 23
376
377#endif
diff --git a/drivers/net/wireless/bcmdhd/include/bcmcdc.h b/drivers/net/wireless/bcmdhd/include/bcmcdc.h
new file mode 100644
index 00000000000..ce45c50d964
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmcdc.h
@@ -0,0 +1,121 @@
1/*
2 * CDC network driver ioctl/indication encoding
3 * Broadcom 802.11abg Networking Device Driver
4 *
5 * Definitions subject to change without notice.
6 *
7 * Copyright (C) 1999-2011, Broadcom Corporation
8 *
9 * Unless you and Broadcom execute a separate written software license
10 * agreement governing use of this software, this software is licensed to you
11 * under the terms of the GNU General Public License version 2 (the "GPL"),
12 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
13 * following added to such license:
14 *
15 * As a special exception, the copyright holders of this software give you
16 * permission to link this software with independent modules, and to copy and
17 * distribute the resulting executable under terms of your choice, provided that
18 * you also meet, for each linked independent module, the terms and conditions of
19 * the license of that module. An independent module is a module which is not
20 * derived from this software. The special exception does not apply to any
21 * modifications of the software.
22 *
23 * Notwithstanding the above, under no circumstances may you combine this
24 * software in any way with any other Broadcom software provided under a license
25 * other than the GPL, without Broadcom's express prior written consent.
26 *
27 * $Id: bcmcdc.h,v 13.25.10.3 2010-12-22 23:47:26 Exp $
28 */
29
30#ifndef _bcmcdc_h_
31#define _bcmcdc_h_
32#include <proto/ethernet.h>
33
34typedef struct cdc_ioctl {
35 uint32 cmd;
36 uint32 len;
37 uint32 flags;
38 uint32 status;
39} cdc_ioctl_t;
40
41
42#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN
43
44
45#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF
46
47#define CDCL_IOC_OUTLEN_SHIFT 0
48#define CDCL_IOC_INLEN_MASK 0xFFFF0000
49#define CDCL_IOC_INLEN_SHIFT 16
50
51
52#define CDCF_IOC_ERROR 0x01
53#define CDCF_IOC_SET 0x02
54#define CDCF_IOC_OVL_IDX_MASK 0x3c
55#define CDCF_IOC_OVL_RSV 0x40
56#define CDCF_IOC_OVL 0x80
57#define CDCF_IOC_ACTION_MASK 0xfe
58#define CDCF_IOC_ACTION_SHIFT 1
59#define CDCF_IOC_IF_MASK 0xF000
60#define CDCF_IOC_IF_SHIFT 12
61#define CDCF_IOC_ID_MASK 0xFFFF0000
62#define CDCF_IOC_ID_SHIFT 16
63
64#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)
65#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT)
66
67#define CDC_GET_IF_IDX(hdr) \
68 ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT))
69#define CDC_SET_IF_IDX(hdr, idx) \
70 ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT)))
71
72
73
74#define BDC_HEADER_LEN 4
75
76#define BDC_PROTO_VER_1 1
77#define BDC_PROTO_VER 2
78
79#define BDC_FLAG_VER_MASK 0xf0
80#define BDC_FLAG_VER_SHIFT 4
81
82#define BDC_FLAG__UNUSED 0x03
83#define BDC_FLAG_SUM_GOOD 0x04
84#define BDC_FLAG_SUM_NEEDED 0x08
85
86#define BDC_PRIORITY_MASK 0x7
87
88#define BDC_FLAG2_FC_FLAG 0x10
89
90#define BDC_PRIORITY_FC_SHIFT 4
91
92#define BDC_FLAG2_IF_MASK 0x0f
93#define BDC_FLAG2_IF_SHIFT 0
94#define BDC_FLAG2_PAD_MASK 0xf0
95#define BDC_FLAG_PAD_MASK 0x03
96#define BDC_FLAG2_PAD_SHIFT 2
97#define BDC_FLAG_PAD_SHIFT 0
98#define BDC_FLAG2_PAD_IDX 0x3c
99#define BDC_FLAG_PAD_IDX 0x03
100#define BDC_GET_PAD_LEN(hdr) \
101 ((int)(((((hdr)->flags2) & BDC_FLAG2_PAD_MASK) >> BDC_FLAG2_PAD_SHIFT) | \
102 ((((hdr)->flags) & BDC_FLAG_PAD_MASK) >> BDC_FLAG_PAD_SHIFT)))
103#define BDC_SET_PAD_LEN(hdr, idx) \
104 ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_PAD_MASK) | \
105 (((idx) & BDC_FLAG2_PAD_IDX) << BDC_FLAG2_PAD_SHIFT))); \
106 ((hdr)->flags = (((hdr)->flags & ~BDC_FLAG_PAD_MASK) | \
107 (((idx) & BDC_FLAG_PAD_IDX) << BDC_FLAG_PAD_SHIFT)))
108
109#define BDC_GET_IF_IDX(hdr) \
110 ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT))
111#define BDC_SET_IF_IDX(hdr, idx) \
112 ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | ((idx) << BDC_FLAG2_IF_SHIFT)))
113
114struct bdc_header {
115 uint8 flags;
116 uint8 priority;
117 uint8 flags2;
118 uint8 dataOffset;
119};
120
121#endif
diff --git a/drivers/net/wireless/bcmdhd/include/bcmdefs.h b/drivers/net/wireless/bcmdhd/include/bcmdefs.h
new file mode 100644
index 00000000000..da1fd5e4eac
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmdefs.h
@@ -0,0 +1,196 @@
1/*
2 * Misc system wide definitions
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmdefs.h,v 13.68.2.8 2011-01-08 04:04:19 Exp $
25 */
26
27
28#ifndef _bcmdefs_h_
29#define _bcmdefs_h_
30
31
32
33#define bcmreclaimed 0
34#define _data _data
35#define _fn _fn
36#define _data _data
37#define _fn _fn
38#define _fn _fn
39#define CONST const
40#define BCMFASTPATH
41
42
43
44
45#define _data _data
46#define _fn _fn
47#define _fn _fn
48#define STATIC static
49
50
51#define SI_BUS 0
52#define PCI_BUS 1
53#define PCMCIA_BUS 2
54#define SDIO_BUS 3
55#define JTAG_BUS 4
56#define USB_BUS 5
57#define SPI_BUS 6
58#define RPC_BUS 7
59
60
61#ifdef BCMBUSTYPE
62#define BUSTYPE(bus) (BCMBUSTYPE)
63#else
64#define BUSTYPE(bus) (bus)
65#endif
66
67
68#ifdef BCMCHIPTYPE
69#define CHIPTYPE(bus) (BCMCHIPTYPE)
70#else
71#define CHIPTYPE(bus) (bus)
72#endif
73
74
75
76#if defined(BCMSPROMBUS)
77#define SPROMBUS (BCMSPROMBUS)
78#elif defined(SI_PCMCIA_SROM)
79#define SPROMBUS (PCMCIA_BUS)
80#else
81#define SPROMBUS (PCI_BUS)
82#endif
83
84
85#ifdef BCMCHIPID
86#define CHIPID(chip) (BCMCHIPID)
87#else
88#define CHIPID(chip) (chip)
89#endif
90
91#ifdef BCMCHIPREV
92#define CHIPREV(rev) (BCMCHIPREV)
93#else
94#define CHIPREV(rev) (rev)
95#endif
96
97
98#define DMADDR_MASK_32 0x0
99#define DMADDR_MASK_30 0xc0000000
100#define DMADDR_MASK_0 0xffffffff
101
102#define DMADDRWIDTH_30 30
103#define DMADDRWIDTH_32 32
104#define DMADDRWIDTH_63 63
105#define DMADDRWIDTH_64 64
106
107#ifdef BCMDMA64OSL
108typedef struct {
109 uint32 loaddr;
110 uint32 hiaddr;
111} dma64addr_t;
112
113typedef dma64addr_t dmaaddr_t;
114#define PHYSADDRHI(_pa) ((_pa).hiaddr)
115#define PHYSADDRHISET(_pa, _val) \
116 do { \
117 (_pa).hiaddr = (_val); \
118 } while (0)
119#define PHYSADDRLO(_pa) ((_pa).loaddr)
120#define PHYSADDRLOSET(_pa, _val) \
121 do { \
122 (_pa).loaddr = (_val); \
123 } while (0)
124
125#else
126typedef unsigned long dmaaddr_t;
127#define PHYSADDRHI(_pa) (0)
128#define PHYSADDRHISET(_pa, _val)
129#define PHYSADDRLO(_pa) ((_pa))
130#define PHYSADDRLOSET(_pa, _val) \
131 do { \
132 (_pa) = (_val); \
133 } while (0)
134#endif
135
136
137typedef struct {
138 dmaaddr_t addr;
139 uint32 length;
140} hnddma_seg_t;
141
142#define MAX_DMA_SEGS 4
143
144
145typedef struct {
146 void *oshdmah;
147 uint origsize;
148 uint nsegs;
149 hnddma_seg_t segs[MAX_DMA_SEGS];
150} hnddma_seg_map_t;
151
152
153
154
155#if defined(BCM_RPC_NOCOPY) || defined(BCM_RCP_TXNOCOPY)
156
157#define BCMEXTRAHDROOM 220
158#else
159#define BCMEXTRAHDROOM 172
160#endif
161
162
163#define BCMDONGLEHDRSZ 12
164#define BCMDONGLEPADSZ 16
165
166#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ)
167
168
169#if defined(BCMASSERT_LOG)
170#define BCMASSERT_SUPPORT
171#endif
172
173
174#define BITFIELD_MASK(width) \
175 (((unsigned)1 << (width)) - 1)
176#define GFIELD(val, field) \
177 (((val) >> field ## _S) & field ## _M)
178#define SFIELD(val, field, bits) \
179 (((val) & (~(field ## _M << field ## _S))) | \
180 ((unsigned)(bits) << field ## _S))
181
182
183#ifdef BCMSMALL
184#undef BCMSPACE
185#define bcmspace FALSE
186#else
187#define BCMSPACE
188#define bcmspace TRUE
189#endif
190
191
192#define MAXSZ_NVRAM_VARS 4096
193
194#define LOCATOR_EXTERN static
195
196#endif
diff --git a/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/bcmdhd/include/bcmdevs.h
new file mode 100644
index 00000000000..4f707c0c692
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmdevs.h
@@ -0,0 +1,182 @@
1/*
2 * Broadcom device-specific manifest constants.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmdevs.h,v 13.285.2.39 2011-02-04 05:03:16 Exp $
25 */
26
27
28#ifndef _BCMDEVS_H
29#define _BCMDEVS_H
30
31
32#define VENDOR_EPIGRAM 0xfeda
33#define VENDOR_BROADCOM 0x14e4
34#define VENDOR_SI_IMAGE 0x1095
35#define VENDOR_TI 0x104c
36#define VENDOR_RICOH 0x1180
37#define VENDOR_JMICRON 0x197b
38
39
40
41#define VENDOR_BROADCOM_PCMCIA 0x02d0
42
43
44#define VENDOR_BROADCOM_SDIO 0x00BF
45
46
47#define BCM_DNGL_VID 0x0a5c
48#define BCM_DNGL_BL_PID_4328 0xbd12
49#define BCM_DNGL_BL_PID_4322 0xbd13
50#define BCM_DNGL_BL_PID_4319 0xbd16
51#define BCM_DNGL_BL_PID_43236 0xbd17
52#define BCM_DNGL_BL_PID_4332 0xbd18
53#define BCM_DNGL_BL_PID_4330 0xbd19
54#define BCM_DNGL_BL_PID_43239 0xbd1b
55#define BCM_DNGL_BDC_PID 0x0bdc
56#define BCM_DNGL_JTAG_PID 0x4a44
57#define BCM4325_D11DUAL_ID 0x431b
58#define BCM4325_D11G_ID 0x431c
59#define BCM4325_D11A_ID 0x431d
60#define BCM4321_D11N_ID 0x4328
61#define BCM4321_D11N2G_ID 0x4329
62#define BCM4321_D11N5G_ID 0x432a
63#define BCM4322_D11N_ID 0x432b
64#define BCM4322_D11N2G_ID 0x432c
65#define BCM4322_D11N5G_ID 0x432d
66#define BCM4329_D11N_ID 0x432e
67#define BCM4329_D11N2G_ID 0x432f
68#define BCM4329_D11N5G_ID 0x4330
69#define BCM4315_D11DUAL_ID 0x4334
70#define BCM4315_D11G_ID 0x4335
71#define BCM4315_D11A_ID 0x4336
72#define BCM4319_D11N_ID 0x4337
73#define BCM4319_D11N2G_ID 0x4338
74#define BCM4319_D11N5G_ID 0x4339
75#define BCM43231_D11N2G_ID 0x4340
76#define BCM43221_D11N2G_ID 0x4341
77#define BCM43222_D11N_ID 0x4350
78#define BCM43222_D11N2G_ID 0x4351
79#define BCM43222_D11N5G_ID 0x4352
80#define BCM43224_D11N_ID 0x4353
81#define BCM43224_D11N_ID_VEN1 0x0576
82#define BCM43226_D11N_ID 0x4354
83#define BCM43236_D11N_ID 0x4346
84#define BCM43236_D11N2G_ID 0x4347
85#define BCM43236_D11N5G_ID 0x4348
86#define BCM43225_D11N2G_ID 0x4357
87#define BCM43421_D11N_ID 0xA99D
88#define BCM4313_D11N2G_ID 0x4727
89#define BCM4330_D11N_ID 0x4360
90#define BCM4330_D11N2G_ID 0x4361
91#define BCM4330_D11N5G_ID 0x4362
92#define BCM4336_D11N_ID 0x4343
93#define BCM6362_D11N_ID 0x435f
94#define BCM4331_D11N_ID 0x4331
95#define BCM4331_D11N2G_ID 0x4332
96#define BCM4331_D11N5G_ID 0x4333
97#define BCM43237_D11N_ID 0x4355
98#define BCM43237_D11N5G_ID 0x4356
99#define BCM43227_D11N2G_ID 0x4358
100#define BCM43228_D11N_ID 0x4359
101#define BCM43228_D11N5G_ID 0x435a
102#define BCM43362_D11N_ID 0x4363
103#define BCM43239_D11N_ID 0x4370
104
105
106#define SDIOH_FPGA_ID 0x43f2
107#define SPIH_FPGA_ID 0x43f5
108#define BCM4710_DEVICE_ID 0x4710
109#define BCM27XX_SDIOH_ID 0x2702
110#define PCIXX21_FLASHMEDIA0_ID 0x8033
111#define PCIXX21_SDIOH0_ID 0x8034
112#define PCIXX21_FLASHMEDIA_ID 0x803b
113#define PCIXX21_SDIOH_ID 0x803c
114#define R5C822_SDIOH_ID 0x0822
115#define JMICRON_SDIOH_ID 0x2381
116
117
118#define BCM4306_CHIP_ID 0x4306
119#define BCM4311_CHIP_ID 0x4311
120#define BCM43111_CHIP_ID 43111
121#define BCM43112_CHIP_ID 43112
122#define BCM4312_CHIP_ID 0x4312
123#define BCM4313_CHIP_ID 0x4313
124#define BCM4315_CHIP_ID 0x4315
125#define BCM4318_CHIP_ID 0x4318
126#define BCM4319_CHIP_ID 0x4319
127#define BCM4320_CHIP_ID 0x4320
128#define BCM4321_CHIP_ID 0x4321
129#define BCM4322_CHIP_ID 0x4322
130#define BCM43221_CHIP_ID 43221
131#define BCM43222_CHIP_ID 43222
132#define BCM43224_CHIP_ID 43224
133#define BCM43225_CHIP_ID 43225
134#define BCM43227_CHIP_ID 43227
135#define BCM43228_CHIP_ID 43228
136#define BCM43226_CHIP_ID 43226
137#define BCM43231_CHIP_ID 43231
138#define BCM43234_CHIP_ID 43234
139#define BCM43235_CHIP_ID 43235
140#define BCM43236_CHIP_ID 43236
141#define BCM43237_CHIP_ID 43237
142#define BCM43238_CHIP_ID 43238
143#define BCM43239_CHIP_ID 43239
144#define BCM43420_CHIP_ID 43420
145#define BCM43421_CHIP_ID 43421
146#define BCM43428_CHIP_ID 43428
147#define BCM43431_CHIP_ID 43431
148#define BCM4325_CHIP_ID 0x4325
149#define BCM4328_CHIP_ID 0x4328
150#define BCM4329_CHIP_ID 0x4329
151#define BCM4331_CHIP_ID 0x4331
152#define BCM4336_CHIP_ID 0x4336
153#define BCM43362_CHIP_ID 43362
154#define BCM4330_CHIP_ID 0x4330
155#define BCM4402_CHIP_ID 0x4402
156#define BCM4704_CHIP_ID 0x4704
157#define BCM4710_CHIP_ID 0x4710
158#define BCM4712_CHIP_ID 0x4712
159#define BCM4785_CHIP_ID 0x4785
160#define BCM5350_CHIP_ID 0x5350
161#define BCM5352_CHIP_ID 0x5352
162#define BCM5354_CHIP_ID 0x5354
163#define BCM5365_CHIP_ID 0x5365
164
165
166#define BCM4303_PKG_ID 2
167#define BCM4309_PKG_ID 1
168#define BCM4712LARGE_PKG_ID 0
169#define BCM4712SMALL_PKG_ID 1
170#define BCM4712MID_PKG_ID 2
171#define BCM4328USBD11G_PKG_ID 2
172#define BCM4328USBDUAL_PKG_ID 3
173#define BCM4328SDIOD11G_PKG_ID 4
174#define BCM4328SDIODUAL_PKG_ID 5
175#define BCM4329_289PIN_PKG_ID 0
176#define BCM4329_182PIN_PKG_ID 1
177#define BCM5354E_PKG_ID 1
178#define HDLSIM5350_PKG_ID 1
179#define HDLSIM_PKG_ID 14
180#define HWSIM_PKG_ID 15
181
182#endif
diff --git a/drivers/net/wireless/bcmdhd/include/bcmendian.h b/drivers/net/wireless/bcmdhd/include/bcmendian.h
new file mode 100644
index 00000000000..04b07ecb804
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmendian.h
@@ -0,0 +1,279 @@
1/*
2 * Byte order utilities
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmendian.h,v 1.36 2009-11-09 05:29:43 Exp $
25 *
26 * This file by default provides proper behavior on little-endian architectures.
27 * On big-endian architectures, IL_BIGENDIAN should be defined.
28 */
29
30
31#ifndef _BCMENDIAN_H_
32#define _BCMENDIAN_H_
33
34#include <typedefs.h>
35
36
37#define BCMSWAP16(val) \
38 ((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \
39 (((uint16)(val) & (uint16)0xff00U) >> 8)))
40
41
42#define BCMSWAP32(val) \
43 ((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \
44 (((uint32)(val) & (uint32)0x0000ff00U) << 8) | \
45 (((uint32)(val) & (uint32)0x00ff0000U) >> 8) | \
46 (((uint32)(val) & (uint32)0xff000000U) >> 24)))
47
48
49#define BCMSWAP32BY16(val) \
50 ((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \
51 (((uint32)(val) & (uint32)0xffff0000U) >> 16)))
52
53
54#ifndef hton16
55#define HTON16(i) BCMSWAP16(i)
56#define hton16(i) bcmswap16(i)
57#define HTON32(i) BCMSWAP32(i)
58#define hton32(i) bcmswap32(i)
59#define NTOH16(i) BCMSWAP16(i)
60#define ntoh16(i) bcmswap16(i)
61#define NTOH32(i) BCMSWAP32(i)
62#define ntoh32(i) bcmswap32(i)
63#define LTOH16(i) (i)
64#define ltoh16(i) (i)
65#define LTOH32(i) (i)
66#define ltoh32(i) (i)
67#define HTOL16(i) (i)
68#define htol16(i) (i)
69#define HTOL32(i) (i)
70#define htol32(i) (i)
71#endif
72
73#define ltoh16_buf(buf, i)
74#define htol16_buf(buf, i)
75
76
77#define load32_ua(a) ltoh32_ua(a)
78#define store32_ua(a, v) htol32_ua_store(v, a)
79#define load16_ua(a) ltoh16_ua(a)
80#define store16_ua(a, v) htol16_ua_store(v, a)
81
82#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8))
83#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24))
84#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1])
85#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3])
86
87#define ltoh_ua(ptr) \
88 (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \
89 sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \
90 sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \
91 *(uint8 *)0)
92
93#define ntoh_ua(ptr) \
94 (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \
95 sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \
96 sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \
97 *(uint8 *)0)
98
99#ifdef __GNUC__
100
101
102
103#define bcmswap16(val) ({ \
104 uint16 _val = (val); \
105 BCMSWAP16(_val); \
106})
107
108#define bcmswap32(val) ({ \
109 uint32 _val = (val); \
110 BCMSWAP32(_val); \
111})
112
113#define bcmswap32by16(val) ({ \
114 uint32 _val = (val); \
115 BCMSWAP32BY16(_val); \
116})
117
118#define bcmswap16_buf(buf, len) ({ \
119 uint16 *_buf = (uint16 *)(buf); \
120 uint _wds = (len) / 2; \
121 while (_wds--) { \
122 *_buf = bcmswap16(*_buf); \
123 _buf++; \
124 } \
125})
126
127#define htol16_ua_store(val, bytes) ({ \
128 uint16 _val = (val); \
129 uint8 *_bytes = (uint8 *)(bytes); \
130 _bytes[0] = _val & 0xff; \
131 _bytes[1] = _val >> 8; \
132})
133
134#define htol32_ua_store(val, bytes) ({ \
135 uint32 _val = (val); \
136 uint8 *_bytes = (uint8 *)(bytes); \
137 _bytes[0] = _val & 0xff; \
138 _bytes[1] = (_val >> 8) & 0xff; \
139 _bytes[2] = (_val >> 16) & 0xff; \
140 _bytes[3] = _val >> 24; \
141})
142
143#define hton16_ua_store(val, bytes) ({ \
144 uint16 _val = (val); \
145 uint8 *_bytes = (uint8 *)(bytes); \
146 _bytes[0] = _val >> 8; \
147 _bytes[1] = _val & 0xff; \
148})
149
150#define hton32_ua_store(val, bytes) ({ \
151 uint32 _val = (val); \
152 uint8 *_bytes = (uint8 *)(bytes); \
153 _bytes[0] = _val >> 24; \
154 _bytes[1] = (_val >> 16) & 0xff; \
155 _bytes[2] = (_val >> 8) & 0xff; \
156 _bytes[3] = _val & 0xff; \
157})
158
159#define ltoh16_ua(bytes) ({ \
160 const uint8 *_bytes = (const uint8 *)(bytes); \
161 _LTOH16_UA(_bytes); \
162})
163
164#define ltoh32_ua(bytes) ({ \
165 const uint8 *_bytes = (const uint8 *)(bytes); \
166 _LTOH32_UA(_bytes); \
167})
168
169#define ntoh16_ua(bytes) ({ \
170 const uint8 *_bytes = (const uint8 *)(bytes); \
171 _NTOH16_UA(_bytes); \
172})
173
174#define ntoh32_ua(bytes) ({ \
175 const uint8 *_bytes = (const uint8 *)(bytes); \
176 _NTOH32_UA(_bytes); \
177})
178
179#else
180
181
182static INLINE uint16
183bcmswap16(uint16 val)
184{
185 return BCMSWAP16(val);
186}
187
188static INLINE uint32
189bcmswap32(uint32 val)
190{
191 return BCMSWAP32(val);
192}
193
194static INLINE uint32
195bcmswap32by16(uint32 val)
196{
197 return BCMSWAP32BY16(val);
198}
199
200
201
202
203static INLINE void
204bcmswap16_buf(uint16 *buf, uint len)
205{
206 len = len / 2;
207
208 while (len--) {
209 *buf = bcmswap16(*buf);
210 buf++;
211 }
212}
213
214
215static INLINE void
216htol16_ua_store(uint16 val, uint8 *bytes)
217{
218 bytes[0] = val & 0xff;
219 bytes[1] = val >> 8;
220}
221
222
223static INLINE void
224htol32_ua_store(uint32 val, uint8 *bytes)
225{
226 bytes[0] = val & 0xff;
227 bytes[1] = (val >> 8) & 0xff;
228 bytes[2] = (val >> 16) & 0xff;
229 bytes[3] = val >> 24;
230}
231
232
233static INLINE void
234hton16_ua_store(uint16 val, uint8 *bytes)
235{
236 bytes[0] = val >> 8;
237 bytes[1] = val & 0xff;
238}
239
240
241static INLINE void
242hton32_ua_store(uint32 val, uint8 *bytes)
243{
244 bytes[0] = val >> 24;
245 bytes[1] = (val >> 16) & 0xff;
246 bytes[2] = (val >> 8) & 0xff;
247 bytes[3] = val & 0xff;
248}
249
250
251static INLINE uint16
252ltoh16_ua(const void *bytes)
253{
254 return _LTOH16_UA((const uint8 *)bytes);
255}
256
257
258static INLINE uint32
259ltoh32_ua(const void *bytes)
260{
261 return _LTOH32_UA((const uint8 *)bytes);
262}
263
264
265static INLINE uint16
266ntoh16_ua(const void *bytes)
267{
268 return _NTOH16_UA((const uint8 *)bytes);
269}
270
271
272static INLINE uint32
273ntoh32_ua(const void *bytes)
274{
275 return _NTOH32_UA((const uint8 *)bytes);
276}
277
278#endif
279#endif
diff --git a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h
new file mode 100644
index 00000000000..fd148c591d8
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h
@@ -0,0 +1,181 @@
1/*
2 * Broadcom PCI-SPI Host Controller Register Definitions
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmpcispi.h,v 13.15.112.1 2010-11-15 18:22:12 Exp $
25 */
26#ifndef _BCM_PCI_SPI_H
27#define _BCM_PCI_SPI_H
28
29/* cpp contortions to concatenate w/arg prescan */
30#ifndef PAD
31#define _PADLINE(line) pad ## line
32#define _XSTR(line) _PADLINE(line)
33#define PAD _XSTR(__LINE__)
34#endif /* PAD */
35
36
37typedef volatile struct {
38 uint32 spih_ctrl; /* 0x00 SPI Control Register */
39 uint32 spih_stat; /* 0x04 SPI Status Register */
40 uint32 spih_data; /* 0x08 SPI Data Register, 32-bits wide */
41 uint32 spih_ext; /* 0x0C SPI Extension Register */
42 uint32 PAD[4]; /* 0x10-0x1F PADDING */
43
44 uint32 spih_gpio_ctrl; /* 0x20 SPI GPIO Control Register */
45 uint32 spih_gpio_data; /* 0x24 SPI GPIO Data Register */
46 uint32 PAD[6]; /* 0x28-0x3F PADDING */
47
48 uint32 spih_int_edge; /* 0x40 SPI Interrupt Edge Register (0=Level, 1=Edge) */
49 uint32 spih_int_pol; /* 0x44 SPI Interrupt Polarity Register (0=Active Low, */
50 /* 1=Active High) */
51 uint32 spih_int_mask; /* 0x48 SPI Interrupt Mask */
52 uint32 spih_int_status; /* 0x4C SPI Interrupt Status */
53 uint32 PAD[4]; /* 0x50-0x5F PADDING */
54
55 uint32 spih_hex_disp; /* 0x60 SPI 4-digit hex display value */
56 uint32 spih_current_ma; /* 0x64 SPI SD card current consumption in mA */
57 uint32 PAD[1]; /* 0x68 PADDING */
58 uint32 spih_disp_sel; /* 0x6c SPI 4-digit hex display mode select (1=current) */
59 uint32 PAD[4]; /* 0x70-0x7F PADDING */
60 uint32 PAD[8]; /* 0x80-0x9F PADDING */
61 uint32 PAD[8]; /* 0xA0-0xBF PADDING */
62 uint32 spih_pll_ctrl; /* 0xC0 PLL Control Register */
63 uint32 spih_pll_status; /* 0xC4 PLL Status Register */
64 uint32 spih_xtal_freq; /* 0xC8 External Clock Frequency in units of 10000Hz */
65 uint32 spih_clk_count; /* 0xCC External Clock Count Register */
66
67} spih_regs_t;
68
69typedef volatile struct {
70 uint32 cfg_space[0x40]; /* 0x000-0x0FF PCI Configuration Space (Read Only) */
71 uint32 P_IMG_CTRL0; /* 0x100 PCI Image0 Control Register */
72
73 uint32 P_BA0; /* 0x104 32 R/W PCI Image0 Base Address register */
74 uint32 P_AM0; /* 0x108 32 R/W PCI Image0 Address Mask register */
75 uint32 P_TA0; /* 0x10C 32 R/W PCI Image0 Translation Address register */
76 uint32 P_IMG_CTRL1; /* 0x110 32 R/W PCI Image1 Control register */
77 uint32 P_BA1; /* 0x114 32 R/W PCI Image1 Base Address register */
78 uint32 P_AM1; /* 0x118 32 R/W PCI Image1 Address Mask register */
79 uint32 P_TA1; /* 0x11C 32 R/W PCI Image1 Translation Address register */
80 uint32 P_IMG_CTRL2; /* 0x120 32 R/W PCI Image2 Control register */
81 uint32 P_BA2; /* 0x124 32 R/W PCI Image2 Base Address register */
82 uint32 P_AM2; /* 0x128 32 R/W PCI Image2 Address Mask register */
83 uint32 P_TA2; /* 0x12C 32 R/W PCI Image2 Translation Address register */
84 uint32 P_IMG_CTRL3; /* 0x130 32 R/W PCI Image3 Control register */
85 uint32 P_BA3; /* 0x134 32 R/W PCI Image3 Base Address register */
86 uint32 P_AM3; /* 0x138 32 R/W PCI Image3 Address Mask register */
87 uint32 P_TA3; /* 0x13C 32 R/W PCI Image3 Translation Address register */
88 uint32 P_IMG_CTRL4; /* 0x140 32 R/W PCI Image4 Control register */
89 uint32 P_BA4; /* 0x144 32 R/W PCI Image4 Base Address register */
90 uint32 P_AM4; /* 0x148 32 R/W PCI Image4 Address Mask register */
91 uint32 P_TA4; /* 0x14C 32 R/W PCI Image4 Translation Address register */
92 uint32 P_IMG_CTRL5; /* 0x150 32 R/W PCI Image5 Control register */
93 uint32 P_BA5; /* 0x154 32 R/W PCI Image5 Base Address register */
94 uint32 P_AM5; /* 0x158 32 R/W PCI Image5 Address Mask register */
95 uint32 P_TA5; /* 0x15C 32 R/W PCI Image5 Translation Address register */
96 uint32 P_ERR_CS; /* 0x160 32 R/W PCI Error Control and Status register */
97 uint32 P_ERR_ADDR; /* 0x164 32 R PCI Erroneous Address register */
98 uint32 P_ERR_DATA; /* 0x168 32 R PCI Erroneous Data register */
99
100 uint32 PAD[5]; /* 0x16C-0x17F PADDING */
101
102 uint32 WB_CONF_SPC_BAR; /* 0x180 32 R WISHBONE Configuration Space Base Address */
103 uint32 W_IMG_CTRL1; /* 0x184 32 R/W WISHBONE Image1 Control register */
104 uint32 W_BA1; /* 0x188 32 R/W WISHBONE Image1 Base Address register */
105 uint32 W_AM1; /* 0x18C 32 R/W WISHBONE Image1 Address Mask register */
106 uint32 W_TA1; /* 0x190 32 R/W WISHBONE Image1 Translation Address reg */
107 uint32 W_IMG_CTRL2; /* 0x194 32 R/W WISHBONE Image2 Control register */
108 uint32 W_BA2; /* 0x198 32 R/W WISHBONE Image2 Base Address register */
109 uint32 W_AM2; /* 0x19C 32 R/W WISHBONE Image2 Address Mask register */
110 uint32 W_TA2; /* 0x1A0 32 R/W WISHBONE Image2 Translation Address reg */
111 uint32 W_IMG_CTRL3; /* 0x1A4 32 R/W WISHBONE Image3 Control register */
112 uint32 W_BA3; /* 0x1A8 32 R/W WISHBONE Image3 Base Address register */
113 uint32 W_AM3; /* 0x1AC 32 R/W WISHBONE Image3 Address Mask register */
114 uint32 W_TA3; /* 0x1B0 32 R/W WISHBONE Image3 Translation Address reg */
115 uint32 W_IMG_CTRL4; /* 0x1B4 32 R/W WISHBONE Image4 Control register */
116 uint32 W_BA4; /* 0x1B8 32 R/W WISHBONE Image4 Base Address register */
117 uint32 W_AM4; /* 0x1BC 32 R/W WISHBONE Image4 Address Mask register */
118 uint32 W_TA4; /* 0x1C0 32 R/W WISHBONE Image4 Translation Address reg */
119 uint32 W_IMG_CTRL5; /* 0x1C4 32 R/W WISHBONE Image5 Control register */
120 uint32 W_BA5; /* 0x1C8 32 R/W WISHBONE Image5 Base Address register */
121 uint32 W_AM5; /* 0x1CC 32 R/W WISHBONE Image5 Address Mask register */
122 uint32 W_TA5; /* 0x1D0 32 R/W WISHBONE Image5 Translation Address reg */
123 uint32 W_ERR_CS; /* 0x1D4 32 R/W WISHBONE Error Control and Status reg */
124 uint32 W_ERR_ADDR; /* 0x1D8 32 R WISHBONE Erroneous Address register */
125 uint32 W_ERR_DATA; /* 0x1DC 32 R WISHBONE Erroneous Data register */
126 uint32 CNF_ADDR; /* 0x1E0 32 R/W Configuration Cycle register */
127 uint32 CNF_DATA; /* 0x1E4 32 R/W Configuration Cycle Generation Data reg */
128
129 uint32 INT_ACK; /* 0x1E8 32 R Interrupt Acknowledge register */
130 uint32 ICR; /* 0x1EC 32 R/W Interrupt Control register */
131 uint32 ISR; /* 0x1F0 32 R/W Interrupt Status register */
132} spih_pciregs_t;
133
134/*
135 * PCI Core interrupt enable and status bit definitions.
136 */
137
138/* PCI Core ICR Register bit definitions */
139#define PCI_INT_PROP_EN (1 << 0) /* Interrupt Propagation Enable */
140#define PCI_WB_ERR_INT_EN (1 << 1) /* Wishbone Error Interrupt Enable */
141#define PCI_PCI_ERR_INT_EN (1 << 2) /* PCI Error Interrupt Enable */
142#define PCI_PAR_ERR_INT_EN (1 << 3) /* Parity Error Interrupt Enable */
143#define PCI_SYS_ERR_INT_EN (1 << 4) /* System Error Interrupt Enable */
144#define PCI_SOFTWARE_RESET (1U << 31) /* Software reset of the PCI Core. */
145
146
147/* PCI Core ISR Register bit definitions */
148#define PCI_INT_PROP_ST (1 << 0) /* Interrupt Propagation Status */
149#define PCI_WB_ERR_INT_ST (1 << 1) /* Wishbone Error Interrupt Status */
150#define PCI_PCI_ERR_INT_ST (1 << 2) /* PCI Error Interrupt Status */
151#define PCI_PAR_ERR_INT_ST (1 << 3) /* Parity Error Interrupt Status */
152#define PCI_SYS_ERR_INT_ST (1 << 4) /* System Error Interrupt Status */
153
154
155/* Registers on the Wishbone bus */
156#define SPIH_CTLR_INTR (1 << 0) /* SPI Host Controller Core Interrupt */
157#define SPIH_DEV_INTR (1 << 1) /* SPI Device Interrupt */
158#define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */
159
160/* GPIO Bit definitions */
161#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */
162#define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */
163#define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */
164
165/* SPI Status Register Bit definitions */
166#define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */
167#define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */
168#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */
169#define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */
170#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */
171#define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */
172
173#define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */
174
175#define SPIH_PLL_NO_CLK (1 << 1) /* Set to 1 if the PLL's input clock is lost. */
176#define SPIH_PLL_LOCKED (1 << 3) /* Set to 1 when the PLL is locked. */
177
178/* Spin bit loop bound check */
179#define SPI_SPIN_BOUND 0xf4240 /* 1 million */
180
181#endif /* _BCM_PCI_SPI_H */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmperf.h b/drivers/net/wireless/bcmdhd/include/bcmperf.h
new file mode 100644
index 00000000000..a3985cf2937
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmperf.h
@@ -0,0 +1,36 @@
1/*
2 * Performance counters software interface.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmperf.h,v 13.5 2007-09-14 22:00:59 Exp $
25 */
26/* essai */
27#ifndef _BCMPERF_H_
28#define _BCMPERF_H_
29/* get cache hits and misses */
30#define BCMPERF_ENABLE_INSTRCOUNT()
31#define BCMPERF_ENABLE_ICACHE_MISS()
32#define BCMPERF_ENABLE_ICACHE_HIT()
33#define BCMPERF_GETICACHE_MISS(x) ((x) = 0)
34#define BCMPERF_GETICACHE_HIT(x) ((x) = 0)
35#define BCMPERF_GETINSTRCOUNT(x) ((x) = 0)
36#endif /* _BCMPERF_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h
new file mode 100644
index 00000000000..5fda5e9b5df
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h
@@ -0,0 +1,120 @@
1/*
2 * Definitions for API from sdio common code (bcmsdh) to individual
3 * host controller drivers.
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: bcmsdbus.h,v 13.17.86.2 2010-12-23 01:13:20 Exp $
26 */
27
28#ifndef _sdio_api_h_
29#define _sdio_api_h_
30
31
32#define SDIOH_API_RC_SUCCESS (0x00)
33#define SDIOH_API_RC_FAIL (0x01)
34#define SDIOH_API_SUCCESS(status) (status == 0)
35
36#define SDIOH_READ 0 /* Read request */
37#define SDIOH_WRITE 1 /* Write request */
38
39#define SDIOH_DATA_FIX 0 /* Fixed addressing */
40#define SDIOH_DATA_INC 1 /* Incremental addressing */
41
42#define SDIOH_CMD_TYPE_NORMAL 0 /* Normal command */
43#define SDIOH_CMD_TYPE_APPEND 1 /* Append command */
44#define SDIOH_CMD_TYPE_CUTTHRU 2 /* Cut-through command */
45
46#define SDIOH_DATA_PIO 0 /* PIO mode */
47#define SDIOH_DATA_DMA 1 /* DMA mode */
48
49
50typedef int SDIOH_API_RC;
51
52/* SDio Host structure */
53typedef struct sdioh_info sdioh_info_t;
54
55/* callback function, taking one arg */
56typedef void (*sdioh_cb_fn_t)(void *);
57
58/* attach, return handler on success, NULL if failed.
59 * The handler shall be provided by all subsequent calls. No local cache
60 * cfghdl points to the starting address of pci device mapped memory
61 */
62extern sdioh_info_t * sdioh_attach(osl_t *osh, void *cfghdl, uint irq);
63extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *si);
64extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *si, sdioh_cb_fn_t fn, void *argh);
65extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *si);
66
67/* query whether SD interrupt is enabled or not */
68extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *si, bool *onoff);
69
70/* enable or disable SD interrupt */
71extern SDIOH_API_RC sdioh_interrupt_set(sdioh_info_t *si, bool enable_disable);
72
73#if defined(DHD_DEBUG)
74extern bool sdioh_interrupt_pending(sdioh_info_t *si);
75#endif
76
77/* read or write one byte using cmd52 */
78extern SDIOH_API_RC sdioh_request_byte(sdioh_info_t *si, uint rw, uint fnc, uint addr, uint8 *byte);
79
80/* read or write 2/4 bytes using cmd53 */
81extern SDIOH_API_RC sdioh_request_word(sdioh_info_t *si, uint cmd_type, uint rw, uint fnc,
82 uint addr, uint32 *word, uint nbyte);
83
84/* read or write any buffer using cmd53 */
85extern SDIOH_API_RC sdioh_request_buffer(sdioh_info_t *si, uint pio_dma, uint fix_inc,
86 uint rw, uint fnc_num, uint32 addr, uint regwidth, uint32 buflen, uint8 *buffer,
87 void *pkt);
88
89/* get cis data */
90extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, uint8 *cis, uint32 length);
91
92extern SDIOH_API_RC sdioh_cfg_read(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data);
93extern SDIOH_API_RC sdioh_cfg_write(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data);
94
95/* query number of io functions */
96extern uint sdioh_query_iofnum(sdioh_info_t *si);
97
98/* handle iovars */
99extern int sdioh_iovar_op(sdioh_info_t *si, const char *name,
100 void *params, int plen, void *arg, int len, bool set);
101
102/* Issue abort to the specified function and clear controller as needed */
103extern int sdioh_abort(sdioh_info_t *si, uint fnc);
104
105/* Start and Stop SDIO without re-enumerating the SD card. */
106extern int sdioh_start(sdioh_info_t *si, int stage);
107extern int sdioh_stop(sdioh_info_t *si);
108
109/* Wait system lock free */
110extern int sdioh_waitlockfree(sdioh_info_t *si);
111
112/* Reset and re-initialize the device */
113extern int sdioh_sdio_reset(sdioh_info_t *si);
114
115/* Helper function */
116void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh);
117
118
119
120#endif /* _sdio_api_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh.h b/drivers/net/wireless/bcmdhd/include/bcmsdh.h
new file mode 100644
index 00000000000..4e3affde6b0
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdh.h
@@ -0,0 +1,211 @@
1/*
2 * SDIO host client driver interface of Broadcom HNBU
3 * export functions to client drivers
4 * abstract OS and BUS specific details of SDIO
5 *
6 * Copyright (C) 1999-2011, Broadcom Corporation
7 *
8 * Unless you and Broadcom execute a separate written software license
9 * agreement governing use of this software, this software is licensed to you
10 * under the terms of the GNU General Public License version 2 (the "GPL"),
11 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
12 * following added to such license:
13 *
14 * As a special exception, the copyright holders of this software give you
15 * permission to link this software with independent modules, and to copy and
16 * distribute the resulting executable under terms of your choice, provided that
17 * you also meet, for each linked independent module, the terms and conditions of
18 * the license of that module. An independent module is a module which is not
19 * derived from this software. The special exception does not apply to any
20 * modifications of the software.
21 *
22 * Notwithstanding the above, under no circumstances may you combine this
23 * software in any way with any other Broadcom software provided under a license
24 * other than the GPL, without Broadcom's express prior written consent.
25 *
26 * $Id: bcmsdh.h,v 13.46.52.3 2010-10-19 00:41:44 Exp $
27 */
28
29#ifndef _bcmsdh_h_
30#define _bcmsdh_h_
31
32#define BCMSDH_ERROR_VAL 0x0001 /* Error */
33#define BCMSDH_INFO_VAL 0x0002 /* Info */
34extern const uint bcmsdh_msglevel;
35
36#define BCMSDH_ERROR(x)
37#define BCMSDH_INFO(x)
38
39/* forward declarations */
40typedef struct bcmsdh_info bcmsdh_info_t;
41typedef void (*bcmsdh_cb_fn_t)(void *);
42
43/* Attach and build an interface to the underlying SD host driver.
44 * - Allocates resources (structs, arrays, mem, OS handles, etc) needed by bcmsdh.
45 * - Returns the bcmsdh handle and virtual address base for register access.
46 * The returned handle should be used in all subsequent calls, but the bcmsh
47 * implementation may maintain a single "default" handle (e.g. the first or
48 * most recent one) to enable single-instance implementations to pass NULL.
49 */
50extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq);
51
52/* Detach - freeup resources allocated in attach */
53extern int bcmsdh_detach(osl_t *osh, void *sdh);
54
55/* Query if SD device interrupts are enabled */
56extern bool bcmsdh_intr_query(void *sdh);
57
58/* Enable/disable SD interrupt */
59extern int bcmsdh_intr_enable(void *sdh);
60extern int bcmsdh_intr_disable(void *sdh);
61
62/* Register/deregister device interrupt handler. */
63extern int bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh);
64extern int bcmsdh_intr_dereg(void *sdh);
65
66#if defined(DHD_DEBUG)
67/* Query pending interrupt status from the host controller */
68extern bool bcmsdh_intr_pending(void *sdh);
69#endif
70
71#ifdef BCMLXSDMMC
72extern int bcmsdh_claim_host_and_lock(void *sdh);
73extern int bcmsdh_release_host_and_unlock(void *sdh);
74#endif /* BCMLXSDMMC */
75
76/* Register a callback to be called if and when bcmsdh detects
77 * device removal. No-op in the case of non-removable/hardwired devices.
78 */
79extern int bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh);
80
81/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface).
82 * fn: function number
83 * addr: unmodified SDIO-space address
84 * data: data byte to write
85 * err: pointer to error code (or NULL)
86 */
87extern uint8 bcmsdh_cfg_read(void *sdh, uint func, uint32 addr, int *err);
88extern void bcmsdh_cfg_write(void *sdh, uint func, uint32 addr, uint8 data, int *err);
89
90/* Read/Write 4bytes from/to cfg space */
91extern uint32 bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err);
92extern void bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err);
93
94/* Read CIS content for specified function.
95 * fn: function whose CIS is being requested (0 is common CIS)
96 * cis: pointer to memory location to place results
97 * length: number of bytes to read
98 * Internally, this routine uses the values from the cis base regs (0x9-0xB)
99 * to form an SDIO-space address to read the data from.
100 */
101extern int bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length);
102
103/* Synchronous access to device (client) core registers via CMD53 to F1.
104 * addr: backplane address (i.e. >= regsva from attach)
105 * size: register width in bytes (2 or 4)
106 * data: data for register write
107 */
108extern uint32 bcmsdh_reg_read(void *sdh, uint32 addr, uint size);
109extern uint32 bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data);
110
111/* Indicate if last reg read/write failed */
112extern bool bcmsdh_regfail(void *sdh);
113
114/* Buffer transfer to/from device (client) core via cmd53.
115 * fn: function number
116 * addr: backplane address (i.e. >= regsva from attach)
117 * flags: backplane width, address increment, sync/async
118 * buf: pointer to memory data buffer
119 * nbytes: number of bytes to transfer to/from buf
120 * pkt: pointer to packet associated with buf (if any)
121 * complete: callback function for command completion (async only)
122 * handle: handle for completion callback (first arg in callback)
123 * Returns 0 or error code.
124 * NOTE: Async operation is not currently supported.
125 */
126typedef void (*bcmsdh_cmplt_fn_t)(void *handle, int status, bool sync_waiting);
127extern int bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags,
128 uint8 *buf, uint nbytes, void *pkt,
129 bcmsdh_cmplt_fn_t complete, void *handle);
130extern int bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags,
131 uint8 *buf, uint nbytes, void *pkt,
132 bcmsdh_cmplt_fn_t complete, void *handle);
133
134/* Flags bits */
135#define SDIO_REQ_4BYTE 0x1 /* Four-byte target (backplane) width (vs. two-byte) */
136#define SDIO_REQ_FIXED 0x2 /* Fixed address (FIFO) (vs. incrementing address) */
137#define SDIO_REQ_ASYNC 0x4 /* Async request (vs. sync request) */
138
139/* Pending (non-error) return code */
140#define BCME_PENDING 1
141
142/* Read/write to memory block (F1, no FIFO) via CMD53 (sync only).
143 * rw: read or write (0/1)
144 * addr: direct SDIO address
145 * buf: pointer to memory data buffer
146 * nbytes: number of bytes to transfer to/from buf
147 * Returns 0 or error code.
148 */
149extern int bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes);
150
151/* Issue an abort to the specified function */
152extern int bcmsdh_abort(void *sdh, uint fn);
153
154/* Start SDIO Host Controller communication */
155extern int bcmsdh_start(void *sdh, int stage);
156
157/* Stop SDIO Host Controller communication */
158extern int bcmsdh_stop(void *sdh);
159
160/* Wait system lock free */
161extern int bcmsdh_waitlockfree(void *sdh);
162
163/* Returns the "Device ID" of target device on the SDIO bus. */
164extern int bcmsdh_query_device(void *sdh);
165
166/* Returns the number of IO functions reported by the device */
167extern uint bcmsdh_query_iofnum(void *sdh);
168
169/* Miscellaneous knob tweaker. */
170extern int bcmsdh_iovar_op(void *sdh, const char *name,
171 void *params, int plen, void *arg, int len, bool set);
172
173/* Reset and reinitialize the device */
174extern int bcmsdh_reset(bcmsdh_info_t *sdh);
175
176/* helper functions */
177
178extern void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh);
179
180/* callback functions */
181typedef struct {
182 /* attach to device */
183 void *(*attach)(uint16 vend_id, uint16 dev_id, uint16 bus, uint16 slot,
184 uint16 func, uint bustype, void * regsva, osl_t * osh,
185 void * param, void *dev);
186 /* detach from device */
187 void (*detach)(void *ch);
188} bcmsdh_driver_t;
189
190/* platform specific/high level functions */
191extern int bcmsdh_register(bcmsdh_driver_t *driver);
192extern void bcmsdh_unregister(void);
193extern bool bcmsdh_chipmatch(uint16 vendor, uint16 device);
194extern void bcmsdh_device_remove(void * sdh);
195
196#if defined(OOB_INTR_ONLY)
197extern int bcmsdh_register_oob_intr(void * dhdp);
198extern void bcmsdh_unregister_oob_intr(void);
199extern void bcmsdh_oob_intr_set(bool enable);
200#endif /* defined(OOB_INTR_ONLY) */
201/* Function to pass device-status bits to DHD. */
202extern uint32 bcmsdh_get_dstatus(void *sdh);
203
204/* Function to return current window addr */
205extern uint32 bcmsdh_cur_sbwad(void *sdh);
206
207/* Function to pass chipid and rev to lower layers for controlling pr's */
208extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev);
209
210
211#endif /* _bcmsdh_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h
new file mode 100644
index 00000000000..d188c4ec7d5
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h
@@ -0,0 +1,122 @@
1/*
2 * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmsdh_sdmmc.h,v 13.5.88.1 2010-12-23 01:13:20 Exp $
25 */
26
27#ifndef __BCMSDH_SDMMC_H__
28#define __BCMSDH_SDMMC_H__
29
30#define sd_err(x)
31#define sd_trace(x)
32#define sd_info(x)
33#define sd_debug(x)
34#define sd_data(x)
35#define sd_ctrl(x)
36
37#define sd_sync_dma(sd, read, nbytes)
38#define sd_init_dma(sd)
39#define sd_ack_intr(sd)
40#define sd_wakeup(sd);
41
42/* Allocate/init/free per-OS private data */
43extern int sdioh_sdmmc_osinit(sdioh_info_t *sd);
44extern void sdioh_sdmmc_osfree(sdioh_info_t *sd);
45
46#define sd_log(x)
47
48#define SDIOH_ASSERT(exp) \
49 do { if (!(exp)) \
50 printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \
51 } while (0)
52
53#define BLOCK_SIZE_4318 64
54#define BLOCK_SIZE_4328 512
55
56/* internal return code */
57#define SUCCESS 0
58#define ERROR 1
59
60/* private bus modes */
61#define SDIOH_MODE_SD4 2
62#define CLIENT_INTR 0x100 /* Get rid of this! */
63
64struct sdioh_info {
65 osl_t *osh; /* osh handler */
66 bool client_intr_enabled; /* interrupt connnected flag */
67 bool intr_handler_valid; /* client driver interrupt handler valid */
68 sdioh_cb_fn_t intr_handler; /* registered interrupt handler */
69 void *intr_handler_arg; /* argument to call interrupt handler */
70 uint16 intmask; /* Current active interrupts */
71 void *sdos_info; /* Pointer to per-OS private data */
72
73 uint irq; /* Client irq */
74 int intrcount; /* Client interrupts */
75
76 bool sd_use_dma; /* DMA on CMD53 */
77 bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */
78 /* Must be on for sd_multiblock to be effective */
79 bool use_client_ints; /* If this is false, make sure to restore */
80 int sd_mode; /* SD1/SD4/SPI */
81 int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */
82 uint8 num_funcs; /* Supported funcs on client */
83 uint32 com_cis_ptr;
84 uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
85 uint max_dma_len;
86 uint max_dma_descriptors; /* DMA Descriptors supported by this controller. */
87// SDDMA_DESCRIPTOR SGList[32]; /* Scatter/Gather DMA List */
88};
89
90/************************************************************
91 * Internal interfaces: per-port references into bcmsdh_sdmmc.c
92 */
93
94/* Global message bits */
95extern uint sd_msglevel;
96
97/* OS-independent interrupt handler */
98extern bool check_client_intr(sdioh_info_t *sd);
99
100/* Core interrupt enable/disable of device interrupts */
101extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd);
102extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd);
103
104
105/**************************************************************
106 * Internal interfaces: bcmsdh_sdmmc.c references to per-port code
107 */
108
109/* Register mapping routines */
110extern uint32 *sdioh_sdmmc_reg_map(osl_t *osh, int32 addr, int size);
111extern void sdioh_sdmmc_reg_unmap(osl_t *osh, int32 addr, int size);
112
113/* Interrupt (de)registration routines */
114extern int sdioh_sdmmc_register_irq(sdioh_info_t *sd, uint irq);
115extern void sdioh_sdmmc_free_irq(uint irq, sdioh_info_t *sd);
116
117typedef struct _BCMSDH_SDMMC_INSTANCE {
118 sdioh_info_t *sd;
119 struct sdio_func *func[SDIOD_MAX_IOFUNCS];
120} BCMSDH_SDMMC_INSTANCE, *PBCMSDH_SDMMC_INSTANCE;
121
122#endif /* __BCMSDH_SDMMC_H__ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
new file mode 100644
index 00000000000..ee29b5c08a5
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h
@@ -0,0 +1,274 @@
1/*
2 * Broadcom SDIO/PCMCIA
3 * Software-specific definitions shared between device and host side
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: bcmsdpcm.h,v 13.4.90.2 2010-05-12 04:14:25 Exp $
26 */
27
28#ifndef _bcmsdpcm_h_
29#define _bcmsdpcm_h_
30
31/*
32 * Software allocation of To SB Mailbox resources
33 */
34
35/* intstatus bits */
36#define I_SMB_NAK I_SMB_SW0 /* To SB Mailbox Frame NAK */
37#define I_SMB_INT_ACK I_SMB_SW1 /* To SB Mailbox Host Interrupt ACK */
38#define I_SMB_USE_OOB I_SMB_SW2 /* To SB Mailbox Use OOB Wakeup */
39#define I_SMB_DEV_INT I_SMB_SW3 /* To SB Mailbox Miscellaneous Interrupt */
40
41#define I_TOSBMAIL (I_SMB_NAK | I_SMB_INT_ACK | I_SMB_USE_OOB | I_SMB_DEV_INT)
42
43/* tosbmailbox bits corresponding to intstatus bits */
44#define SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */
45#define SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */
46#define SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */
47#define SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */
48#define SMB_MASK 0x0000000f /* To SB Mailbox Mask */
49
50/* tosbmailboxdata */
51#define SMB_DATA_VERSION_MASK 0x00ff0000 /* host protocol version (sent with F2 enable) */
52#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version (sent with F2 enable) */
53
54/*
55 * Software allocation of To Host Mailbox resources
56 */
57
58/* intstatus bits */
59#define I_HMB_FC_STATE I_HMB_SW0 /* To Host Mailbox Flow Control State */
60#define I_HMB_FC_CHANGE I_HMB_SW1 /* To Host Mailbox Flow Control State Changed */
61#define I_HMB_FRAME_IND I_HMB_SW2 /* To Host Mailbox Frame Indication */
62#define I_HMB_HOST_INT I_HMB_SW3 /* To Host Mailbox Miscellaneous Interrupt */
63
64#define I_TOHOSTMAIL (I_HMB_FC_CHANGE | I_HMB_FRAME_IND | I_HMB_HOST_INT)
65
66/* tohostmailbox bits corresponding to intstatus bits */
67#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State */
68#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */
69#define HMB_FRAME_IND (1 << 2) /* To Host Mailbox Frame Indication */
70#define HMB_HOST_INT (1 << 3) /* To Host Mailbox Miscellaneous Interrupt */
71#define HMB_MASK 0x0000000f /* To Host Mailbox Mask */
72
73/* tohostmailboxdata */
74#define HMB_DATA_NAKHANDLED 0x01 /* we're ready to retransmit NAK'd frame to host */
75#define HMB_DATA_DEVREADY 0x02 /* we're ready to to talk to host after enable */
76#define HMB_DATA_FC 0x04 /* per prio flowcontrol update flag to host */
77#define HMB_DATA_FWREADY 0x08 /* firmware is ready for protocol activity */
78#define HMB_DATA_FWHALT 0x10 /* firmware has halted operation */
79
80#define HMB_DATA_FCDATA_MASK 0xff000000 /* per prio flowcontrol data */
81#define HMB_DATA_FCDATA_SHIFT 24 /* per prio flowcontrol data */
82
83#define HMB_DATA_VERSION_MASK 0x00ff0000 /* device protocol version (with devready) */
84#define HMB_DATA_VERSION_SHIFT 16 /* device protocol version (with devready) */
85
86/*
87 * Software-defined protocol header
88 */
89
90/* Current protocol version */
91#define SDPCM_PROT_VERSION 4
92
93/* SW frame header */
94#define SDPCM_SEQUENCE_MASK 0x000000ff /* Sequence Number Mask */
95#define SDPCM_PACKET_SEQUENCE(p) (((uint8 *)p)[0] & 0xff) /* p starts w/SW Header */
96
97#define SDPCM_CHANNEL_MASK 0x00000f00 /* Channel Number Mask */
98#define SDPCM_CHANNEL_SHIFT 8 /* Channel Number Shift */
99#define SDPCM_PACKET_CHANNEL(p) (((uint8 *)p)[1] & 0x0f) /* p starts w/SW Header */
100
101#define SDPCM_FLAGS_MASK 0x0000f000 /* Mask of flag bits */
102#define SDPCM_FLAGS_SHIFT 12 /* Flag bits shift */
103#define SDPCM_PACKET_FLAGS(p) ((((uint8 *)p)[1] & 0xf0) >> 4) /* p starts w/SW Header */
104
105/* Next Read Len: lookahead length of next frame, in 16-byte units (rounded up) */
106#define SDPCM_NEXTLEN_MASK 0x00ff0000 /* Next Read Len Mask */
107#define SDPCM_NEXTLEN_SHIFT 16 /* Next Read Len Shift */
108#define SDPCM_NEXTLEN_VALUE(p) ((((uint8 *)p)[2] & 0xff) << 4) /* p starts w/SW Header */
109#define SDPCM_NEXTLEN_OFFSET 2
110
111/* Data Offset from SOF (HW Tag, SW Tag, Pad) */
112#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */
113#define SDPCM_DOFFSET_VALUE(p) (((uint8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff)
114#define SDPCM_DOFFSET_MASK 0xff000000
115#define SDPCM_DOFFSET_SHIFT 24
116
117#define SDPCM_FCMASK_OFFSET 4 /* Flow control */
118#define SDPCM_FCMASK_VALUE(p) (((uint8 *)p)[SDPCM_FCMASK_OFFSET ] & 0xff)
119#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */
120#define SDPCM_WINDOW_VALUE(p) (((uint8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff)
121#define SDPCM_VERSION_OFFSET 6 /* Version # */
122#define SDPCM_VERSION_VALUE(p) (((uint8 *)p)[SDPCM_VERSION_OFFSET] & 0xff)
123#define SDPCM_UNUSED_OFFSET 7 /* Spare */
124#define SDPCM_UNUSED_VALUE(p) (((uint8 *)p)[SDPCM_UNUSED_OFFSET] & 0xff)
125
126#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */
127
128/* logical channel numbers */
129#define SDPCM_CONTROL_CHANNEL 0 /* Control Request/Response Channel Id */
130#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */
131#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */
132#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets (superframes) */
133#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */
134#define SDPCM_MAX_CHANNEL 15
135
136#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for eight-bit frame seq number */
137
138#define SDPCM_FLAG_RESVD0 0x01
139#define SDPCM_FLAG_RESVD1 0x02
140#define SDPCM_FLAG_GSPI_TXENAB 0x04
141#define SDPCM_FLAG_GLOMDESC 0x08 /* Superframe descriptor mask */
142
143/* For GLOM_CHANNEL frames, use a flag to indicate descriptor frame */
144#define SDPCM_GLOMDESC_FLAG (SDPCM_FLAG_GLOMDESC << SDPCM_FLAGS_SHIFT)
145
146#define SDPCM_GLOMDESC(p) (((uint8 *)p)[1] & 0x80)
147
148/* For TEST_CHANNEL packets, define another 4-byte header */
149#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2);
150 * Semantics of Ext byte depend on command.
151 * Len is current or requested frame length, not
152 * including test header; sent little-endian.
153 */
154#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */
155#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */
156#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */
157#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count */
158#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off */
159
160/* Handy macro for filling in datagen packets with a pattern */
161#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno))
162
163/*
164 * Software counters (first part matches hardware counters)
165 */
166
167typedef volatile struct {
168 uint32 cmd52rd; /* Cmd52RdCount, SDIO: cmd52 reads */
169 uint32 cmd52wr; /* Cmd52WrCount, SDIO: cmd52 writes */
170 uint32 cmd53rd; /* Cmd53RdCount, SDIO: cmd53 reads */
171 uint32 cmd53wr; /* Cmd53WrCount, SDIO: cmd53 writes */
172 uint32 abort; /* AbortCount, SDIO: aborts */
173 uint32 datacrcerror; /* DataCrcErrorCount, SDIO: frames w/CRC error */
174 uint32 rdoutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Rd Frm out of sync */
175 uint32 wroutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Wr Frm out of sync */
176 uint32 writebusy; /* WriteBusyCount, SDIO: device asserted "busy" */
177 uint32 readwait; /* ReadWaitCount, SDIO: no data ready for a read cmd */
178 uint32 readterm; /* ReadTermCount, SDIO: read frame termination cmds */
179 uint32 writeterm; /* WriteTermCount, SDIO: write frames termination cmds */
180 uint32 rxdescuflo; /* receive descriptor underflows */
181 uint32 rxfifooflo; /* receive fifo overflows */
182 uint32 txfifouflo; /* transmit fifo underflows */
183 uint32 runt; /* runt (too short) frames recv'd from bus */
184 uint32 badlen; /* frame's rxh len does not match its hw tag len */
185 uint32 badcksum; /* frame's hw tag chksum doesn't agree with len value */
186 uint32 seqbreak; /* break in sequence # space from one rx frame to the next */
187 uint32 rxfcrc; /* frame rx header indicates crc error */
188 uint32 rxfwoos; /* frame rx header indicates write out of sync */
189 uint32 rxfwft; /* frame rx header indicates write frame termination */
190 uint32 rxfabort; /* frame rx header indicates frame aborted */
191 uint32 woosint; /* write out of sync interrupt */
192 uint32 roosint; /* read out of sync interrupt */
193 uint32 rftermint; /* read frame terminate interrupt */
194 uint32 wftermint; /* write frame terminate interrupt */
195} sdpcmd_cnt_t;
196
197/*
198 * Register Access Macros
199 */
200
201#define SDIODREV_IS(var, val) ((var) == (val))
202#define SDIODREV_GE(var, val) ((var) >= (val))
203#define SDIODREV_GT(var, val) ((var) > (val))
204#define SDIODREV_LT(var, val) ((var) < (val))
205#define SDIODREV_LE(var, val) ((var) <= (val))
206
207#define SDIODDMAREG32(h, dir, chnl) \
208 ((dir) == DMA_TX ? \
209 (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].xmt) : \
210 (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].rcv))
211
212#define SDIODDMAREG64(h, dir, chnl) \
213 ((dir) == DMA_TX ? \
214 (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].xmt) : \
215 (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].rcv))
216
217#define SDIODDMAREG(h, dir, chnl) \
218 (SDIODREV_LT((h)->corerev, 1) ? \
219 SDIODDMAREG32((h), (dir), (chnl)) : \
220 SDIODDMAREG64((h), (dir), (chnl)))
221
222#define PCMDDMAREG(h, dir, chnl) \
223 ((dir) == DMA_TX ? \
224 (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.xmt) : \
225 (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.rcv))
226
227#define SDPCMDMAREG(h, dir, chnl, coreid) \
228 ((coreid) == SDIOD_CORE_ID ? \
229 SDIODDMAREG(h, dir, chnl) : \
230 PCMDDMAREG(h, dir, chnl))
231
232#define SDIODFIFOREG(h, corerev) \
233 (SDIODREV_LT((corerev), 1) ? \
234 ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod32.dmafifo)) : \
235 ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod64.dmafifo)))
236
237#define PCMDFIFOREG(h) \
238 ((dma32diag_t *)(uintptr)&((h)->regs->dma.pcm32.dmafifo))
239
240#define SDPCMFIFOREG(h, coreid, corerev) \
241 ((coreid) == SDIOD_CORE_ID ? \
242 SDIODFIFOREG(h, corerev) : \
243 PCMDFIFOREG(h))
244
245/*
246 * Shared structure between dongle and the host.
247 * The structure contains pointers to trap or assert information.
248 */
249#define SDPCM_SHARED_VERSION 0x0001
250#define SDPCM_SHARED_VERSION_MASK 0x00FF
251#define SDPCM_SHARED_ASSERT_BUILT 0x0100
252#define SDPCM_SHARED_ASSERT 0x0200
253#define SDPCM_SHARED_TRAP 0x0400
254#define SDPCM_SHARED_IN_BRPT 0x0800
255#define SDPCM_SHARED_SET_BRPT 0x1000
256#define SDPCM_SHARED_PENDING_BRPT 0x2000
257
258typedef struct {
259 uint32 flags;
260 uint32 trap_addr;
261 uint32 assert_exp_addr;
262 uint32 assert_file_addr;
263 uint32 assert_line;
264 uint32 console_addr; /* Address of hndrte_cons_t */
265 uint32 msgtrace_addr;
266 uint32 brpt_addr;
267} sdpcm_shared_t;
268
269extern sdpcm_shared_t sdpcm_shared;
270
271/* Function can be used to notify host of FW halt */
272extern void sdpcmd_fwhalt(void);
273
274#endif /* _bcmsdpcm_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h
new file mode 100644
index 00000000000..0bff355f8ff
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h
@@ -0,0 +1,135 @@
1/*
2 * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmsdspi.h,v 13.11.86.1 2010-11-15 18:14:56 Exp $
25 */
26#ifndef _BCM_SD_SPI_H
27#define _BCM_SD_SPI_H
28
29/* global msglevel for debug messages - bitvals come from sdiovar.h */
30
31#define sd_err(x)
32#define sd_trace(x)
33#define sd_info(x)
34#define sd_debug(x)
35#define sd_data(x)
36#define sd_ctrl(x)
37
38#define sd_log(x)
39
40#define SDIOH_ASSERT(exp) \
41 do { if (!(exp)) \
42 printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \
43 } while (0)
44
45#define BLOCK_SIZE_4318 64
46#define BLOCK_SIZE_4328 512
47
48/* internal return code */
49#define SUCCESS 0
50#undef ERROR
51#define ERROR 1
52
53/* private bus modes */
54#define SDIOH_MODE_SPI 0
55
56#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */
57#define USE_MULTIBLOCK 0x4
58
59struct sdioh_info {
60 uint cfg_bar; /* pci cfg address for bar */
61 uint32 caps; /* cached value of capabilities reg */
62 uint bar0; /* BAR0 for PCI Device */
63 osl_t *osh; /* osh handler */
64 void *controller; /* Pointer to SPI Controller's private data struct */
65
66 uint lockcount; /* nest count of sdspi_lock() calls */
67 bool client_intr_enabled; /* interrupt connnected flag */
68 bool intr_handler_valid; /* client driver interrupt handler valid */
69 sdioh_cb_fn_t intr_handler; /* registered interrupt handler */
70 void *intr_handler_arg; /* argument to call interrupt handler */
71 bool initialized; /* card initialized */
72 uint32 target_dev; /* Target device ID */
73 uint32 intmask; /* Current active interrupts */
74 void *sdos_info; /* Pointer to per-OS private data */
75
76 uint32 controller_type; /* Host controller type */
77 uint8 version; /* Host Controller Spec Compliance Version */
78 uint irq; /* Client irq */
79 uint32 intrcount; /* Client interrupts */
80 uint32 local_intrcount; /* Controller interrupts */
81 bool host_init_done; /* Controller initted */
82 bool card_init_done; /* Client SDIO interface initted */
83 bool polled_mode; /* polling for command completion */
84
85 bool sd_use_dma; /* DMA on CMD53 */
86 bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */
87 /* Must be on for sd_multiblock to be effective */
88 bool use_client_ints; /* If this is false, make sure to restore */
89 bool got_hcint; /* Host Controller interrupt. */
90 /* polling hack in wl_linux.c:wl_timer() */
91 int adapter_slot; /* Maybe dealing with multiple slots/controllers */
92 int sd_mode; /* SD1/SD4/SPI */
93 int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */
94 uint32 data_xfer_count; /* Current register transfer size */
95 uint32 cmd53_wr_data; /* Used to pass CMD53 write data */
96 uint32 card_response; /* Used to pass back response status byte */
97 uint32 card_rsp_data; /* Used to pass back response data word */
98 uint16 card_rca; /* Current Address */
99 uint8 num_funcs; /* Supported funcs on client */
100 uint32 com_cis_ptr;
101 uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
102 void *dma_buf;
103 ulong dma_phys;
104 int r_cnt; /* rx count */
105 int t_cnt; /* tx_count */
106};
107
108/************************************************************
109 * Internal interfaces: per-port references into bcmsdspi.c
110 */
111
112/* Global message bits */
113extern uint sd_msglevel;
114
115/**************************************************************
116 * Internal interfaces: bcmsdspi.c references to per-port code
117 */
118
119/* Register mapping routines */
120extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size);
121extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size);
122
123/* Interrupt (de)registration routines */
124extern int spi_register_irq(sdioh_info_t *sd, uint irq);
125extern void spi_free_irq(uint irq, sdioh_info_t *sd);
126
127/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */
128extern void spi_lock(sdioh_info_t *sd);
129extern void spi_unlock(sdioh_info_t *sd);
130
131/* Allocate/init/free per-OS private data */
132extern int spi_osinit(sdioh_info_t *sd);
133extern void spi_osfree(sdioh_info_t *sd);
134
135#endif /* _BCM_SD_SPI_H */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h
new file mode 100644
index 00000000000..0f4c0267dbc
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h
@@ -0,0 +1,267 @@
1/*
2 * 'Standard' SDIO HOST CONTROLLER driver
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmsdstd.h,v 13.21.2.6 2010-11-15 18:14:01 Exp $
25 */
26#ifndef _BCM_SD_STD_H
27#define _BCM_SD_STD_H
28
29/* global msglevel for debug messages - bitvals come from sdiovar.h */
30#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0)
31#define sd_trace(x)
32#define sd_info(x)
33#define sd_debug(x)
34#define sd_data(x)
35#define sd_ctrl(x)
36#define sd_dma(x)
37
38#define sd_sync_dma(sd, read, nbytes)
39#define sd_init_dma(sd)
40#define sd_ack_intr(sd)
41#define sd_wakeup(sd);
42/* Allocate/init/free per-OS private data */
43extern int sdstd_osinit(sdioh_info_t *sd);
44extern void sdstd_osfree(sdioh_info_t *sd);
45
46#define sd_log(x)
47
48#define SDIOH_ASSERT(exp) \
49 do { if (!(exp)) \
50 printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \
51 } while (0)
52
53#define BLOCK_SIZE_4318 64
54#define BLOCK_SIZE_4328 512
55
56/* internal return code */
57#define SUCCESS 0
58#define ERROR 1
59
60/* private bus modes */
61#define SDIOH_MODE_SPI 0
62#define SDIOH_MODE_SD1 1
63#define SDIOH_MODE_SD4 2
64
65#define MAX_SLOTS 6 /* For PCI: Only 6 BAR entries => 6 slots */
66#define SDIOH_REG_WINSZ 0x100 /* Number of registers in Standard Host Controller */
67
68#define SDIOH_TYPE_ARASAN_HDK 1
69#define SDIOH_TYPE_BCM27XX 2
70#define SDIOH_TYPE_TI_PCIXX21 4 /* TI PCIxx21 Standard Host Controller */
71#define SDIOH_TYPE_RICOH_R5C822 5 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter */
72#define SDIOH_TYPE_JMICRON 6 /* JMicron Standard SDIO Host Controller */
73
74/* For linux, allow yielding for dongle */
75#define BCMSDYIELD
76
77/* Expected card status value for CMD7 */
78#define SDIOH_CMD7_EXP_STATUS 0x00001E00
79
80#define RETRIES_LARGE 100000
81#define RETRIES_SMALL 100
82
83
84#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */
85#define USE_MULTIBLOCK 0x4
86
87#define USE_FIFO 0x8 /* Fifo vs non-fifo */
88
89#define CLIENT_INTR 0x100 /* Get rid of this! */
90
91#define HC_INTR_RETUNING 0x1000
92
93
94struct sdioh_info {
95 uint cfg_bar; /* pci cfg address for bar */
96 uint32 caps; /* cached value of capabilities reg */
97 uint32 curr_caps; /* max current capabilities reg */
98
99 osl_t *osh; /* osh handler */
100 volatile char *mem_space; /* pci device memory va */
101 uint lockcount; /* nest count of sdstd_lock() calls */
102 bool client_intr_enabled; /* interrupt connnected flag */
103 bool intr_handler_valid; /* client driver interrupt handler valid */
104 sdioh_cb_fn_t intr_handler; /* registered interrupt handler */
105 void *intr_handler_arg; /* argument to call interrupt handler */
106 bool initialized; /* card initialized */
107 uint target_dev; /* Target device ID */
108 uint16 intmask; /* Current active interrupts */
109 void *sdos_info; /* Pointer to per-OS private data */
110
111 uint32 controller_type; /* Host controller type */
112 uint8 version; /* Host Controller Spec Compliance Version */
113 uint irq; /* Client irq */
114 int intrcount; /* Client interrupts */
115 int local_intrcount; /* Controller interrupts */
116 bool host_init_done; /* Controller initted */
117 bool card_init_done; /* Client SDIO interface initted */
118 bool polled_mode; /* polling for command completion */
119
120 bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */
121 /* Must be on for sd_multiblock to be effective */
122 bool use_client_ints; /* If this is false, make sure to restore */
123 /* polling hack in wl_linux.c:wl_timer() */
124 int adapter_slot; /* Maybe dealing with multiple slots/controllers */
125 int sd_mode; /* SD1/SD4/SPI */
126 int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */
127 uint32 data_xfer_count; /* Current transfer */
128 uint16 card_rca; /* Current Address */
129 int8 sd_dma_mode; /* DMA Mode (PIO, SDMA, ... ADMA2) on CMD53 */
130 uint8 num_funcs; /* Supported funcs on client */
131 uint32 com_cis_ptr;
132 uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
133 void *dma_buf; /* DMA Buffer virtual address */
134 ulong dma_phys; /* DMA Buffer physical address */
135 void *adma2_dscr_buf; /* ADMA2 Descriptor Buffer virtual address */
136 ulong adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */
137
138 /* adjustments needed to make the dma align properly */
139 void *dma_start_buf;
140 ulong dma_start_phys;
141 uint alloced_dma_size;
142 void *adma2_dscr_start_buf;
143 ulong adma2_dscr_start_phys;
144 uint alloced_adma2_dscr_size;
145
146 int r_cnt; /* rx count */
147 int t_cnt; /* tx_count */
148 bool got_hcint; /* local interrupt flag */
149 uint16 last_intrstatus; /* to cache intrstatus */
150 int host_UHSISupported; /* whether UHSI is supported for HC. */
151 int card_UHSI_voltage_Supported; /* whether UHSI is supported for
152 * Card in terms of Voltage [1.8 or 3.3].
153 */
154 int global_UHSI_Supp; /* type of UHSI support in both host and card.
155 * HOST_SDR_UNSUPP: capabilities not supported/matched
156 * HOST_SDR_12_25: SDR12 and SDR25 supported
157 * HOST_SDR_50_104_DDR: one of SDR50/SDR104 or DDR50 supptd
158 */
159 int sd3_dat_state; /* data transfer state used for retuning check */
160 int sd3_tun_state; /* tuning state used for retuning check */
161 bool sd3_tuning_reqd; /* tuning requirement parameter */
162 uint32 caps3; /* cached value of 32 MSbits capabilities reg (SDIO 3.0) */
163};
164
165#define DMA_MODE_NONE 0
166#define DMA_MODE_SDMA 1
167#define DMA_MODE_ADMA1 2
168#define DMA_MODE_ADMA2 3
169#define DMA_MODE_ADMA2_64 4
170#define DMA_MODE_AUTO -1
171
172#define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE))
173
174/* SDIO Host Control Register DMA Mode Definitions */
175#define SDIOH_SDMA_MODE 0
176#define SDIOH_ADMA1_MODE 1
177#define SDIOH_ADMA2_MODE 2
178#define SDIOH_ADMA2_64_MODE 3
179
180#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */
181#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */
182#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */
183#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */
184#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */
185#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */
186#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */
187#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */
188
189/* States for Tuning and corr data */
190#define TUNING_IDLE 0
191#define TUNING_START 1
192#define TUNING_START_AFTER_DAT 2
193#define TUNING_ONGOING 3
194
195#define DATA_TRANSFER_IDLE 0
196#define DATA_TRANSFER_ONGOING 1
197
198/* ADMA2 Descriptor Table Entry for 32-bit Address */
199typedef struct adma2_dscr_32b {
200 uint32 len_attr;
201 uint32 phys_addr;
202} adma2_dscr_32b_t;
203
204/* ADMA1 Descriptor Table Entry */
205typedef struct adma1_dscr {
206 uint32 phys_addr_attr;
207} adma1_dscr_t;
208
209/************************************************************
210 * Internal interfaces: per-port references into bcmsdstd.c
211 */
212
213/* Global message bits */
214extern uint sd_msglevel;
215
216/* OS-independent interrupt handler */
217extern bool check_client_intr(sdioh_info_t *sd);
218
219/* Core interrupt enable/disable of device interrupts */
220extern void sdstd_devintr_on(sdioh_info_t *sd);
221extern void sdstd_devintr_off(sdioh_info_t *sd);
222
223/* Enable/disable interrupts for local controller events */
224extern void sdstd_intrs_on(sdioh_info_t *sd, uint16 norm, uint16 err);
225extern void sdstd_intrs_off(sdioh_info_t *sd, uint16 norm, uint16 err);
226
227/* Wait for specified interrupt and error bits to be set */
228extern void sdstd_spinbits(sdioh_info_t *sd, uint16 norm, uint16 err);
229
230
231/**************************************************************
232 * Internal interfaces: bcmsdstd.c references to per-port code
233 */
234
235/* Register mapping routines */
236extern uint32 *sdstd_reg_map(osl_t *osh, int32 addr, int size);
237extern void sdstd_reg_unmap(osl_t *osh, int32 addr, int size);
238
239/* Interrupt (de)registration routines */
240extern int sdstd_register_irq(sdioh_info_t *sd, uint irq);
241extern void sdstd_free_irq(uint irq, sdioh_info_t *sd);
242
243/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */
244extern void sdstd_lock(sdioh_info_t *sd);
245extern void sdstd_unlock(sdioh_info_t *sd);
246extern void sdstd_waitlockfree(sdioh_info_t *sd);
247
248/* OS-specific wait-for-interrupt-or-status */
249extern int sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield, uint16 *bits);
250
251/* used by bcmsdstd_linux [implemented in sdstd] */
252extern void sdstd_3_enable_retuning_int(sdioh_info_t *sd);
253extern void sdstd_3_disable_retuning_int(sdioh_info_t *sd);
254extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd);
255extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd);
256extern int sdstd_3_get_tune_state(sdioh_info_t *sd);
257extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state);
258extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd);
259extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd);
260extern int sdstd_3_clk_tuning(sdioh_info_t *sd, uint32 sd3ClkMode);
261
262/* used by sdstd [implemented in bcmsdstd_linux/ndis] */
263extern void sdstd_3_start_tuning(sdioh_info_t *sd);
264extern void sdstd_3_osinit_tuning(sdioh_info_t *sd);
265extern void sdstd_3_osclean_tuning(sdioh_info_t *sd);
266
267#endif /* _BCM_SD_STD_H */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmspi.h b/drivers/net/wireless/bcmdhd/include/bcmspi.h
new file mode 100644
index 00000000000..0eb2a30c9a8
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmspi.h
@@ -0,0 +1,40 @@
1/*
2 * Broadcom SPI Low-Level Hardware Driver API
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmspi.h,v 13.5.112.1 2010-11-15 18:13:09 Exp $
25 */
26#ifndef _BCM_SPI_H
27#define _BCM_SPI_H
28
29extern void spi_devintr_off(sdioh_info_t *sd);
30extern void spi_devintr_on(sdioh_info_t *sd);
31extern bool spi_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor);
32extern bool spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode);
33extern bool spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr);
34extern bool spi_hw_attach(sdioh_info_t *sd);
35extern bool spi_hw_detach(sdioh_info_t *sd);
36extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen);
37extern void spi_spinbits(sdioh_info_t *sd);
38extern void spi_waitbits(sdioh_info_t *sd, bool yield);
39
40#endif /* _BCM_SPI_H */
diff --git a/drivers/net/wireless/bcmdhd/include/bcmutils.h b/drivers/net/wireless/bcmdhd/include/bcmutils.h
new file mode 100644
index 00000000000..530036f0ba7
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmutils.h
@@ -0,0 +1,708 @@
1/*
2 * Misc useful os-independent macros and functions.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmutils.h,v 13.236.2.16 2011-01-26 00:45:06 Exp $
25 */
26
27
28#ifndef _bcmutils_h_
29#define _bcmutils_h_
30
31#define bcm_strcpy_s(dst, noOfElements, src) strcpy((dst), (src))
32#define bcm_strncpy_s(dst, noOfElements, src, count) strncpy((dst), (src), (count))
33#define bcm_strcat_s(dst, noOfElements, src) strcat((dst), (src))
34
35#ifdef __cplusplus
36extern "C" {
37#endif
38
39
40#define _BCM_U 0x01
41#define _BCM_L 0x02
42#define _BCM_D 0x04
43#define _BCM_C 0x08
44#define _BCM_P 0x10
45#define _BCM_S 0x20
46#define _BCM_X 0x40
47#define _BCM_SP 0x80
48
49extern const unsigned char bcm_ctype[];
50#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)])
51
52#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0)
53#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0)
54#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0)
55#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0)
56#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0)
57#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0)
58#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0)
59#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0)
60#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0)
61#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0)
62#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0)
63#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
64#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c))
65
66
67
68struct bcmstrbuf {
69 char *buf;
70 unsigned int size;
71 char *origbuf;
72 unsigned int origsize;
73};
74
75
76#ifdef BCMDRIVER
77#include <osl.h>
78
79#define GPIO_PIN_NOTDEFINED 0x20
80
81
82#define SPINWAIT(exp, us) { \
83 uint countdown = (us) + 9; \
84 while ((exp) && (countdown >= 10)) {\
85 OSL_DELAY(10); \
86 countdown -= 10; \
87 } \
88}
89
90
91#ifndef PKTQ_LEN_DEFAULT
92#define PKTQ_LEN_DEFAULT 128
93#endif
94#ifndef PKTQ_MAX_PREC
95#define PKTQ_MAX_PREC 16
96#endif
97
98typedef struct pktq_prec {
99 void *head;
100 void *tail;
101 uint16 len;
102 uint16 max;
103} pktq_prec_t;
104
105
106
107struct pktq {
108 uint16 num_prec;
109 uint16 hi_prec;
110 uint16 max;
111 uint16 len;
112
113 struct pktq_prec q[PKTQ_MAX_PREC];
114};
115
116
117struct spktq {
118 uint16 num_prec;
119 uint16 hi_prec;
120 uint16 max;
121 uint16 len;
122
123 struct pktq_prec q[1];
124};
125
126#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--)
127
128
129typedef bool (*ifpkt_cb_t)(void*, int);
130
131#ifdef BCMPKTPOOL
132#define POOL_ENAB(pool) ((pool) && (pool)->inited)
133#if defined(BCM4329C0)
134#define SHARED_POOL (pktpool_shared_ptr)
135#else
136#define SHARED_POOL (pktpool_shared)
137#endif
138#else
139#define POOL_ENAB(bus) 0
140#define SHARED_POOL ((struct pktpool *)NULL)
141#endif
142
143#ifndef PKTPOOL_LEN_MAX
144#define PKTPOOL_LEN_MAX 40
145#endif
146#define PKTPOOL_CB_MAX 3
147
148struct pktpool;
149typedef void (*pktpool_cb_t)(struct pktpool *pool, void *arg);
150typedef struct {
151 pktpool_cb_t cb;
152 void *arg;
153} pktpool_cbinfo_t;
154
155#ifdef BCMDBG_POOL
156
157#define POOL_IDLE 0
158#define POOL_RXFILL 1
159#define POOL_RXDH 2
160#define POOL_RXD11 3
161#define POOL_TXDH 4
162#define POOL_TXD11 5
163#define POOL_AMPDU 6
164#define POOL_TXENQ 7
165
166typedef struct {
167 void *p;
168 uint32 cycles;
169 uint32 dur;
170} pktpool_dbg_t;
171
172typedef struct {
173 uint8 txdh;
174 uint8 txd11;
175 uint8 enq;
176 uint8 rxdh;
177 uint8 rxd11;
178 uint8 rxfill;
179 uint8 idle;
180} pktpool_stats_t;
181#endif
182
183typedef struct pktpool {
184 bool inited;
185 uint16 r;
186 uint16 w;
187 uint16 len;
188 uint16 maxlen;
189 uint16 plen;
190 bool istx;
191 bool empty;
192 uint8 cbtoggle;
193 uint8 cbcnt;
194 uint8 ecbcnt;
195 bool emptycb_disable;
196 pktpool_cbinfo_t cbs[PKTPOOL_CB_MAX];
197 pktpool_cbinfo_t ecbs[PKTPOOL_CB_MAX];
198 void *q[PKTPOOL_LEN_MAX + 1];
199
200#ifdef BCMDBG_POOL
201 uint8 dbg_cbcnt;
202 pktpool_cbinfo_t dbg_cbs[PKTPOOL_CB_MAX];
203 uint16 dbg_qlen;
204 pktpool_dbg_t dbg_q[PKTPOOL_LEN_MAX + 1];
205#endif
206} pktpool_t;
207
208#if defined(BCM4329C0)
209extern pktpool_t *pktpool_shared_ptr;
210#else
211extern pktpool_t *pktpool_shared;
212#endif
213
214extern int pktpool_init(osl_t *osh, pktpool_t *pktp, int *pktplen, int plen, bool istx);
215extern int pktpool_deinit(osl_t *osh, pktpool_t *pktp);
216extern int pktpool_fill(osl_t *osh, pktpool_t *pktp, bool minimal);
217extern void* pktpool_get(pktpool_t *pktp);
218extern void pktpool_free(pktpool_t *pktp, void *p);
219extern int pktpool_add(pktpool_t *pktp, void *p);
220extern uint16 pktpool_avail(pktpool_t *pktp);
221extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg);
222extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg);
223extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen);
224extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable);
225
226#define POOLPTR(pp) ((pktpool_t *)(pp))
227#define pktpool_len(pp) (POOLPTR(pp)->len - 1)
228#define pktpool_plen(pp) (POOLPTR(pp)->plen)
229#define pktpool_maxlen(pp) (POOLPTR(pp)->maxlen)
230
231#ifdef BCMDBG_POOL
232extern int pktpool_dbg_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg);
233extern int pktpool_start_trigger(pktpool_t *pktp, void *p);
234extern int pktpool_dbg_dump(pktpool_t *pktp);
235extern int pktpool_dbg_notify(pktpool_t *pktp);
236extern int pktpool_stats_dump(pktpool_t *pktp, pktpool_stats_t *stats);
237#endif
238
239
240
241struct ether_addr;
242
243extern int ether_isbcast(const void *ea);
244extern int ether_isnulladdr(const void *ea);
245
246
247
248#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max))
249#define pktq_plen(pq, prec) ((pq)->q[prec].len)
250#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len)
251#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max)
252#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0)
253
254#define pktq_ppeek(pq, prec) ((pq)->q[prec].head)
255#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail)
256
257extern void *pktq_penq(struct pktq *pq, int prec, void *p);
258extern void *pktq_penq_head(struct pktq *pq, int prec, void *p);
259extern void *pktq_pdeq(struct pktq *pq, int prec);
260extern void *pktq_pdeq_tail(struct pktq *pq, int prec);
261
262extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir,
263 ifpkt_cb_t fn, int arg);
264
265extern bool pktq_pdel(struct pktq *pq, void *p, int prec);
266
267
268
269extern int pktq_mlen(struct pktq *pq, uint prec_bmp);
270extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out);
271
272
273
274#define pktq_len(pq) ((int)(pq)->len)
275#define pktq_max(pq) ((int)(pq)->max)
276#define pktq_avail(pq) ((int)((pq)->max - (pq)->len))
277#define pktq_full(pq) ((pq)->len >= (pq)->max)
278#define pktq_empty(pq) ((pq)->len == 0)
279
280
281#define pktenq(pq, p) pktq_penq(((struct pktq *)pq), 0, (p))
282#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)pq), 0, (p))
283#define pktdeq(pq) pktq_pdeq(((struct pktq *)pq), 0)
284#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)pq), 0)
285#define pktqinit(pq, len) pktq_init(((struct pktq *)pq), 1, len)
286
287extern void pktq_init(struct pktq *pq, int num_prec, int max_len);
288
289extern void *pktq_deq(struct pktq *pq, int *prec_out);
290extern void *pktq_deq_tail(struct pktq *pq, int *prec_out);
291extern void *pktq_peek(struct pktq *pq, int *prec_out);
292extern void *pktq_peek_tail(struct pktq *pq, int *prec_out);
293extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir, ifpkt_cb_t fn, int arg);
294
295
296
297extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf);
298extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf);
299extern uint pkttotlen(osl_t *osh, void *p);
300extern void *pktlast(osl_t *osh, void *p);
301extern uint pktsegcnt(osl_t *osh, void *p);
302
303
304extern uint pktsetprio(void *pkt, bool update_vtag);
305#define PKTPRIO_VDSCP 0x100
306#define PKTPRIO_VLAN 0x200
307#define PKTPRIO_UPD 0x400
308#define PKTPRIO_DSCP 0x800
309
310
311extern int bcm_atoi(char *s);
312extern ulong bcm_strtoul(char *cp, char **endp, uint base);
313extern char *bcmstrstr(char *haystack, char *needle);
314extern char *bcmstrcat(char *dest, const char *src);
315extern char *bcmstrncat(char *dest, const char *src, uint size);
316extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen);
317char* bcmstrtok(char **string, const char *delimiters, char *tokdelim);
318int bcmstricmp(const char *s1, const char *s2);
319int bcmstrnicmp(const char* s1, const char* s2, int cnt);
320
321
322
323extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf);
324extern int bcm_ether_atoe(char *p, struct ether_addr *ea);
325
326
327struct ipv4_addr;
328extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf);
329
330
331extern void bcm_mdelay(uint ms);
332
333extern char *getvar(char *vars, const char *name);
334extern int getintvar(char *vars, const char *name);
335extern int getintvararray(char *vars, const char *name, int index);
336extern int getintvararraysize(char *vars, const char *name);
337extern uint getgpiopin(char *vars, char *pin_name, uint def_pin);
338#define bcm_perf_enable()
339#define bcmstats(fmt)
340#define bcmlog(fmt, a1, a2)
341#define bcmdumplog(buf, size) *buf = '\0'
342#define bcmdumplogent(buf, idx) -1
343
344#define bcmtslog(tstamp, fmt, a1, a2)
345#define bcmprinttslogs()
346#define bcmprinttstamp(us)
347
348extern char *bcm_nvram_vars(uint *length);
349extern int bcm_nvram_cache(void *sih);
350
351
352
353
354typedef struct bcm_iovar {
355 const char *name;
356 uint16 varid;
357 uint16 flags;
358 uint16 type;
359 uint16 minlen;
360} bcm_iovar_t;
361
362
363
364
365#define IOV_GET 0
366#define IOV_SET 1
367
368
369#define IOV_GVAL(id) ((id)*2)
370#define IOV_SVAL(id) (((id)*2)+IOV_SET)
371#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET)
372#define IOV_ID(actionid) (actionid >> 1)
373
374
375
376extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name);
377extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set);
378#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
379 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
380extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len);
381#endif
382#endif
383
384
385#define IOVT_VOID 0
386#define IOVT_BOOL 1
387#define IOVT_INT8 2
388#define IOVT_UINT8 3
389#define IOVT_INT16 4
390#define IOVT_UINT16 5
391#define IOVT_INT32 6
392#define IOVT_UINT32 7
393#define IOVT_BUFFER 8
394#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER)
395
396
397#define BCM_IOV_TYPE_INIT { \
398 "void", \
399 "bool", \
400 "int8", \
401 "uint8", \
402 "int16", \
403 "uint16", \
404 "int32", \
405 "uint32", \
406 "buffer", \
407 "" }
408
409#define BCM_IOVT_IS_INT(type) (\
410 (type == IOVT_BOOL) || \
411 (type == IOVT_INT8) || \
412 (type == IOVT_UINT8) || \
413 (type == IOVT_INT16) || \
414 (type == IOVT_UINT16) || \
415 (type == IOVT_INT32) || \
416 (type == IOVT_UINT32))
417
418
419
420#define BCME_STRLEN 64
421#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST))
422
423
424
425
426#define BCME_OK 0
427#define BCME_ERROR -1
428#define BCME_BADARG -2
429#define BCME_BADOPTION -3
430#define BCME_NOTUP -4
431#define BCME_NOTDOWN -5
432#define BCME_NOTAP -6
433#define BCME_NOTSTA -7
434#define BCME_BADKEYIDX -8
435#define BCME_RADIOOFF -9
436#define BCME_NOTBANDLOCKED -10
437#define BCME_NOCLK -11
438#define BCME_BADRATESET -12
439#define BCME_BADBAND -13
440#define BCME_BUFTOOSHORT -14
441#define BCME_BUFTOOLONG -15
442#define BCME_BUSY -16
443#define BCME_NOTASSOCIATED -17
444#define BCME_BADSSIDLEN -18
445#define BCME_OUTOFRANGECHAN -19
446#define BCME_BADCHAN -20
447#define BCME_BADADDR -21
448#define BCME_NORESOURCE -22
449#define BCME_UNSUPPORTED -23
450#define BCME_BADLEN -24
451#define BCME_NOTREADY -25
452#define BCME_EPERM -26
453#define BCME_NOMEM -27
454#define BCME_ASSOCIATED -28
455#define BCME_RANGE -29
456#define BCME_NOTFOUND -30
457#define BCME_WME_NOT_ENABLED -31
458#define BCME_TSPEC_NOTFOUND -32
459#define BCME_ACM_NOTSUPPORTED -33
460#define BCME_NOT_WME_ASSOCIATION -34
461#define BCME_SDIO_ERROR -35
462#define BCME_DONGLE_DOWN -36
463#define BCME_VERSION -37
464#define BCME_TXFAIL -38
465#define BCME_RXFAIL -39
466#define BCME_NODEVICE -40
467#define BCME_NMODE_DISABLED -41
468#define BCME_NONRESIDENT -42
469#define BCME_LAST BCME_NONRESIDENT
470
471
472#define BCMERRSTRINGTABLE { \
473 "OK", \
474 "Undefined error", \
475 "Bad Argument", \
476 "Bad Option", \
477 "Not up", \
478 "Not down", \
479 "Not AP", \
480 "Not STA", \
481 "Bad Key Index", \
482 "Radio Off", \
483 "Not band locked", \
484 "No clock", \
485 "Bad Rate valueset", \
486 "Bad Band", \
487 "Buffer too short", \
488 "Buffer too long", \
489 "Busy", \
490 "Not Associated", \
491 "Bad SSID len", \
492 "Out of Range Channel", \
493 "Bad Channel", \
494 "Bad Address", \
495 "Not Enough Resources", \
496 "Unsupported", \
497 "Bad length", \
498 "Not Ready", \
499 "Not Permitted", \
500 "No Memory", \
501 "Associated", \
502 "Not In Range", \
503 "Not Found", \
504 "WME Not Enabled", \
505 "TSPEC Not Found", \
506 "ACM Not Supported", \
507 "Not WME Association", \
508 "SDIO Bus Error", \
509 "Dongle Not Accessible", \
510 "Incorrect version", \
511 "TX Failure", \
512 "RX Failure", \
513 "Device Not Present", \
514 "NMODE Disabled", \
515 "Nonresident overlay access", \
516}
517
518#ifndef ABS
519#define ABS(a) (((a) < 0)?-(a):(a))
520#endif
521
522#ifndef MIN
523#define MIN(a, b) (((a) < (b))?(a):(b))
524#endif
525
526#ifndef MAX
527#define MAX(a, b) (((a) > (b))?(a):(b))
528#endif
529
530#define CEIL(x, y) (((x) + ((y)-1)) / (y))
531#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
532#define ISALIGNED(a, x) (((uintptr)(a) & ((x)-1)) == 0)
533#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \
534 & ~((boundary) - 1))
535#define ISPOWEROF2(x) ((((x)-1)&(x)) == 0)
536#define VALID_MASK(mask) !((mask) & ((mask) + 1))
537#ifndef OFFSETOF
538#define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member)
539#endif
540#ifndef ARRAYSIZE
541#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
542#endif
543
544
545extern void *_bcmutils_dummy_fn;
546#define REFERENCE_FUNCTION(f) (_bcmutils_dummy_fn = (void *)(f))
547
548
549#ifndef setbit
550#ifndef NBBY
551#define NBBY 8
552#endif
553#define setbit(a, i) (((uint8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY))
554#define clrbit(a, i) (((uint8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
555#define isset(a, i) (((const uint8 *)a)[(i)/NBBY] & (1<<((i)%NBBY)))
556#define isclr(a, i) ((((const uint8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
557#endif
558
559#define NBITS(type) (sizeof(type) * 8)
560#define NBITVAL(nbits) (1 << (nbits))
561#define MAXBITVAL(nbits) ((1 << (nbits)) - 1)
562#define NBITMASK(nbits) MAXBITVAL(nbits)
563#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8)
564
565
566#define MUX(pred, true, false) ((pred) ? (true) : (false))
567
568
569#define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1)
570#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
571
572
573#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1))
574#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1))
575
576
577#define MODADD(x, y, bound) \
578 MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y))
579#define MODSUB(x, y, bound) \
580 MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y))
581
582
583#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1))
584#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1))
585
586
587#define CRC8_INIT_VALUE 0xff
588#define CRC8_GOOD_VALUE 0x9f
589#define CRC16_INIT_VALUE 0xffff
590#define CRC16_GOOD_VALUE 0xf0b8
591#define CRC32_INIT_VALUE 0xffffffff
592#define CRC32_GOOD_VALUE 0xdebb20e3
593
594
595typedef struct bcm_bit_desc {
596 uint32 bit;
597 const char* name;
598} bcm_bit_desc_t;
599
600
601typedef struct bcm_tlv {
602 uint8 id;
603 uint8 len;
604 uint8 data[1];
605} bcm_tlv_t;
606
607
608#define bcm_valid_tlv(elt, buflen) ((buflen) >= 2 && (int)(buflen) >= (int)(2 + (elt)->len))
609
610
611#define ETHER_ADDR_STR_LEN 18
612
613
614
615static INLINE void
616xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst)
617{
618 if (
619#ifdef __i386__
620 1 ||
621#endif
622 (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) {
623
624
625 ((uint32 *)dst)[0] = ((const uint32 *)src1)[0] ^ ((const uint32 *)src2)[0];
626 ((uint32 *)dst)[1] = ((const uint32 *)src1)[1] ^ ((const uint32 *)src2)[1];
627 ((uint32 *)dst)[2] = ((const uint32 *)src1)[2] ^ ((const uint32 *)src2)[2];
628 ((uint32 *)dst)[3] = ((const uint32 *)src1)[3] ^ ((const uint32 *)src2)[3];
629 } else {
630
631 int k;
632 for (k = 0; k < 16; k++)
633 dst[k] = src1[k] ^ src2[k];
634 }
635}
636
637
638
639extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc);
640extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc);
641extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc);
642
643#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \
644 defined(WLMSG_ASSOC)
645extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len);
646#endif
647
648#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \
649 defined(WLMSG_ASSOC) || defined(WLMEDIA_PEAKRATE)
650extern int bcm_format_hex(char *str, const void *bytes, int len);
651#endif
652
653extern const char *bcm_crypto_algo_name(uint algo);
654extern char *bcm_chipname(uint chipid, char *buf, uint len);
655extern char *bcm_brev_str(uint32 brev, char *buf);
656extern void printbig(char *buf);
657extern void prhex(const char *msg, uchar *buf, uint len);
658
659
660extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen);
661extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key);
662extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key);
663
664
665extern const char *bcmerrorstr(int bcmerror);
666
667
668typedef uint32 mbool;
669#define mboolset(mb, bit) ((mb) |= (bit))
670#define mboolclr(mb, bit) ((mb) &= ~(bit))
671#define mboolisset(mb, bit) (((mb) & (bit)) != 0)
672#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val)))
673
674
675extern uint16 bcm_qdbm_to_mw(uint8 qdbm);
676extern uint8 bcm_mw_to_qdbm(uint16 mw);
677
678
679struct fielddesc {
680 const char *nameandfmt;
681 uint32 offset;
682 uint32 len;
683};
684
685extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size);
686extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...);
687extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount);
688extern int bcm_cmp_bytes(uchar *arg1, uchar *arg2, uint8 nbytes);
689extern void bcm_print_bytes(char *name, const uchar *cdata, int len);
690
691typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset);
692extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str,
693 char *buf, uint32 bufsize);
694
695extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len);
696extern uint bcm_bitcount(uint8 *bitmap, uint bytelength);
697
698
699
700#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
701
702unsigned int process_nvram_vars(char *varbuf, unsigned int len);
703
704#ifdef __cplusplus
705 }
706#endif
707
708#endif
diff --git a/drivers/net/wireless/bcmdhd/include/bcmwifi.h b/drivers/net/wireless/bcmdhd/include/bcmwifi.h
new file mode 100644
index 00000000000..45f3c0312dc
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/bcmwifi.h
@@ -0,0 +1,165 @@
1/*
2 * Misc utility routines for WL and Apps
3 * This header file housing the define and function prototype use by
4 * both the wl driver, tools & Apps.
5 *
6 * Copyright (C) 1999-2011, Broadcom Corporation
7 *
8 * Unless you and Broadcom execute a separate written software license
9 * agreement governing use of this software, this software is licensed to you
10 * under the terms of the GNU General Public License version 2 (the "GPL"),
11 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
12 * following added to such license:
13 *
14 * As a special exception, the copyright holders of this software give you
15 * permission to link this software with independent modules, and to copy and
16 * distribute the resulting executable under terms of your choice, provided that
17 * you also meet, for each linked independent module, the terms and conditions of
18 * the license of that module. An independent module is a module which is not
19 * derived from this software. The special exception does not apply to any
20 * modifications of the software.
21 *
22 * Notwithstanding the above, under no circumstances may you combine this
23 * software in any way with any other Broadcom software provided under a license
24 * other than the GPL, without Broadcom's express prior written consent.
25 *
26 * $Id: bcmwifi.h,v 1.29.6.3 2010-08-03 17:47:04 Exp $
27 */
28
29
30#ifndef _bcmwifi_h_
31#define _bcmwifi_h_
32
33
34
35typedef uint16 chanspec_t;
36
37
38#define CH_UPPER_SB 0x01
39#define CH_LOWER_SB 0x02
40#define CH_EWA_VALID 0x04
41#define CH_20MHZ_APART 4
42#define CH_10MHZ_APART 2
43#define CH_5MHZ_APART 1
44#define CH_MAX_2G_CHANNEL 14
45#define WLC_MAX_2G_CHANNEL CH_MAX_2G_CHANNEL
46#define MAXCHANNEL 224
47
48#define WL_CHANSPEC_CHAN_MASK 0x00ff
49#define WL_CHANSPEC_CHAN_SHIFT 0
50
51#define WL_CHANSPEC_CTL_SB_MASK 0x0300
52#define WL_CHANSPEC_CTL_SB_SHIFT 8
53#define WL_CHANSPEC_CTL_SB_LOWER 0x0100
54#define WL_CHANSPEC_CTL_SB_UPPER 0x0200
55#define WL_CHANSPEC_CTL_SB_NONE 0x0300
56
57#define WL_CHANSPEC_BW_MASK 0x0C00
58#define WL_CHANSPEC_BW_SHIFT 10
59#define WL_CHANSPEC_BW_10 0x0400
60#define WL_CHANSPEC_BW_20 0x0800
61#define WL_CHANSPEC_BW_40 0x0C00
62
63#define WL_CHANSPEC_BAND_MASK 0xf000
64#define WL_CHANSPEC_BAND_SHIFT 12
65#define WL_CHANSPEC_BAND_5G 0x1000
66#define WL_CHANSPEC_BAND_2G 0x2000
67#define INVCHANSPEC 255
68
69
70#define WF_CHAN_FACTOR_2_4_G 4814
71#define WF_CHAN_FACTOR_5_G 10000
72#define WF_CHAN_FACTOR_4_G 8000
73
74
75#define LOWER_20_SB(channel) (((channel) > CH_10MHZ_APART) ? ((channel) - CH_10MHZ_APART) : 0)
76#define UPPER_20_SB(channel) (((channel) < (MAXCHANNEL - CH_10MHZ_APART)) ? \
77 ((channel) + CH_10MHZ_APART) : 0)
78#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX)
79#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \
80 WL_CHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \
81 WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
82#define NEXT_20MHZ_CHAN(channel) (((channel) < (MAXCHANNEL - CH_20MHZ_APART)) ? \
83 ((channel) + CH_20MHZ_APART) : 0)
84#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \
85 ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \
86 ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \
87 WL_CHANSPEC_BAND_5G))
88#define CHSPEC_CHANNEL(chspec) ((uint8)((chspec) & WL_CHANSPEC_CHAN_MASK))
89#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK)
90
91
92#define CHSPEC_CTL_SB(chspec) (chspec & WL_CHANSPEC_CTL_SB_MASK)
93#define CHSPEC_BW(chspec) (chspec & WL_CHANSPEC_BW_MASK)
94
95#ifdef WL11N_20MHZONLY
96
97#define CHSPEC_IS10(chspec) 0
98#define CHSPEC_IS20(chspec) 1
99#ifndef CHSPEC_IS40
100#define CHSPEC_IS40(chspec) 0
101#endif
102
103#else
104
105#define CHSPEC_IS10(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10)
106#define CHSPEC_IS20(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
107#ifndef CHSPEC_IS40
108#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
109#endif
110
111#endif
112
113#define CHSPEC_IS20_UNCOND(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
114
115#define CHSPEC_IS5G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
116#define CHSPEC_IS2G(chspec) (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G)
117#define CHSPEC_SB_NONE(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE)
118#define CHSPEC_SB_UPPER(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER)
119#define CHSPEC_SB_LOWER(chspec) (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER)
120#define CHSPEC_CTL_CHAN(chspec) ((CHSPEC_SB_LOWER(chspec)) ? \
121 (LOWER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \
122 (UPPER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))))
123#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G(chspec) ? WLC_BAND_5G : WLC_BAND_2G)
124
125#define CHANSPEC_STR_LEN 8
126
127
128#define WLC_MAXRATE 108
129#define WLC_RATE_1M 2
130#define WLC_RATE_2M 4
131#define WLC_RATE_5M5 11
132#define WLC_RATE_11M 22
133#define WLC_RATE_6M 12
134#define WLC_RATE_9M 18
135#define WLC_RATE_12M 24
136#define WLC_RATE_18M 36
137#define WLC_RATE_24M 48
138#define WLC_RATE_36M 72
139#define WLC_RATE_48M 96
140#define WLC_RATE_54M 108
141
142#define WLC_2G_25MHZ_OFFSET 5
143
144
145extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf);
146
147
148extern chanspec_t wf_chspec_aton(char *a);
149
150
151extern bool wf_chspec_malformed(chanspec_t chanspec);
152
153
154extern uint8 wf_chspec_ctlchan(chanspec_t chspec);
155
156
157extern chanspec_t wf_chspec_ctlchspec(chanspec_t chspec);
158
159
160extern int wf_mhz2channel(uint freq, uint start_factor);
161
162
163extern int wf_channel2mhz(uint channel, uint start_factor);
164
165#endif
diff --git a/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/bcmdhd/include/dhdioctl.h
new file mode 100644
index 00000000000..9661dac2603
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/dhdioctl.h
@@ -0,0 +1,129 @@
1/*
2 * Definitions for ioctls to access DHD iovars.
3 * Based on wlioctl.h (for Broadcom 802.11abg driver).
4 * (Moves towards generic ioctls for BCM drivers/iovars.)
5 *
6 * Definitions subject to change without notice.
7 *
8 * Copyright (C) 1999-2011, Broadcom Corporation
9 *
10 * Unless you and Broadcom execute a separate written software license
11 * agreement governing use of this software, this software is licensed to you
12 * under the terms of the GNU General Public License version 2 (the "GPL"),
13 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
14 * following added to such license:
15 *
16 * As a special exception, the copyright holders of this software give you
17 * permission to link this software with independent modules, and to copy and
18 * distribute the resulting executable under terms of your choice, provided that
19 * you also meet, for each linked independent module, the terms and conditions of
20 * the license of that module. An independent module is a module which is not
21 * derived from this software. The special exception does not apply to any
22 * modifications of the software.
23 *
24 * Notwithstanding the above, under no circumstances may you combine this
25 * software in any way with any other Broadcom software provided under a license
26 * other than the GPL, without Broadcom's express prior written consent.
27 *
28 * $Id: dhdioctl.h,v 13.11.10.1 2010-12-22 23:47:26 Exp $
29 */
30
31#ifndef _dhdioctl_h_
32#define _dhdioctl_h_
33
34#include <typedefs.h>
35
36
37/* require default structure packing */
38#define BWL_DEFAULT_PACKING
39#include <packed_section_start.h>
40
41
42/* Linux network driver ioctl encoding */
43typedef struct dhd_ioctl {
44 uint cmd; /* common ioctl definition */
45 void *buf; /* pointer to user buffer */
46 uint len; /* length of user buffer */
47 bool set; /* get or set request (optional) */
48 uint used; /* bytes read or written (optional) */
49 uint needed; /* bytes needed (optional) */
50 uint driver; /* to identify target driver */
51} dhd_ioctl_t;
52
53/* Underlying BUS definition */
54enum {
55 BUS_TYPE_USB = 0, /* for USB dongles */
56 BUS_TYPE_SDIO /* for SDIO dongles */
57};
58
59/* per-driver magic numbers */
60#define DHD_IOCTL_MAGIC 0x00444944
61
62/* bump this number if you change the ioctl interface */
63#define DHD_IOCTL_VERSION 1
64
65#define DHD_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */
66#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */
67
68/* common ioctl definitions */
69#define DHD_GET_MAGIC 0
70#define DHD_GET_VERSION 1
71#define DHD_GET_VAR 2
72#define DHD_SET_VAR 3
73
74/* message levels */
75#define DHD_ERROR_VAL 0x0001
76#define DHD_TRACE_VAL 0x0002
77#define DHD_INFO_VAL 0x0004
78#define DHD_DATA_VAL 0x0008
79#define DHD_CTL_VAL 0x0010
80#define DHD_TIMER_VAL 0x0020
81#define DHD_HDRS_VAL 0x0040
82#define DHD_BYTES_VAL 0x0080
83#define DHD_INTR_VAL 0x0100
84#define DHD_LOG_VAL 0x0200
85#define DHD_GLOM_VAL 0x0400
86#define DHD_EVENT_VAL 0x0800
87#define DHD_BTA_VAL 0x1000
88#define DHD_ISCAN_VAL 0x2000
89#define DHD_ARPOE_VAL 0x4000
90
91#ifdef SDTEST
92/* For pktgen iovar */
93typedef struct dhd_pktgen {
94 uint version; /* To allow structure change tracking */
95 uint freq; /* Max ticks between tx/rx attempts */
96 uint count; /* Test packets to send/rcv each attempt */
97 uint print; /* Print counts every <print> attempts */
98 uint total; /* Total packets (or bursts) */
99 uint minlen; /* Minimum length of packets to send */
100 uint maxlen; /* Maximum length of packets to send */
101 uint numsent; /* Count of test packets sent */
102 uint numrcvd; /* Count of test packets received */
103 uint numfail; /* Count of test send failures */
104 uint mode; /* Test mode (type of test packets) */
105 uint stop; /* Stop after this many tx failures */
106} dhd_pktgen_t;
107
108/* Version in case structure changes */
109#define DHD_PKTGEN_VERSION 2
110
111/* Type of test packets to use */
112#define DHD_PKTGEN_ECHO 1 /* Send echo requests */
113#define DHD_PKTGEN_SEND 2 /* Send discard packets */
114#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */
115#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */
116#endif /* SDTEST */
117
118/* Enter idle immediately (no timeout) */
119#define DHD_IDLE_IMMEDIATE (-1)
120
121/* Values for idleclock iovar: other values are the sd_divisor to use when idle */
122#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */
123#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */
124
125
126/* require default structure packing */
127#include <packed_section_end.h>
128
129#endif /* _dhdioctl_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h
new file mode 100644
index 00000000000..ae1f975bdb6
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/epivers.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 1999-2011, Broadcom Corporation
3 *
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2 (the "GPL"),
7 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
8 * following added to such license:
9 *
10 * As a special exception, the copyright holders of this software give you
11 * permission to link this software with independent modules, and to copy and
12 * distribute the resulting executable under terms of your choice, provided that
13 * you also meet, for each linked independent module, the terms and conditions of
14 * the license of that module. An independent module is a module which is not
15 * derived from this software. The special exception does not apply to any
16 * modifications of the software.
17 *
18 * Notwithstanding the above, under no circumstances may you combine this
19 * software in any way with any other Broadcom software provided under a license
20 * other than the GPL, without Broadcom's express prior written consent.
21 *
22 * $Id: epivers.h.in,v 13.32.4.1 2010-09-17 00:39:18 $
23 *
24*/
25
26
27#ifndef _epivers_h_
28#define _epivers_h_
29
30#define EPI_MAJOR_VERSION 5
31
32#define EPI_MINOR_VERSION 90
33
34#define EPI_RC_NUMBER 125
35
36#define EPI_INCREMENTAL_NUMBER 94
37
38#define EPI_BUILD_NUMBER 0
39
40#define EPI_VERSION 5, 90, 125, 94
41
42#define EPI_VERSION_NUM 0x055a7d5e
43
44#define EPI_VERSION_DEV 5.90.125
45
46
47#define EPI_VERSION_STR "5.90.125.94"
48
49#endif
diff --git a/drivers/net/wireless/bcmdhd/include/hndpmu.h b/drivers/net/wireless/bcmdhd/include/hndpmu.h
new file mode 100644
index 00000000000..51c51b9734a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/hndpmu.h
@@ -0,0 +1,34 @@
1/*
2 * HND SiliconBackplane PMU support.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: hndpmu.h,v 13.35.8.5 2011-02-11 00:56:32 Exp $
25 */
26
27#ifndef _hndpmu_h_
28#define _hndpmu_h_
29
30
31extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on);
32extern void si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength);
33
34#endif /* _hndpmu_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h
new file mode 100644
index 00000000000..8b9615c35f3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h
@@ -0,0 +1,88 @@
1/*
2 * HNDRTE arm trap handling.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: hndrte_armtrap.h,v 13.4.14.1 2011-02-05 00:04:30 Exp $
25 */
26
27#ifndef _hndrte_armtrap_h
28#define _hndrte_armtrap_h
29
30
31/* ARM trap handling */
32
33/* Trap types defined by ARM (see arminc.h) */
34
35/* Trap locations in lo memory */
36#define TRAP_STRIDE 4
37#define FIRST_TRAP TR_RST
38#define LAST_TRAP (TR_FIQ * TRAP_STRIDE)
39
40#if defined(__ARM_ARCH_4T__)
41#define MAX_TRAP_TYPE (TR_FIQ + 1)
42#elif defined(__ARM_ARCH_7M__)
43#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS)
44#endif /* __ARM_ARCH_7M__ */
45
46/* The trap structure is defined here as offsets for assembly */
47#define TR_TYPE 0x00
48#define TR_EPC 0x04
49#define TR_CPSR 0x08
50#define TR_SPSR 0x0c
51#define TR_REGS 0x10
52#define TR_REG(n) (TR_REGS + (n) * 4)
53#define TR_SP TR_REG(13)
54#define TR_LR TR_REG(14)
55#define TR_PC TR_REG(15)
56
57#define TRAP_T_SIZE 80
58
59#ifndef _LANGUAGE_ASSEMBLY
60
61#include <typedefs.h>
62
63typedef struct _trap_struct {
64 uint32 type;
65 uint32 epc;
66 uint32 cpsr;
67 uint32 spsr;
68 uint32 r0;
69 uint32 r1;
70 uint32 r2;
71 uint32 r3;
72 uint32 r4;
73 uint32 r5;
74 uint32 r6;
75 uint32 r7;
76 uint32 r8;
77 uint32 r9;
78 uint32 r10;
79 uint32 r11;
80 uint32 r12;
81 uint32 r13;
82 uint32 r14;
83 uint32 pc;
84} trap_t;
85
86#endif /* !_LANGUAGE_ASSEMBLY */
87
88#endif /* _hndrte_armtrap_h */
diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h
new file mode 100644
index 00000000000..b9ede53af70
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h
@@ -0,0 +1,68 @@
1/*
2 * Console support for hndrte.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: hndrte_cons.h,v 13.4.10.4 2011-02-05 00:08:20 Exp $
25 */
26
27#ifndef _HNDRTE_CONS_H
28#define _HNDRTE_CONS_H
29
30#include <typedefs.h>
31
32#define CBUF_LEN (128)
33
34#define LOG_BUF_LEN 1024
35
36typedef struct {
37 uint32 buf; /* Can't be pointer on (64-bit) hosts */
38 uint buf_size;
39 uint idx;
40 char *_buf_compat; /* redundant pointer for backward compat. */
41} hndrte_log_t;
42
43typedef struct {
44 /* Virtual UART
45 * When there is no UART (e.g. Quickturn), the host should write a complete
46 * input line directly into cbuf and then write the length into vcons_in.
47 * This may also be used when there is a real UART (at risk of conflicting with
48 * the real UART). vcons_out is currently unused.
49 */
50 volatile uint vcons_in;
51 volatile uint vcons_out;
52
53 /* Output (logging) buffer
54 * Console output is written to a ring buffer log_buf at index log_idx.
55 * The host may read the output when it sees log_idx advance.
56 * Output will be lost if the output wraps around faster than the host polls.
57 */
58 hndrte_log_t log;
59
60 /* Console input line buffer
61 * Characters are read one at a time into cbuf until <CR> is received, then
62 * the buffer is processed as a command line. Also used for virtual UART.
63 */
64 uint cbuf_idx;
65 char cbuf[CBUF_LEN];
66} hndrte_cons_t;
67
68#endif /* _HNDRTE_CONS_H */
diff --git a/drivers/net/wireless/bcmdhd/include/hndsoc.h b/drivers/net/wireless/bcmdhd/include/hndsoc.h
new file mode 100644
index 00000000000..4e26121c388
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/hndsoc.h
@@ -0,0 +1,207 @@
1/*
2 * Broadcom HND chip & on-chip-interconnect-related definitions.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: hndsoc.h,v 13.11 2009-12-03 23:52:31 Exp $
25 */
26
27#ifndef _HNDSOC_H
28#define _HNDSOC_H
29
30/* Include the soci specific files */
31#include <sbconfig.h>
32#include <aidmp.h>
33
34/*
35 * SOC Interconnect Address Map.
36 * All regions may not exist on all chips.
37 */
38#define SI_SDRAM_BASE 0x00000000 /* Physical SDRAM */
39#define SI_PCI_MEM 0x08000000 /* Host Mode sb2pcitranslation0 (64 MB) */
40#define SI_PCI_MEM_SZ (64 * 1024 * 1024)
41#define SI_PCI_CFG 0x0c000000 /* Host Mode sb2pcitranslation1 (64 MB) */
42#define SI_SDRAM_SWAPPED 0x10000000 /* Byteswapped Physical SDRAM */
43#define SI_SDRAM_R2 0x80000000 /* Region 2 for sdram (512 MB) */
44
45#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */
46
47#define SI_WRAP_BASE 0x18100000 /* Wrapper space base */
48#define SI_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */
49#define SI_MAXCORES 16 /* Max cores (this is arbitrary, for software
50 * convenience and could be changed if we
51 * make any larger chips
52 */
53
54#define SI_FASTRAM 0x19000000 /* On-chip RAM on chips that also have DDR */
55#define SI_FASTRAM_SWAPPED 0x19800000
56
57#define SI_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */
58#define SI_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */
59#define SI_ARMCM3_ROM 0x1e000000 /* ARM Cortex-M3 ROM */
60#define SI_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */
61#define SI_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */
62#define SI_ARM7S_ROM 0x20000000 /* ARM7TDMI-S ROM */
63#define SI_ARMCM3_SRAM2 0x60000000 /* ARM Cortex-M3 SRAM Region 2 */
64#define SI_ARM7S_SRAM2 0x80000000 /* ARM7TDMI-S SRAM Region 2 */
65#define SI_ARM_FLASH1 0xffff0000 /* ARM Flash Region 1 */
66#define SI_ARM_FLASH1_SZ 0x00010000 /* ARM Size of Flash Region 1 */
67
68#define SI_PCI_DMA 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */
69#define SI_PCI_DMA2 0x80000000 /* Client Mode sb2pcitranslation2 (1 GB) */
70#define SI_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */
71#define SI_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2
72 * (2 ZettaBytes), low 32 bits
73 */
74#define SI_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2
75 * (2 ZettaBytes), high 32 bits
76 */
77
78/* core codes */
79#define NODEV_CORE_ID 0x700 /* Invalid coreid */
80#define CC_CORE_ID 0x800 /* chipcommon core */
81#define ILINE20_CORE_ID 0x801 /* iline20 core */
82#define SRAM_CORE_ID 0x802 /* sram core */
83#define SDRAM_CORE_ID 0x803 /* sdram core */
84#define PCI_CORE_ID 0x804 /* pci core */
85#define MIPS_CORE_ID 0x805 /* mips core */
86#define ENET_CORE_ID 0x806 /* enet mac core */
87#define CODEC_CORE_ID 0x807 /* v90 codec core */
88#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */
89#define ADSL_CORE_ID 0x809 /* ADSL core */
90#define ILINE100_CORE_ID 0x80a /* iline100 core */
91#define IPSEC_CORE_ID 0x80b /* ipsec core */
92#define UTOPIA_CORE_ID 0x80c /* utopia core */
93#define PCMCIA_CORE_ID 0x80d /* pcmcia core */
94#define SOCRAM_CORE_ID 0x80e /* internal memory core */
95#define MEMC_CORE_ID 0x80f /* memc sdram core */
96#define OFDM_CORE_ID 0x810 /* OFDM phy core */
97#define EXTIF_CORE_ID 0x811 /* external interface core */
98#define D11_CORE_ID 0x812 /* 802.11 MAC core */
99#define APHY_CORE_ID 0x813 /* 802.11a phy core */
100#define BPHY_CORE_ID 0x814 /* 802.11b phy core */
101#define GPHY_CORE_ID 0x815 /* 802.11g phy core */
102#define MIPS33_CORE_ID 0x816 /* mips3302 core */
103#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */
104#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */
105#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */
106#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */
107#define SDIOH_CORE_ID 0x81b /* sdio host core */
108#define ROBO_CORE_ID 0x81c /* roboswitch core */
109#define ATA100_CORE_ID 0x81d /* parallel ATA core */
110#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */
111#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */
112#define PCIE_CORE_ID 0x820 /* pci express core */
113#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */
114#define SRAMC_CORE_ID 0x822 /* SRAM controller core */
115#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */
116#define ARM11_CORE_ID 0x824 /* ARM 1176 core */
117#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */
118#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */
119#define PMU_CORE_ID 0x827 /* PMU core */
120#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */
121#define SDIOD_CORE_ID 0x829 /* SDIO device core */
122#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */
123#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */
124#define MIPS74K_CORE_ID 0x82c /* mips 74k core */
125#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */
126#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */
127#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */
128#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */
129#define SC_CORE_ID 0x831 /* shared common core */
130#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */
131#define SPIH_CORE_ID 0x833 /* SPI host core */
132#define I2S_CORE_ID 0x834 /* I2S core */
133#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */
134#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */
135#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */
136#define DEF_AI_COMP 0xfff /* Default component, in ai chips it maps all
137 * unused address ranges
138 */
139
140/* There are TWO constants on all HND chips: SI_ENUM_BASE above,
141 * and chipcommon being the first core:
142 */
143#define SI_CC_IDX 0
144
145/* SOC Interconnect types (aka chip types) */
146#define SOCI_SB 0
147#define SOCI_AI 1
148#define SOCI_UBUS 2
149
150/* Common core control flags */
151#define SICF_BIST_EN 0x8000
152#define SICF_PME_EN 0x4000
153#define SICF_CORE_BITS 0x3ffc
154#define SICF_FGC 0x0002
155#define SICF_CLOCK_EN 0x0001
156
157/* Common core status flags */
158#define SISF_BIST_DONE 0x8000
159#define SISF_BIST_ERROR 0x4000
160#define SISF_GATED_CLK 0x2000
161#define SISF_DMA64 0x1000
162#define SISF_CORE_BITS 0x0fff
163
164/* A register that is common to all cores to
165 * communicate w/PMU regarding clock control.
166 */
167#define SI_CLK_CTL_ST 0x1e0 /* clock control and status */
168
169/* clk_ctl_st register */
170#define CCS_FORCEALP 0x00000001 /* force ALP request */
171#define CCS_FORCEHT 0x00000002 /* force HT request */
172#define CCS_FORCEILP 0x00000004 /* force ILP request */
173#define CCS_ALPAREQ 0x00000008 /* ALP Avail Request */
174#define CCS_HTAREQ 0x00000010 /* HT Avail Request */
175#define CCS_FORCEHWREQOFF 0x00000020 /* Force HW Clock Request Off */
176#define CCS_ERSRC_REQ_MASK 0x00000700 /* external resource requests */
177#define CCS_ERSRC_REQ_SHIFT 8
178#define CCS_ALPAVAIL 0x00010000 /* ALP is available */
179#define CCS_HTAVAIL 0x00020000 /* HT is available */
180#define CCS_BP_ON_APL 0x00040000 /* RO: Backplane is running on ALP clock */
181#define CCS_BP_ON_HT 0x00080000 /* RO: Backplane is running on HT clock */
182#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */
183#define CCS_ERSRC_STS_SHIFT 24
184
185#define CCS0_HTAVAIL 0x00010000 /* HT avail in chipc and pcmcia on 4328a0 */
186#define CCS0_ALPAVAIL 0x00020000 /* ALP avail in chipc and pcmcia on 4328a0 */
187
188/* Not really related to SOC Interconnect, but a couple of software
189 * conventions for the use the flash space:
190 */
191
192/* Minumum amount of flash we support */
193#define FLASH_MIN 0x00020000 /* Minimum flash size */
194
195/* A boot/binary may have an embedded block that describes its size */
196#define BISZ_OFFSET 0x3e0 /* At this offset into the binary */
197#define BISZ_MAGIC 0x4249535a /* Marked with this value: 'BISZ' */
198#define BISZ_MAGIC_IDX 0 /* Word 0: magic */
199#define BISZ_TXTST_IDX 1 /* 1: text start */
200#define BISZ_TXTEND_IDX 2 /* 2: text end */
201#define BISZ_DATAST_IDX 3 /* 3: data start */
202#define BISZ_DATAEND_IDX 4 /* 4: data end */
203#define BISZ_BSSST_IDX 5 /* 5: bss start */
204#define BISZ_BSSEND_IDX 6 /* 6: bss end */
205#define BISZ_SIZE 7 /* descriptor size in 32-bit integers */
206
207#endif /* _HNDSOC_H */
diff --git a/drivers/net/wireless/bcmdhd/include/htsf.h b/drivers/net/wireless/bcmdhd/include/htsf.h
new file mode 100644
index 00000000000..379fbbe37db
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/htsf.h
@@ -0,0 +1,74 @@
1/*
2 * Time stamps for latency measurements
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: htsf.h,v 1.1.2.4 2011-01-21 08:27:03 Exp $
25 */
26#ifndef _HTSF_H_
27#define _HTSF_H_
28
29#define HTSFMAGIC 0xCDCDABAB /* in network order for tcpdump */
30#define HTSFENDMAGIC 0xEFEFABAB /* to distinguish from RT2 magic */
31#define HTSF_HOSTOFFSET 102
32#define HTSF_DNGLOFFSET HTSF_HOSTOFFSET - 4
33#define HTSF_DNGLOFFSET2 HTSF_HOSTOFFSET + 106
34#define HTSF_MIN_PKTLEN 200
35#define ETHER_TYPE_BRCM_PKTDLYSTATS 0x886d
36
37typedef enum htsfts_type {
38 T10,
39 T20,
40 T30,
41 T40,
42 T50,
43 T60,
44 T70,
45 T80,
46 T90,
47 TA0,
48 TE0
49} htsf_timestamp_t;
50
51typedef struct {
52 uint32 magic;
53 uint32 prio;
54 uint32 seqnum;
55 uint32 misc;
56 uint32 c10;
57 uint32 t10;
58 uint32 c20;
59 uint32 t20;
60 uint32 t30;
61 uint32 t40;
62 uint32 t50;
63 uint32 t60;
64 uint32 t70;
65 uint32 t80;
66 uint32 t90;
67 uint32 cA0;
68 uint32 tA0;
69 uint32 cE0;
70 uint32 tE0;
71 uint32 endmagic;
72} htsfts_t;
73
74#endif /* _HTSF_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/linux_osl.h b/drivers/net/wireless/bcmdhd/include/linux_osl.h
new file mode 100644
index 00000000000..1ec136eb70d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/linux_osl.h
@@ -0,0 +1,431 @@
1/*
2 * Linux OS Independent Layer
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: linux_osl.h,v 13.158.6.3 2010-12-22 23:47:26 Exp $
25 */
26
27
28#ifndef _linux_osl_h_
29#define _linux_osl_h_
30
31#include <typedefs.h>
32
33
34extern void * osl_os_open_image(char * filename);
35extern int osl_os_get_image_block(char * buf, int len, void * image);
36extern void osl_os_close_image(void * image);
37
38
39#ifdef BCMDRIVER
40
41
42extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag);
43extern void osl_detach(osl_t *osh);
44
45
46extern uint32 g_assert_type;
47
48
49#if defined(BCMASSERT_LOG)
50 #define ASSERT(exp) \
51 do { if (!(exp)) osl_assert(#exp, __FILE__, __LINE__); } while (0)
52extern void osl_assert(char *exp, char *file, int line);
53#else
54 #ifdef __GNUC__
55 #define GCC_VERSION \
56 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
57 #if GCC_VERSION > 30100
58 #define ASSERT(exp) do {} while (0)
59 #else
60
61 #define ASSERT(exp)
62 #endif
63 #endif
64#endif
65
66
67#define OSL_DELAY(usec) osl_delay(usec)
68extern void osl_delay(uint usec);
69
70#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \
71 osl_pcmcia_read_attr((osh), (offset), (buf), (size))
72#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \
73 osl_pcmcia_write_attr((osh), (offset), (buf), (size))
74extern void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size);
75extern void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size);
76
77
78#define OSL_PCI_READ_CONFIG(osh, offset, size) \
79 osl_pci_read_config((osh), (offset), (size))
80#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \
81 osl_pci_write_config((osh), (offset), (size), (val))
82extern uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size);
83extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val);
84
85
86#define OSL_PCI_BUS(osh) osl_pci_bus(osh)
87#define OSL_PCI_SLOT(osh) osl_pci_slot(osh)
88extern uint osl_pci_bus(osl_t *osh);
89extern uint osl_pci_slot(osl_t *osh);
90
91
92typedef struct {
93 bool pkttag;
94 uint pktalloced;
95 bool mmbus;
96 pktfree_cb_fn_t tx_fn;
97 void *tx_ctx;
98} osl_pubinfo_t;
99
100#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \
101 do { \
102 ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \
103 ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \
104 } while (0)
105
106
107
108#define BUS_SWAP32(v) (v)
109
110 #define MALLOC(osh, size) osl_malloc((osh), (size))
111 #define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size))
112 #define MALLOCED(osh) osl_malloced((osh))
113 extern void *osl_malloc(osl_t *osh, uint size);
114 extern void osl_mfree(osl_t *osh, void *addr, uint size);
115 extern uint osl_malloced(osl_t *osh);
116
117#define NATIVE_MALLOC(osh, size) kmalloc(size, GFP_ATOMIC)
118#define NATIVE_MFREE(osh, addr, size) kfree(addr)
119
120#define MALLOC_FAILED(osh) osl_malloc_failed((osh))
121extern uint osl_malloc_failed(osl_t *osh);
122
123
124#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align()
125#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \
126 osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap))
127#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \
128 osl_dma_free_consistent((osh), (void*)(va), (size), (pa))
129extern uint osl_dma_consistent_align(void);
130extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align, uint *tot, ulong *pap);
131extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa);
132
133
134#define DMA_TX 1
135#define DMA_RX 2
136
137
138#define DMA_MAP(osh, va, size, direction, p, dmah) \
139 osl_dma_map((osh), (va), (size), (direction))
140#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \
141 osl_dma_unmap((osh), (pa), (size), (direction))
142extern uint osl_dma_map(osl_t *osh, void *va, uint size, int direction);
143extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction);
144
145
146#define OSL_DMADDRWIDTH(osh, addrwidth) do {} while (0)
147
148
149 #include <bcmsdh.h>
150 #define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(NULL, (uintptr)(r), sizeof(*(r)), (v)))
151 #define OSL_READ_REG(osh, r) (bcmsdh_reg_read(NULL, (uintptr)(r), sizeof(*(r))))
152
153 #define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \
154 mmap_op else bus_op
155 #define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \
156 mmap_op : bus_op
157
158#define OSL_ERROR(bcmerror) osl_error(bcmerror)
159extern int osl_error(int bcmerror);
160
161
162#define PKTBUFSZ 2048
163
164
165
166#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ))
167#define printf(fmt, args...) printk(fmt , ## args)
168#include <linux/kernel.h>
169#include <linux/string.h>
170
171#define bcopy(src, dst, len) memcpy((dst), (src), (len))
172#define bcmp(b1, b2, len) memcmp((b1), (b2), (len))
173#define bzero(b, len) memset((b), '\0', (len))
174
175
176
177#ifndef __mips__
178#define R_REG(osh, r) (\
179 SELECT_BUS_READ(osh, sizeof(*(r)) == sizeof(uint8) ? readb((volatile uint8*)(r)) : \
180 sizeof(*(r)) == sizeof(uint16) ? readw((volatile uint16*)(r)) : \
181 readl((volatile uint32*)(r)), OSL_READ_REG(osh, r)) \
182)
183#else
184#define R_REG(osh, r) (\
185 SELECT_BUS_READ(osh, \
186 ({ \
187 __typeof(*(r)) __osl_v; \
188 __asm__ __volatile__("sync"); \
189 switch (sizeof(*(r))) { \
190 case sizeof(uint8): __osl_v = \
191 readb((volatile uint8*)(r)); break; \
192 case sizeof(uint16): __osl_v = \
193 readw((volatile uint16*)(r)); break; \
194 case sizeof(uint32): __osl_v = \
195 readl((volatile uint32*)(r)); break; \
196 } \
197 __asm__ __volatile__("sync"); \
198 __osl_v; \
199 }), \
200 ({ \
201 __typeof(*(r)) __osl_v; \
202 __asm__ __volatile__("sync"); \
203 __osl_v = OSL_READ_REG(osh, r); \
204 __asm__ __volatile__("sync"); \
205 __osl_v; \
206 })) \
207)
208#endif
209
210#define W_REG(osh, r, v) do { \
211 SELECT_BUS_WRITE(osh, \
212 switch (sizeof(*(r))) { \
213 case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \
214 case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \
215 case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \
216 }, \
217 (OSL_WRITE_REG(osh, r, v))); \
218 } while (0)
219
220
221#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v))
222#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v))
223
224
225#define bcopy(src, dst, len) memcpy((dst), (src), (len))
226#define bcmp(b1, b2, len) memcmp((b1), (b2), (len))
227#define bzero(b, len) memset((b), '\0', (len))
228
229
230#ifdef __mips__
231#include <asm/addrspace.h>
232#define OSL_UNCACHED(va) ((void *)KSEG1ADDR((va)))
233#define OSL_CACHED(va) ((void *)KSEG0ADDR((va)))
234#else
235#define OSL_UNCACHED(va) ((void *)va)
236#define OSL_CACHED(va) ((void *)va)
237#endif
238
239
240#if defined(__i386__)
241#define OSL_GETCYCLES(x) rdtscl((x))
242#else
243#define OSL_GETCYCLES(x) ((x) = 0)
244#endif
245
246
247#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; })
248
249
250#if !defined(CONFIG_MMC_MSM7X00A)
251#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size))
252#else
253#define REG_MAP(pa, size) (void *)(0)
254#endif
255#define REG_UNMAP(va) iounmap((va))
256
257
258#define R_SM(r) *(r)
259#define W_SM(r, v) (*(r) = (v))
260#define BZERO_SM(r, len) memset((r), '\0', (len))
261
262
263#include <linuxver.h>
264
265
266#define PKTGET(osh, len, send) osl_pktget((osh), (len))
267#define PKTDUP(osh, skb) osl_pktdup((osh), (skb))
268#define PKTLIST_DUMP(osh, buf)
269#define PKTDBG_TRACE(osh, pkt, bit)
270#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send))
271#ifdef DHD_USE_STATIC_BUF
272#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len))
273#define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send))
274#endif
275#define PKTDATA(osh, skb) (((struct sk_buff*)(skb))->data)
276#define PKTLEN(osh, skb) (((struct sk_buff*)(skb))->len)
277#define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head))
278#define PKTTAILROOM(osh, skb) ((((struct sk_buff*)(skb))->end)-(((struct sk_buff*)(skb))->tail))
279#define PKTNEXT(osh, skb) (((struct sk_buff*)(skb))->next)
280#define PKTSETNEXT(osh, skb, x) (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x))
281#define PKTSETLEN(osh, skb, len) __skb_trim((struct sk_buff*)(skb), (len))
282#define PKTPUSH(osh, skb, bytes) skb_push((struct sk_buff*)(skb), (bytes))
283#define PKTPULL(osh, skb, bytes) skb_pull((struct sk_buff*)(skb), (bytes))
284#define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb))
285#define PKTALLOCED(osh) ((osl_pubinfo_t *)(osh))->pktalloced
286#define PKTSETPOOL(osh, skb, x, y) do {} while (0)
287#define PKTPOOL(osh, skb) FALSE
288#define PKTSHRINK(osh, m) (m)
289
290#ifdef CTFPOOL
291#define CTFPOOL_REFILL_THRESH 3
292typedef struct ctfpool {
293 void *head;
294 spinlock_t lock;
295 uint max_obj;
296 uint curr_obj;
297 uint obj_size;
298 uint refills;
299 uint fast_allocs;
300 uint fast_frees;
301 uint slow_allocs;
302} ctfpool_t;
303#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
304#define FASTBUF (1 << 4)
305#define CTFBUF (1 << 5)
306#define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) |= FASTBUF)
307#define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) &= (~FASTBUF))
308#define PKTSETCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) |= CTFBUF)
309#define PKTCLRCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) &= (~CTFBUF))
310#define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->mac_len) & FASTBUF)
311#define PKTISCTF(osh, skb) ((((struct sk_buff*)(skb))->mac_len) & CTFBUF)
312#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->mac_len)
313#else
314#define FASTBUF (1 << 0)
315#define CTFBUF (1 << 1)
316#define PKTSETFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) |= FASTBUF)
317#define PKTCLRFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) &= (~FASTBUF))
318#define PKTSETCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) |= CTFBUF)
319#define PKTCLRCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) &= (~CTFBUF))
320#define PKTISFAST(osh, skb) ((((struct sk_buff*)(skb))->__unused) & FASTBUF)
321#define PKTISCTF(osh, skb) ((((struct sk_buff*)(skb))->__unused) & CTFBUF)
322#define PKTFAST(osh, skb) (((struct sk_buff*)(skb))->__unused)
323#endif
324
325#define CTFPOOLPTR(osh, skb) (((struct sk_buff*)(skb))->sk)
326#define CTFPOOLHEAD(osh, skb) (((ctfpool_t *)((struct sk_buff*)(skb))->sk)->head)
327
328extern void *osl_ctfpool_add(osl_t *osh);
329extern void osl_ctfpool_replenish(osl_t *osh, uint thresh);
330extern int32 osl_ctfpool_init(osl_t *osh, uint numobj, uint size);
331extern void osl_ctfpool_cleanup(osl_t *osh);
332extern void osl_ctfpool_stats(osl_t *osh, void *b);
333#endif
334
335#ifdef HNDCTF
336#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
337#define SKIPCT (1 << 6)
338#define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len |= SKIPCT)
339#define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len &= (~SKIPCT))
340#define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->mac_len & SKIPCT)
341#else
342#define SKIPCT (1 << 2)
343#define PKTSETSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused |= SKIPCT)
344#define PKTCLRSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused &= (~SKIPCT))
345#define PKTSKIPCT(osh, skb) (((struct sk_buff*)(skb))->__unused & SKIPCT)
346#endif
347#else
348#define PKTSETSKIPCT(osh, skb)
349#define PKTCLRSKIPCT(osh, skb)
350#define PKTSKIPCT(osh, skb)
351#endif
352
353extern void osl_pktfree(osl_t *osh, void *skb, bool send);
354extern void *osl_pktget_static(osl_t *osh, uint len);
355extern void osl_pktfree_static(osl_t *osh, void *skb, bool send);
356
357extern void *osl_pktget(osl_t *osh, uint len);
358extern void *osl_pktdup(osl_t *osh, void *skb);
359
360
361static INLINE void *
362osl_pkt_frmnative(osl_pubinfo_t *osh, void *pkt)
363{
364 struct sk_buff *nskb;
365
366 if (osh->pkttag)
367 bzero((void*)((struct sk_buff*)pkt)->cb, OSL_PKTTAG_SZ);
368
369
370 for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) {
371 osh->pktalloced++;
372 }
373
374 return (void *)pkt;
375}
376#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_pubinfo_t *)osh), (struct sk_buff*)(skb))
377
378
379static INLINE struct sk_buff *
380osl_pkt_tonative(osl_pubinfo_t *osh, void *pkt)
381{
382 struct sk_buff *nskb;
383
384 if (osh->pkttag)
385 bzero(((struct sk_buff*)pkt)->cb, OSL_PKTTAG_SZ);
386
387
388 for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) {
389 osh->pktalloced--;
390 }
391
392 return (struct sk_buff *)pkt;
393}
394#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((osl_pubinfo_t *)(osh), (pkt))
395
396#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev)
397#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x))
398#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority)
399#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x))
400#define PKTSUMNEEDED(skb) (((struct sk_buff*)(skb))->ip_summed == CHECKSUM_HW)
401#define PKTSETSUMGOOD(skb, x) (((struct sk_buff*)(skb))->ip_summed = \
402 ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE))
403
404#define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned)
405
406
407
408#else
409
410
411
412 #define ASSERT(exp) do {} while (0)
413
414
415#define MALLOC(o, l) malloc(l)
416#define MFREE(o, p, l) free(p)
417#include <stdlib.h>
418
419
420#include <string.h>
421
422
423#include <stdio.h>
424
425
426extern void bcopy(const void *src, void *dst, size_t len);
427extern int bcmp(const void *b1, const void *b2, size_t len);
428extern void bzero(void *b, size_t len);
429#endif
430
431#endif
diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h
new file mode 100644
index 00000000000..96844db2f05
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/linuxver.h
@@ -0,0 +1,593 @@
1/*
2 * Linux-specific abstractions to gain some independence from linux kernel versions.
3 * Pave over some 2.2 versus 2.4 versus 2.6 kernel differences.
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: linuxver.h,v 13.53.2.2 2010-12-22 23:47:26 Exp $
26 */
27
28
29#ifndef _linuxver_h_
30#define _linuxver_h_
31
32#include <linux/version.h>
33#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
34#include <linux/config.h>
35#else
36#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33))
37#include <generated/autoconf.h>
38#else
39#include <linux/autoconf.h>
40#endif
41#endif
42#include <linux/module.h>
43
44#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0))
45
46#ifdef __UNDEF_NO_VERSION__
47#undef __NO_VERSION__
48#else
49#define __NO_VERSION__
50#endif
51#endif
52
53#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
54#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i")
55#define module_param_string(_name_, _string_, _size_, _perm_) \
56 MODULE_PARM(_string_, "c" __MODULE_STRING(_size_))
57#endif
58
59
60#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9))
61#include <linux/malloc.h>
62#else
63#include <linux/slab.h>
64#endif
65
66#include <linux/types.h>
67#include <linux/init.h>
68#include <linux/mm.h>
69#include <linux/string.h>
70#include <linux/pci.h>
71#include <linux/interrupt.h>
72#include <linux/netdevice.h>
73#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
74#include <linux/semaphore.h>
75#endif
76#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
77#undef IP_TOS
78#endif
79#include <asm/io.h>
80
81#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41))
82#include <linux/workqueue.h>
83#else
84#include <linux/tqueue.h>
85#ifndef work_struct
86#define work_struct tq_struct
87#endif
88#ifndef INIT_WORK
89#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data))
90#endif
91#ifndef schedule_work
92#define schedule_work(_work) schedule_task((_work))
93#endif
94#ifndef flush_scheduled_work
95#define flush_scheduled_work() flush_scheduled_tasks()
96#endif
97#endif
98
99#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
100#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func)
101#else
102#define MY_INIT_WORK(_work, _func) INIT_WORK(_work, _func, _work)
103typedef void (*work_func_t)(void *work);
104#endif
105
106#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
107
108#ifndef IRQ_NONE
109typedef void irqreturn_t;
110#define IRQ_NONE
111#define IRQ_HANDLED
112#define IRQ_RETVAL(x)
113#endif
114#else
115typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs);
116#endif
117
118#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
119#define IRQF_SHARED SA_SHIRQ
120#endif
121
122#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17)
123#ifdef CONFIG_NET_RADIO
124#define CONFIG_WIRELESS_EXT
125#endif
126#endif
127
128#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67)
129#define MOD_INC_USE_COUNT
130#define MOD_DEC_USE_COUNT
131#endif
132
133#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
134#include <linux/sched.h>
135#endif
136
137#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
138#include <net/lib80211.h>
139#endif
140#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
141#include <linux/ieee80211.h>
142#else
143#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
144#include <net/ieee80211.h>
145#endif
146#endif
147
148
149#ifndef __exit
150#define __exit
151#endif
152#ifndef __devexit
153#define __devexit
154#endif
155#ifndef __devinit
156#define __devinit __init
157#endif
158#ifndef __devinitdata
159#define __devinitdata
160#endif
161#ifndef __devexit_p
162#define __devexit_p(x) x
163#endif
164
165#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0))
166
167#define pci_get_drvdata(dev) (dev)->sysdata
168#define pci_set_drvdata(dev, value) (dev)->sysdata = (value)
169
170
171
172struct pci_device_id {
173 unsigned int vendor, device;
174 unsigned int subvendor, subdevice;
175 unsigned int class, class_mask;
176 unsigned long driver_data;
177};
178
179struct pci_driver {
180 struct list_head node;
181 char *name;
182 const struct pci_device_id *id_table;
183 int (*probe)(struct pci_dev *dev,
184 const struct pci_device_id *id);
185 void (*remove)(struct pci_dev *dev);
186 void (*suspend)(struct pci_dev *dev);
187 void (*resume)(struct pci_dev *dev);
188};
189
190#define MODULE_DEVICE_TABLE(type, name)
191#define PCI_ANY_ID (~0)
192
193
194#define pci_module_init pci_register_driver
195extern int pci_register_driver(struct pci_driver *drv);
196extern void pci_unregister_driver(struct pci_driver *drv);
197
198#endif
199
200#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18))
201#define pci_module_init pci_register_driver
202#endif
203
204#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18))
205#ifdef MODULE
206#define module_init(x) int init_module(void) { return x(); }
207#define module_exit(x) void cleanup_module(void) { x(); }
208#else
209#define module_init(x) __initcall(x);
210#define module_exit(x) __exitcall(x);
211#endif
212#endif
213
214#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
215#define WL_USE_NETDEV_OPS
216#else
217#undef WL_USE_NETDEV_OPS
218#endif
219
220#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) && defined(CONFIG_RFKILL_INPUT)
221#define WL_CONFIG_RFKILL_INPUT
222#else
223#undef WL_CONFIG_RFKILL_INPUT
224#endif
225
226#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48))
227#define list_for_each(pos, head) \
228 for (pos = (head)->next; pos != (head); pos = pos->next)
229#endif
230
231#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 13))
232#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)])
233#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 44))
234#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)
235#endif
236
237#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 23))
238#define pci_enable_device(dev) do { } while (0)
239#endif
240
241#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14))
242#define net_device device
243#endif
244
245#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 42))
246
247
248
249#ifndef PCI_DMA_TODEVICE
250#define PCI_DMA_TODEVICE 1
251#define PCI_DMA_FROMDEVICE 2
252#endif
253
254typedef u32 dma_addr_t;
255
256
257static inline int get_order(unsigned long size)
258{
259 int order;
260
261 size = (size-1) >> (PAGE_SHIFT-1);
262 order = -1;
263 do {
264 size >>= 1;
265 order++;
266 } while (size);
267 return order;
268}
269
270static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
271 dma_addr_t *dma_handle)
272{
273 void *ret;
274 int gfp = GFP_ATOMIC | GFP_DMA;
275
276 ret = (void *)__get_free_pages(gfp, get_order(size));
277
278 if (ret != NULL) {
279 memset(ret, 0, size);
280 *dma_handle = virt_to_bus(ret);
281 }
282 return ret;
283}
284static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size,
285 void *vaddr, dma_addr_t dma_handle)
286{
287 free_pages((unsigned long)vaddr, get_order(size));
288}
289#define pci_map_single(cookie, address, size, dir) virt_to_bus(address)
290#define pci_unmap_single(cookie, address, size, dir)
291
292#endif
293
294#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43))
295
296#define dev_kfree_skb_any(a) dev_kfree_skb(a)
297#define netif_down(dev) do { (dev)->start = 0; } while (0)
298
299
300#ifndef _COMPAT_NETDEVICE_H
301
302
303
304#define dev_kfree_skb_irq(a) dev_kfree_skb(a)
305#define netif_wake_queue(dev) \
306 do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while (0)
307#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy)
308
309static inline void netif_start_queue(struct net_device *dev)
310{
311 dev->tbusy = 0;
312 dev->interrupt = 0;
313 dev->start = 1;
314}
315
316#define netif_queue_stopped(dev) (dev)->tbusy
317#define netif_running(dev) (dev)->start
318
319#endif
320
321#define netif_device_attach(dev) netif_start_queue(dev)
322#define netif_device_detach(dev) netif_stop_queue(dev)
323
324
325#define tasklet_struct tq_struct
326static inline void tasklet_schedule(struct tasklet_struct *tasklet)
327{
328 queue_task(tasklet, &tq_immediate);
329 mark_bh(IMMEDIATE_BH);
330}
331
332static inline void tasklet_init(struct tasklet_struct *tasklet,
333 void (*func)(unsigned long),
334 unsigned long data)
335{
336 tasklet->next = NULL;
337 tasklet->sync = 0;
338 tasklet->routine = (void (*)(void *))func;
339 tasklet->data = (void *)data;
340}
341#define tasklet_kill(tasklet) { do {} while (0); }
342
343
344#define del_timer_sync(timer) del_timer(timer)
345
346#else
347
348#define netif_down(dev)
349
350#endif
351
352#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3))
353
354
355#define PREPARE_TQUEUE(_tq, _routine, _data) \
356 do { \
357 (_tq)->routine = _routine; \
358 (_tq)->data = _data; \
359 } while (0)
360
361
362#define INIT_TQUEUE(_tq, _routine, _data) \
363 do { \
364 INIT_LIST_HEAD(&(_tq)->list); \
365 (_tq)->sync = 0; \
366 PREPARE_TQUEUE((_tq), (_routine), (_data)); \
367 } while (0)
368
369#endif
370
371
372#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9)
373#define PCI_SAVE_STATE(a, b) pci_save_state(a)
374#define PCI_RESTORE_STATE(a, b) pci_restore_state(a)
375#else
376#define PCI_SAVE_STATE(a, b) pci_save_state(a, b)
377#define PCI_RESTORE_STATE(a, b) pci_restore_state(a, b)
378#endif
379
380#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6))
381static inline int
382pci_save_state(struct pci_dev *dev, u32 *buffer)
383{
384 int i;
385 if (buffer) {
386 for (i = 0; i < 16; i++)
387 pci_read_config_dword(dev, i * 4, &buffer[i]);
388 }
389 return 0;
390}
391
392static inline int
393pci_restore_state(struct pci_dev *dev, u32 *buffer)
394{
395 int i;
396
397 if (buffer) {
398 for (i = 0; i < 16; i++)
399 pci_write_config_dword(dev, i * 4, buffer[i]);
400 }
401
402 else {
403 for (i = 0; i < 6; i ++)
404 pci_write_config_dword(dev,
405 PCI_BASE_ADDRESS_0 + (i * 4),
406 pci_resource_start(dev, i));
407 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
408 }
409 return 0;
410}
411#endif
412
413
414#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 19))
415#define read_c0_count() read_32bit_cp0_register(CP0_COUNT)
416#endif
417
418
419#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24))
420#ifndef SET_MODULE_OWNER
421#define SET_MODULE_OWNER(dev) do {} while (0)
422#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
423#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
424#else
425#define OLD_MOD_INC_USE_COUNT do {} while (0)
426#define OLD_MOD_DEC_USE_COUNT do {} while (0)
427#endif
428#else
429#ifndef SET_MODULE_OWNER
430#define SET_MODULE_OWNER(dev) do {} while (0)
431#endif
432#ifndef MOD_INC_USE_COUNT
433#define MOD_INC_USE_COUNT do {} while (0)
434#endif
435#ifndef MOD_DEC_USE_COUNT
436#define MOD_DEC_USE_COUNT do {} while (0)
437#endif
438#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
439#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
440#endif
441
442#ifndef SET_NETDEV_DEV
443#define SET_NETDEV_DEV(net, pdev) do {} while (0)
444#endif
445
446#ifndef HAVE_FREE_NETDEV
447#define free_netdev(dev) kfree(dev)
448#endif
449
450#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
451
452#define af_packet_priv data
453#endif
454
455
456#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
457#define DRV_SUSPEND_STATE_TYPE pm_message_t
458#else
459#define DRV_SUSPEND_STATE_TYPE uint32
460#endif
461
462#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
463#define CHECKSUM_HW CHECKSUM_PARTIAL
464#endif
465
466typedef struct {
467 void *parent;
468 struct task_struct *p_task;
469 long thr_pid;
470 int prio;
471 struct semaphore sema;
472 bool terminated;
473 struct completion completed;
474} tsk_ctl_t;
475
476
477
478
479#ifdef DHD_DEBUG
480#define DBG_THR(x) printk x
481#else
482#define DBG_THR(x)
483#endif
484
485#define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x)
486
487
488#define PROC_START(thread_func, owner, tsk_ctl, flags) \
489{ \
490 sema_init(&((tsk_ctl)->sema), 0); \
491 init_completion(&((tsk_ctl)->completed)); \
492 (tsk_ctl)->parent = owner; \
493 (tsk_ctl)->terminated = FALSE; \
494 (tsk_ctl)->thr_pid = kernel_thread(thread_func, tsk_ctl, flags); \
495 if ((tsk_ctl)->thr_pid > 0) \
496 wait_for_completion(&((tsk_ctl)->completed)); \
497 DBG_THR(("%s thr:%lx started\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \
498}
499
500#define PROC_STOP(tsk_ctl) \
501{ \
502 (tsk_ctl)->terminated = TRUE; \
503 smp_wmb(); \
504 up(&((tsk_ctl)->sema)); \
505 wait_for_completion(&((tsk_ctl)->completed)); \
506 DBG_THR(("%s thr:%lx terminated OK\n", __FUNCTION__, (tsk_ctl)->thr_pid)); \
507 (tsk_ctl)->thr_pid = -1; \
508}
509
510
511
512#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31))
513#define KILL_PROC(nr, sig) \
514{ \
515struct task_struct *tsk; \
516struct pid *pid; \
517pid = find_get_pid((pid_t)nr); \
518tsk = pid_task(pid, PIDTYPE_PID); \
519if (tsk) send_sig(sig, tsk, 1); \
520}
521#else
522#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && (LINUX_VERSION_CODE <= \
523 KERNEL_VERSION(2, 6, 30))
524#define KILL_PROC(pid, sig) \
525{ \
526 struct task_struct *tsk; \
527 tsk = find_task_by_vpid(pid); \
528 if (tsk) send_sig(sig, tsk, 1); \
529}
530#else
531#define KILL_PROC(pid, sig) \
532{ \
533 kill_proc(pid, sig, 1); \
534}
535#endif
536#endif
537
538#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
539#include <linux/time.h>
540#include <linux/wait.h>
541#else
542#include <linux/sched.h>
543
544#define __wait_event_interruptible_timeout(wq, condition, ret) \
545do { \
546 wait_queue_t __wait; \
547 init_waitqueue_entry(&__wait, current); \
548 \
549 add_wait_queue(&wq, &__wait); \
550 for (;;) { \
551 set_current_state(TASK_INTERRUPTIBLE); \
552 if (condition) \
553 break; \
554 if (!signal_pending(current)) { \
555 ret = schedule_timeout(ret); \
556 if (!ret) \
557 break; \
558 continue; \
559 } \
560 ret = -ERESTARTSYS; \
561 break; \
562 } \
563 current->state = TASK_RUNNING; \
564 remove_wait_queue(&wq, &__wait); \
565} while (0)
566
567#define wait_event_interruptible_timeout(wq, condition, timeout) \
568({ \
569 long __ret = timeout; \
570 if (!(condition)) \
571 __wait_event_interruptible_timeout(wq, condition, __ret); \
572 __ret; \
573})
574
575#endif
576
577#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
578#define WL_DEV_IF(dev) ((wl_if_t*)netdev_priv(dev))
579#else
580#define WL_DEV_IF(dev) ((wl_if_t*)(dev)->priv)
581#endif
582
583#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
584#define WL_ISR(i, d, p) wl_isr((i), (d))
585#else
586#define WL_ISR(i, d, p) wl_isr((i), (d), (p))
587#endif
588
589#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
590#define netdev_priv(dev) dev->priv
591#endif
592
593#endif
diff --git a/drivers/net/wireless/bcmdhd/include/miniopt.h b/drivers/net/wireless/bcmdhd/include/miniopt.h
new file mode 100644
index 00000000000..f468420f534
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/miniopt.h
@@ -0,0 +1,77 @@
1/*
2 * Command line options parser.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 * $Id: miniopt.h,v 1.3 2009-01-15 00:06:54 Exp $
24 */
25
26
27#ifndef MINI_OPT_H
28#define MINI_OPT_H
29
30#ifdef __cplusplus
31extern "C" {
32#endif
33
34/* ---- Include Files ---------------------------------------------------- */
35/* ---- Constants and Types ---------------------------------------------- */
36
37#define MINIOPT_MAXKEY 128 /* Max options */
38typedef struct miniopt {
39
40 /* These are persistent after miniopt_init() */
41 const char* name; /* name for prompt in error strings */
42 const char* flags; /* option chars that take no args */
43 bool longflags; /* long options may be flags */
44 bool opt_end; /* at end of options (passed a "--") */
45
46 /* These are per-call to miniopt() */
47
48 int consumed; /* number of argv entries cosumed in
49 * the most recent call to miniopt()
50 */
51 bool positional;
52 bool good_int; /* 'val' member is the result of a sucessful
53 * strtol conversion of the option value
54 */
55 char opt;
56 char key[MINIOPT_MAXKEY];
57 char* valstr; /* positional param, or value for the option,
58 * or null if the option had
59 * no accompanying value
60 */
61 uint uval; /* strtol translation of valstr */
62 int val; /* strtol translation of valstr */
63} miniopt_t;
64
65void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags);
66int miniopt(miniopt_t *t, char **argv);
67
68
69/* ---- Variable Externs ------------------------------------------------- */
70/* ---- Function Prototypes ---------------------------------------------- */
71
72
73#ifdef __cplusplus
74 }
75#endif
76
77#endif /* MINI_OPT_H */
diff --git a/drivers/net/wireless/bcmdhd/include/msgtrace.h b/drivers/net/wireless/bcmdhd/include/msgtrace.h
new file mode 100644
index 00000000000..721d42100f2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/msgtrace.h
@@ -0,0 +1,74 @@
1/*
2 * Trace messages sent over HBUS
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: msgtrace.h,v 1.4 2009-04-10 04:15:32 Exp $
25 */
26
27#ifndef _MSGTRACE_H
28#define _MSGTRACE_H
29
30#ifndef _TYPEDEFS_H_
31#include <typedefs.h>
32#endif
33
34
35/* This marks the start of a packed structure section. */
36#include <packed_section_start.h>
37
38#define MSGTRACE_VERSION 1
39
40/* Message trace header */
41typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr {
42 uint8 version;
43 uint8 spare;
44 uint16 len; /* Len of the trace */
45 uint32 seqnum; /* Sequence number of message. Useful if the messsage has been lost
46 * because of DMA error or a bus reset (ex: SDIO Func2)
47 */
48 uint32 discarded_bytes; /* Number of discarded bytes because of trace overflow */
49 uint32 discarded_printf; /* Number of discarded printf because of trace overflow */
50} BWL_POST_PACKED_STRUCT msgtrace_hdr_t;
51
52#define MSGTRACE_HDRLEN sizeof(msgtrace_hdr_t)
53
54/* The hbus driver generates traces when sending a trace message. This causes endless traces.
55 * This flag must be set to TRUE in any hbus traces. The flag is reset in the function msgtrace_put.
56 * This prevents endless traces but generates hasardous lost of traces only in bus device code.
57 * It is recommendat to set this flag in macro SD_TRACE but not in SD_ERROR for avoiding missing
58 * hbus error traces. hbus error trace should not generates endless traces.
59 */
60extern bool msgtrace_hbus_trace;
61
62typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr,
63 uint16 hdrlen, uint8 *buf, uint16 buflen);
64extern void msgtrace_start(void);
65extern void msgtrace_stop(void);
66extern void msgtrace_sent(void);
67extern void msgtrace_put(char *buf, int count);
68extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send);
69extern bool msgtrace_event_enabled(void);
70
71/* This marks the end of a packed structure section. */
72#include <packed_section_end.h>
73
74#endif /* _MSGTRACE_H */
diff --git a/drivers/net/wireless/bcmdhd/include/osl.h b/drivers/net/wireless/bcmdhd/include/osl.h
new file mode 100644
index 00000000000..80248ee7604
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/osl.h
@@ -0,0 +1,66 @@
1/*
2 * OS Abstraction Layer
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: osl.h,v 13.44.96.1 2010-05-20 11:09:18 Exp $
25 */
26
27
28#ifndef _osl_h_
29#define _osl_h_
30
31
32typedef struct osl_info osl_t;
33typedef struct osl_dmainfo osldma_t;
34
35#define OSL_PKTTAG_SZ 32
36
37
38typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status);
39
40
41#include <linux_osl.h>
42
43#ifndef PKTDBG_TRACE
44#define PKTDBG_TRACE(osh, pkt, bit)
45#endif
46
47
48
49#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val)))
50
51#ifndef AND_REG
52#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v))
53#endif
54
55#ifndef OR_REG
56#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v))
57#endif
58
59#if !defined(OSL_SYSUPTIME)
60#define OSL_SYSUPTIME() (0)
61#define OSL_SYSUPTIME_SUPPORT FALSE
62#else
63#define OSL_SYSUPTIME_SUPPORT TRUE
64#endif
65
66#endif
diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_end.h b/drivers/net/wireless/bcmdhd/include/packed_section_end.h
new file mode 100644
index 00000000000..5d4a8767807
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/packed_section_end.h
@@ -0,0 +1,54 @@
1/*
2 * Declare directives for structure packing. No padding will be provided
3 * between the members of packed structures, and therefore, there is no
4 * guarantee that structure members will be aligned.
5 *
6 * Declaring packed structures is compiler specific. In order to handle all
7 * cases, packed structures should be delared as:
8 *
9 * #include <packed_section_start.h>
10 *
11 * typedef BWL_PRE_PACKED_STRUCT struct foobar_t {
12 * some_struct_members;
13 * } BWL_POST_PACKED_STRUCT foobar_t;
14 *
15 * #include <packed_section_end.h>
16 *
17 *
18 * Copyright (C) 1999-2011, Broadcom Corporation
19 *
20 * Unless you and Broadcom execute a separate written software license
21 * agreement governing use of this software, this software is licensed to you
22 * under the terms of the GNU General Public License version 2 (the "GPL"),
23 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
24 * following added to such license:
25 *
26 * As a special exception, the copyright holders of this software give you
27 * permission to link this software with independent modules, and to copy and
28 * distribute the resulting executable under terms of your choice, provided that
29 * you also meet, for each linked independent module, the terms and conditions of
30 * the license of that module. An independent module is a module which is not
31 * derived from this software. The special exception does not apply to any
32 * modifications of the software.
33 *
34 * Notwithstanding the above, under no circumstances may you combine this
35 * software in any way with any other Broadcom software provided under a license
36 * other than the GPL, without Broadcom's express prior written consent.
37 * $Id: packed_section_end.h,v 1.4 2008-12-09 23:43:22 Exp $
38 */
39
40
41
42
43#ifdef BWL_PACKED_SECTION
44 #undef BWL_PACKED_SECTION
45#else
46 #error "BWL_PACKED_SECTION is NOT defined!"
47#endif
48
49
50
51
52
53#undef BWL_PRE_PACKED_STRUCT
54#undef BWL_POST_PACKED_STRUCT
diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_start.h b/drivers/net/wireless/bcmdhd/include/packed_section_start.h
new file mode 100644
index 00000000000..da2fed68afa
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/packed_section_start.h
@@ -0,0 +1,61 @@
1/*
2 * Declare directives for structure packing. No padding will be provided
3 * between the members of packed structures, and therefore, there is no
4 * guarantee that structure members will be aligned.
5 *
6 * Declaring packed structures is compiler specific. In order to handle all
7 * cases, packed structures should be delared as:
8 *
9 * #include <packed_section_start.h>
10 *
11 * typedef BWL_PRE_PACKED_STRUCT struct foobar_t {
12 * some_struct_members;
13 * } BWL_POST_PACKED_STRUCT foobar_t;
14 *
15 * #include <packed_section_end.h>
16 *
17 *
18 * Copyright (C) 1999-2011, Broadcom Corporation
19 *
20 * Unless you and Broadcom execute a separate written software license
21 * agreement governing use of this software, this software is licensed to you
22 * under the terms of the GNU General Public License version 2 (the "GPL"),
23 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
24 * following added to such license:
25 *
26 * As a special exception, the copyright holders of this software give you
27 * permission to link this software with independent modules, and to copy and
28 * distribute the resulting executable under terms of your choice, provided that
29 * you also meet, for each linked independent module, the terms and conditions of
30 * the license of that module. An independent module is a module which is not
31 * derived from this software. The special exception does not apply to any
32 * modifications of the software.
33 *
34 * Notwithstanding the above, under no circumstances may you combine this
35 * software in any way with any other Broadcom software provided under a license
36 * other than the GPL, without Broadcom's express prior written consent.
37 * $Id: packed_section_start.h,v 1.4.124.1 2010-09-17 00:47:03 Exp $
38 */
39
40
41
42
43#ifdef BWL_PACKED_SECTION
44 #error "BWL_PACKED_SECTION is already defined!"
45#else
46 #define BWL_PACKED_SECTION
47#endif
48
49
50
51
52
53#if defined(__GNUC__)
54 #define BWL_PRE_PACKED_STRUCT
55 #define BWL_POST_PACKED_STRUCT __attribute__ ((packed))
56#elif defined(__CC_ARM)
57 #define BWL_PRE_PACKED_STRUCT __packed
58 #define BWL_POST_PACKED_STRUCT
59#else
60 #error "Unknown compiler!"
61#endif
diff --git a/drivers/net/wireless/bcmdhd/include/pcicfg.h b/drivers/net/wireless/bcmdhd/include/pcicfg.h
new file mode 100644
index 00000000000..fae063a72f1
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/pcicfg.h
@@ -0,0 +1,52 @@
1/*
2 * pcicfg.h: PCI configuration constants and structures.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: pcicfg.h,v 1.50 2009-12-07 21:56:06 Exp $
25 */
26
27
28#ifndef _h_pcicfg_
29#define _h_pcicfg_
30
31
32#define PCI_CFG_VID 0
33#define PCI_CFG_CMD 4
34#define PCI_CFG_REV 8
35#define PCI_CFG_BAR0 0x10
36#define PCI_CFG_BAR1 0x14
37#define PCI_BAR0_WIN 0x80
38#define PCI_INT_STATUS 0x90
39#define PCI_INT_MASK 0x94
40
41#define PCIE_EXTCFG_OFFSET 0x100
42#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024)
43#define PCI_BAR0_PCISBR_OFFSET (4 * 1024)
44
45#define PCI_BAR0_WINSZ (16 * 1024)
46
47
48#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024)
49#define PCI_16KB0_CCREGS_OFFSET (12 * 1024)
50#define PCI_16KBB0_WINSZ (16 * 1024)
51
52#endif
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11.h b/drivers/net/wireless/bcmdhd/include/proto/802.11.h
new file mode 100644
index 00000000000..2342cb38314
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11.h
@@ -0,0 +1,1731 @@
1/*
2 * Copyright (C) 1999-2011, Broadcom Corporation
3 *
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2 (the "GPL"),
7 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
8 * following added to such license:
9 *
10 * As a special exception, the copyright holders of this software give you
11 * permission to link this software with independent modules, and to copy and
12 * distribute the resulting executable under terms of your choice, provided that
13 * you also meet, for each linked independent module, the terms and conditions of
14 * the license of that module. An independent module is a module which is not
15 * derived from this software. The special exception does not apply to any
16 * modifications of the software.
17 *
18 * Notwithstanding the above, under no circumstances may you combine this
19 * software in any way with any other Broadcom software provided under a license
20 * other than the GPL, without Broadcom's express prior written consent.
21 *
22 * Fundamental types and constants relating to 802.11
23 *
24 * $Id: 802.11.h,v 9.260.2.6 2010-12-15 21:41:14 Exp $
25 */
26
27
28#ifndef _802_11_H_
29#define _802_11_H_
30
31#ifndef _TYPEDEFS_H_
32#include <typedefs.h>
33#endif
34
35#ifndef _NET_ETHERNET_H_
36#include <proto/ethernet.h>
37#endif
38
39#include <proto/wpa.h>
40
41
42#include <packed_section_start.h>
43
44
45#define DOT11_TU_TO_US 1024
46
47
48#define DOT11_A3_HDR_LEN 24
49#define DOT11_A4_HDR_LEN 30
50#define DOT11_MAC_HDR_LEN DOT11_A3_HDR_LEN
51#define DOT11_FCS_LEN 4
52#define DOT11_ICV_LEN 4
53#define DOT11_ICV_AES_LEN 8
54#define DOT11_QOS_LEN 2
55#define DOT11_HTC_LEN 4
56
57#define DOT11_KEY_INDEX_SHIFT 6
58#define DOT11_IV_LEN 4
59#define DOT11_IV_TKIP_LEN 8
60#define DOT11_IV_AES_OCB_LEN 4
61#define DOT11_IV_AES_CCM_LEN 8
62#define DOT11_IV_MAX_LEN 8
63
64
65#define DOT11_MAX_MPDU_BODY_LEN 2304
66
67#define DOT11_MAX_MPDU_LEN (DOT11_A4_HDR_LEN + \
68 DOT11_QOS_LEN + \
69 DOT11_IV_AES_CCM_LEN + \
70 DOT11_MAX_MPDU_BODY_LEN + \
71 DOT11_ICV_LEN + \
72 DOT11_FCS_LEN)
73
74#define DOT11_MAX_SSID_LEN 32
75
76
77#define DOT11_DEFAULT_RTS_LEN 2347
78#define DOT11_MAX_RTS_LEN 2347
79
80
81#define DOT11_MIN_FRAG_LEN 256
82#define DOT11_MAX_FRAG_LEN 2346
83#define DOT11_DEFAULT_FRAG_LEN 2346
84
85
86#define DOT11_MIN_BEACON_PERIOD 1
87#define DOT11_MAX_BEACON_PERIOD 0xFFFF
88
89
90#define DOT11_MIN_DTIM_PERIOD 1
91#define DOT11_MAX_DTIM_PERIOD 0xFF
92
93
94#define DOT11_LLC_SNAP_HDR_LEN 8
95#define DOT11_OUI_LEN 3
96BWL_PRE_PACKED_STRUCT struct dot11_llc_snap_header {
97 uint8 dsap;
98 uint8 ssap;
99 uint8 ctl;
100 uint8 oui[DOT11_OUI_LEN];
101 uint16 type;
102} BWL_POST_PACKED_STRUCT;
103
104
105#define RFC1042_HDR_LEN (ETHER_HDR_LEN + DOT11_LLC_SNAP_HDR_LEN)
106
107
108
109BWL_PRE_PACKED_STRUCT struct dot11_header {
110 uint16 fc;
111 uint16 durid;
112 struct ether_addr a1;
113 struct ether_addr a2;
114 struct ether_addr a3;
115 uint16 seq;
116 struct ether_addr a4;
117} BWL_POST_PACKED_STRUCT;
118
119
120
121BWL_PRE_PACKED_STRUCT struct dot11_rts_frame {
122 uint16 fc;
123 uint16 durid;
124 struct ether_addr ra;
125 struct ether_addr ta;
126} BWL_POST_PACKED_STRUCT;
127#define DOT11_RTS_LEN 16
128
129BWL_PRE_PACKED_STRUCT struct dot11_cts_frame {
130 uint16 fc;
131 uint16 durid;
132 struct ether_addr ra;
133} BWL_POST_PACKED_STRUCT;
134#define DOT11_CTS_LEN 10
135
136BWL_PRE_PACKED_STRUCT struct dot11_ack_frame {
137 uint16 fc;
138 uint16 durid;
139 struct ether_addr ra;
140} BWL_POST_PACKED_STRUCT;
141#define DOT11_ACK_LEN 10
142
143BWL_PRE_PACKED_STRUCT struct dot11_ps_poll_frame {
144 uint16 fc;
145 uint16 durid;
146 struct ether_addr bssid;
147 struct ether_addr ta;
148} BWL_POST_PACKED_STRUCT;
149#define DOT11_PS_POLL_LEN 16
150
151BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame {
152 uint16 fc;
153 uint16 durid;
154 struct ether_addr ra;
155 struct ether_addr bssid;
156} BWL_POST_PACKED_STRUCT;
157#define DOT11_CS_END_LEN 16
158
159
160BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific {
161 uint8 category;
162 uint8 OUI[3];
163 uint8 type;
164 uint8 subtype;
165 uint8 data[1040];
166} BWL_POST_PACKED_STRUCT;
167typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t;
168
169
170BWL_PRE_PACKED_STRUCT struct dot11_action_vs_frmhdr {
171 uint8 category;
172 uint8 OUI[3];
173 uint8 type;
174 uint8 subtype;
175 uint8 data[1];
176} BWL_POST_PACKED_STRUCT;
177typedef struct dot11_action_vs_frmhdr dot11_action_vs_frmhdr_t;
178#define DOT11_ACTION_VS_HDR_LEN 6
179
180#define BCM_ACTION_OUI_BYTE0 0x00
181#define BCM_ACTION_OUI_BYTE1 0x90
182#define BCM_ACTION_OUI_BYTE2 0x4c
183
184
185#define DOT11_BA_CTL_POLICY_NORMAL 0x0000
186#define DOT11_BA_CTL_POLICY_NOACK 0x0001
187#define DOT11_BA_CTL_POLICY_MASK 0x0001
188
189#define DOT11_BA_CTL_MTID 0x0002
190#define DOT11_BA_CTL_COMPRESSED 0x0004
191
192#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0
193#define DOT11_BA_CTL_NUMMSDU_SHIFT 6
194
195#define DOT11_BA_CTL_TID_MASK 0xF000
196#define DOT11_BA_CTL_TID_SHIFT 12
197
198
199BWL_PRE_PACKED_STRUCT struct dot11_ctl_header {
200 uint16 fc;
201 uint16 durid;
202 struct ether_addr ra;
203 struct ether_addr ta;
204} BWL_POST_PACKED_STRUCT;
205#define DOT11_CTL_HDR_LEN 16
206
207
208BWL_PRE_PACKED_STRUCT struct dot11_bar {
209 uint16 bar_control;
210 uint16 seqnum;
211} BWL_POST_PACKED_STRUCT;
212#define DOT11_BAR_LEN 4
213
214#define DOT11_BA_BITMAP_LEN 128
215#define DOT11_BA_CMP_BITMAP_LEN 8
216
217BWL_PRE_PACKED_STRUCT struct dot11_ba {
218 uint16 ba_control;
219 uint16 seqnum;
220 uint8 bitmap[DOT11_BA_BITMAP_LEN];
221} BWL_POST_PACKED_STRUCT;
222#define DOT11_BA_LEN 4
223
224
225BWL_PRE_PACKED_STRUCT struct dot11_management_header {
226 uint16 fc;
227 uint16 durid;
228 struct ether_addr da;
229 struct ether_addr sa;
230 struct ether_addr bssid;
231 uint16 seq;
232} BWL_POST_PACKED_STRUCT;
233#define DOT11_MGMT_HDR_LEN 24
234
235
236
237BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb {
238 uint32 timestamp[2];
239 uint16 beacon_interval;
240 uint16 capability;
241} BWL_POST_PACKED_STRUCT;
242#define DOT11_BCN_PRB_LEN 12
243#define DOT11_BCN_PRB_FIXED_LEN 12
244
245BWL_PRE_PACKED_STRUCT struct dot11_auth {
246 uint16 alg;
247 uint16 seq;
248 uint16 status;
249} BWL_POST_PACKED_STRUCT;
250#define DOT11_AUTH_FIXED_LEN 6
251
252BWL_PRE_PACKED_STRUCT struct dot11_assoc_req {
253 uint16 capability;
254 uint16 listen;
255} BWL_POST_PACKED_STRUCT;
256#define DOT11_ASSOC_REQ_FIXED_LEN 4
257
258BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req {
259 uint16 capability;
260 uint16 listen;
261 struct ether_addr ap;
262} BWL_POST_PACKED_STRUCT;
263#define DOT11_REASSOC_REQ_FIXED_LEN 10
264
265BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp {
266 uint16 capability;
267 uint16 status;
268 uint16 aid;
269} BWL_POST_PACKED_STRUCT;
270#define DOT11_ASSOC_RESP_FIXED_LEN 6
271
272BWL_PRE_PACKED_STRUCT struct dot11_action_measure {
273 uint8 category;
274 uint8 action;
275 uint8 token;
276 uint8 data[1];
277} BWL_POST_PACKED_STRUCT;
278#define DOT11_ACTION_MEASURE_LEN 3
279
280BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width {
281 uint8 category;
282 uint8 action;
283 uint8 ch_width;
284} BWL_POST_PACKED_STRUCT;
285
286BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops {
287 uint8 category;
288 uint8 action;
289 uint8 control;
290} BWL_POST_PACKED_STRUCT;
291
292#define SM_PWRSAVE_ENABLE 1
293#define SM_PWRSAVE_MODE 2
294
295
296BWL_PRE_PACKED_STRUCT struct dot11_power_cnst {
297 uint8 id;
298 uint8 len;
299 uint8 power;
300} BWL_POST_PACKED_STRUCT;
301typedef struct dot11_power_cnst dot11_power_cnst_t;
302
303BWL_PRE_PACKED_STRUCT struct dot11_power_cap {
304 uint8 min;
305 uint8 max;
306} BWL_POST_PACKED_STRUCT;
307typedef struct dot11_power_cap dot11_power_cap_t;
308
309BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep {
310 uint8 id;
311 uint8 len;
312 uint8 tx_pwr;
313 uint8 margin;
314} BWL_POST_PACKED_STRUCT;
315typedef struct dot11_tpc_rep dot11_tpc_rep_t;
316#define DOT11_MNG_IE_TPC_REPORT_LEN 2
317
318BWL_PRE_PACKED_STRUCT struct dot11_supp_channels {
319 uint8 id;
320 uint8 len;
321 uint8 first_channel;
322 uint8 num_channels;
323} BWL_POST_PACKED_STRUCT;
324typedef struct dot11_supp_channels dot11_supp_channels_t;
325
326
327BWL_PRE_PACKED_STRUCT struct dot11_extch {
328 uint8 id;
329 uint8 len;
330 uint8 extch;
331} BWL_POST_PACKED_STRUCT;
332typedef struct dot11_extch dot11_extch_ie_t;
333
334BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch {
335 uint8 id;
336 uint8 len;
337 uint8 oui[3];
338 uint8 type;
339 uint8 extch;
340} BWL_POST_PACKED_STRUCT;
341typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t;
342
343#define BRCM_EXTCH_IE_LEN 5
344#define BRCM_EXTCH_IE_TYPE 53
345#define DOT11_EXTCH_IE_LEN 1
346#define DOT11_EXT_CH_MASK 0x03
347#define DOT11_EXT_CH_UPPER 0x01
348#define DOT11_EXT_CH_LOWER 0x03
349#define DOT11_EXT_CH_NONE 0x00
350
351BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr {
352 uint8 category;
353 uint8 action;
354 uint8 data[1];
355} BWL_POST_PACKED_STRUCT;
356#define DOT11_ACTION_FRMHDR_LEN 2
357
358
359BWL_PRE_PACKED_STRUCT struct dot11_channel_switch {
360 uint8 id;
361 uint8 len;
362 uint8 mode;
363 uint8 channel;
364 uint8 count;
365} BWL_POST_PACKED_STRUCT;
366typedef struct dot11_channel_switch dot11_chan_switch_ie_t;
367
368#define DOT11_SWITCH_IE_LEN 3
369
370#define DOT11_CSA_MODE_ADVISORY 0
371#define DOT11_CSA_MODE_NO_TX 1
372
373BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel {
374 uint8 category;
375 uint8 action;
376 dot11_chan_switch_ie_t chan_switch_ie;
377 dot11_brcm_extch_ie_t extch_ie;
378} BWL_POST_PACKED_STRUCT;
379
380BWL_PRE_PACKED_STRUCT struct dot11_csa_body {
381 uint8 mode;
382 uint8 reg;
383 uint8 channel;
384 uint8 count;
385} BWL_POST_PACKED_STRUCT;
386
387
388BWL_PRE_PACKED_STRUCT struct dot11_ext_csa {
389 uint8 id;
390 uint8 len;
391 struct dot11_csa_body b;
392} BWL_POST_PACKED_STRUCT;
393typedef struct dot11_ext_csa dot11_ext_csa_ie_t;
394#define DOT11_EXT_CSA_IE_LEN 4
395
396BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa {
397 uint8 category;
398 uint8 action;
399 dot11_ext_csa_ie_t chan_switch_ie;
400} BWL_POST_PACKED_STRUCT;
401
402BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa {
403 uint8 category;
404 uint8 action;
405 struct dot11_csa_body b;
406} BWL_POST_PACKED_STRUCT;
407
408BWL_PRE_PACKED_STRUCT struct dot11_obss_coex {
409 uint8 id;
410 uint8 len;
411 uint8 info;
412} BWL_POST_PACKED_STRUCT;
413typedef struct dot11_obss_coex dot11_obss_coex_t;
414#define DOT11_OBSS_COEXINFO_LEN 1
415
416#define DOT11_OBSS_COEX_INFO_REQ 0x01
417#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02
418#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04
419
420BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist {
421 uint8 id;
422 uint8 len;
423 uint8 regclass;
424 uint8 chanlist[1];
425} BWL_POST_PACKED_STRUCT;
426typedef struct dot11_obss_chanlist dot11_obss_chanlist_t;
427#define DOT11_OBSS_CHANLIST_FIXED_LEN 1
428
429BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie {
430 uint8 id;
431 uint8 len;
432 uint8 cap;
433} BWL_POST_PACKED_STRUCT;
434typedef struct dot11_extcap_ie dot11_extcap_ie_t;
435#define DOT11_EXTCAP_LEN 1
436
437
438
439#define DOT11_MEASURE_TYPE_BASIC 0
440#define DOT11_MEASURE_TYPE_CCA 1
441#define DOT11_MEASURE_TYPE_RPI 2
442#define DOT11_MEASURE_TYPE_CHLOAD 3
443#define DOT11_MEASURE_TYPE_NOISE 4
444#define DOT11_MEASURE_TYPE_BEACON 5
445#define DOT11_MEASURE_TYPE_FRAME 6
446#define DOT11_MEASURE_TYPE_STATS 7
447#define DOT11_MEASURE_TYPE_LCI 8
448#define DOT11_MEASURE_TYPE_TXSTREAM 9
449#define DOT11_MEASURE_TYPE_PAUSE 255
450
451
452#define DOT11_MEASURE_MODE_PARALLEL (1<<0)
453#define DOT11_MEASURE_MODE_ENABLE (1<<1)
454#define DOT11_MEASURE_MODE_REQUEST (1<<2)
455#define DOT11_MEASURE_MODE_REPORT (1<<3)
456#define DOT11_MEASURE_MODE_DUR (1<<4)
457
458#define DOT11_MEASURE_MODE_LATE (1<<0)
459#define DOT11_MEASURE_MODE_INCAPABLE (1<<1)
460#define DOT11_MEASURE_MODE_REFUSED (1<<2)
461
462#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0))
463#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1))
464#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2))
465#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3))
466#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4))
467
468BWL_PRE_PACKED_STRUCT struct dot11_meas_req {
469 uint8 id;
470 uint8 len;
471 uint8 token;
472 uint8 mode;
473 uint8 type;
474 uint8 channel;
475 uint8 start_time[8];
476 uint16 duration;
477} BWL_POST_PACKED_STRUCT;
478typedef struct dot11_meas_req dot11_meas_req_t;
479#define DOT11_MNG_IE_MREQ_LEN 14
480
481#define DOT11_MNG_IE_MREQ_FIXED_LEN 3
482
483BWL_PRE_PACKED_STRUCT struct dot11_meas_rep {
484 uint8 id;
485 uint8 len;
486 uint8 token;
487 uint8 mode;
488 uint8 type;
489 BWL_PRE_PACKED_STRUCT union
490 {
491 BWL_PRE_PACKED_STRUCT struct {
492 uint8 channel;
493 uint8 start_time[8];
494 uint16 duration;
495 uint8 map;
496 } BWL_POST_PACKED_STRUCT basic;
497 uint8 data[1];
498 } BWL_POST_PACKED_STRUCT rep;
499} BWL_POST_PACKED_STRUCT;
500typedef struct dot11_meas_rep dot11_meas_rep_t;
501
502
503#define DOT11_MNG_IE_MREP_FIXED_LEN 3
504
505BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic {
506 uint8 channel;
507 uint8 start_time[8];
508 uint16 duration;
509 uint8 map;
510} BWL_POST_PACKED_STRUCT;
511typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t;
512#define DOT11_MEASURE_BASIC_REP_LEN 12
513
514BWL_PRE_PACKED_STRUCT struct dot11_quiet {
515 uint8 id;
516 uint8 len;
517 uint8 count;
518 uint8 period;
519 uint16 duration;
520 uint16 offset;
521} BWL_POST_PACKED_STRUCT;
522typedef struct dot11_quiet dot11_quiet_t;
523
524BWL_PRE_PACKED_STRUCT struct chan_map_tuple {
525 uint8 channel;
526 uint8 map;
527} BWL_POST_PACKED_STRUCT;
528typedef struct chan_map_tuple chan_map_tuple_t;
529
530BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs {
531 uint8 id;
532 uint8 len;
533 uint8 eaddr[ETHER_ADDR_LEN];
534 uint8 interval;
535 chan_map_tuple_t map[1];
536} BWL_POST_PACKED_STRUCT;
537typedef struct dot11_ibss_dfs dot11_ibss_dfs_t;
538
539
540#define WME_OUI "\x00\x50\xf2"
541#define WME_OUI_LEN 3
542#define WME_OUI_TYPE 2
543#define WME_VER 1
544#define WME_TYPE 2
545#define WME_SUBTYPE_IE 0
546#define WME_SUBTYPE_PARAM_IE 1
547#define WME_SUBTYPE_TSPEC 2
548
549
550#define AC_BE 0
551#define AC_BK 1
552#define AC_VI 2
553#define AC_VO 3
554#define AC_COUNT 4
555
556typedef uint8 ac_bitmap_t;
557
558#define AC_BITMAP_NONE 0x0
559#define AC_BITMAP_ALL 0xf
560#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0)
561#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac))))
562#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac))))
563
564
565BWL_PRE_PACKED_STRUCT struct wme_ie {
566 uint8 oui[3];
567 uint8 type;
568 uint8 subtype;
569 uint8 version;
570 uint8 qosinfo;
571} BWL_POST_PACKED_STRUCT;
572typedef struct wme_ie wme_ie_t;
573#define WME_IE_LEN 7
574
575BWL_PRE_PACKED_STRUCT struct edcf_acparam {
576 uint8 ACI;
577 uint8 ECW;
578 uint16 TXOP;
579} BWL_POST_PACKED_STRUCT;
580typedef struct edcf_acparam edcf_acparam_t;
581
582
583BWL_PRE_PACKED_STRUCT struct wme_param_ie {
584 uint8 oui[3];
585 uint8 type;
586 uint8 subtype;
587 uint8 version;
588 uint8 qosinfo;
589 uint8 rsvd;
590 edcf_acparam_t acparam[AC_COUNT];
591} BWL_POST_PACKED_STRUCT;
592typedef struct wme_param_ie wme_param_ie_t;
593#define WME_PARAM_IE_LEN 24
594
595
596#define WME_QI_AP_APSD_MASK 0x80
597#define WME_QI_AP_APSD_SHIFT 7
598#define WME_QI_AP_COUNT_MASK 0x0f
599#define WME_QI_AP_COUNT_SHIFT 0
600
601
602#define WME_QI_STA_MAXSPLEN_MASK 0x60
603#define WME_QI_STA_MAXSPLEN_SHIFT 5
604#define WME_QI_STA_APSD_ALL_MASK 0xf
605#define WME_QI_STA_APSD_ALL_SHIFT 0
606#define WME_QI_STA_APSD_BE_MASK 0x8
607#define WME_QI_STA_APSD_BE_SHIFT 3
608#define WME_QI_STA_APSD_BK_MASK 0x4
609#define WME_QI_STA_APSD_BK_SHIFT 2
610#define WME_QI_STA_APSD_VI_MASK 0x2
611#define WME_QI_STA_APSD_VI_SHIFT 1
612#define WME_QI_STA_APSD_VO_MASK 0x1
613#define WME_QI_STA_APSD_VO_SHIFT 0
614
615
616#define EDCF_AIFSN_MIN 1
617#define EDCF_AIFSN_MAX 15
618#define EDCF_AIFSN_MASK 0x0f
619#define EDCF_ACM_MASK 0x10
620#define EDCF_ACI_MASK 0x60
621#define EDCF_ACI_SHIFT 5
622#define EDCF_AIFSN_SHIFT 12
623
624
625#define EDCF_ECW_MIN 0
626#define EDCF_ECW_MAX 15
627#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1)
628#define EDCF_ECWMIN_MASK 0x0f
629#define EDCF_ECWMAX_MASK 0xf0
630#define EDCF_ECWMAX_SHIFT 4
631
632
633#define EDCF_TXOP_MIN 0
634#define EDCF_TXOP_MAX 65535
635#define EDCF_TXOP2USEC(txop) ((txop) << 5)
636
637
638#define NON_EDCF_AC_BE_ACI_STA 0x02
639
640
641#define EDCF_AC_BE_ACI_STA 0x03
642#define EDCF_AC_BE_ECW_STA 0xA4
643#define EDCF_AC_BE_TXOP_STA 0x0000
644#define EDCF_AC_BK_ACI_STA 0x27
645#define EDCF_AC_BK_ECW_STA 0xA4
646#define EDCF_AC_BK_TXOP_STA 0x0000
647#define EDCF_AC_VI_ACI_STA 0x42
648#define EDCF_AC_VI_ECW_STA 0x43
649#define EDCF_AC_VI_TXOP_STA 0x005e
650#define EDCF_AC_VO_ACI_STA 0x62
651#define EDCF_AC_VO_ECW_STA 0x32
652#define EDCF_AC_VO_TXOP_STA 0x002f
653
654
655#define EDCF_AC_BE_ACI_AP 0x03
656#define EDCF_AC_BE_ECW_AP 0x64
657#define EDCF_AC_BE_TXOP_AP 0x0000
658#define EDCF_AC_BK_ACI_AP 0x27
659#define EDCF_AC_BK_ECW_AP 0xA4
660#define EDCF_AC_BK_TXOP_AP 0x0000
661#define EDCF_AC_VI_ACI_AP 0x41
662#define EDCF_AC_VI_ECW_AP 0x43
663#define EDCF_AC_VI_TXOP_AP 0x005e
664#define EDCF_AC_VO_ACI_AP 0x61
665#define EDCF_AC_VO_ECW_AP 0x32
666#define EDCF_AC_VO_TXOP_AP 0x002f
667
668
669BWL_PRE_PACKED_STRUCT struct edca_param_ie {
670 uint8 qosinfo;
671 uint8 rsvd;
672 edcf_acparam_t acparam[AC_COUNT];
673} BWL_POST_PACKED_STRUCT;
674typedef struct edca_param_ie edca_param_ie_t;
675#define EDCA_PARAM_IE_LEN 18
676
677
678BWL_PRE_PACKED_STRUCT struct qos_cap_ie {
679 uint8 qosinfo;
680} BWL_POST_PACKED_STRUCT;
681typedef struct qos_cap_ie qos_cap_ie_t;
682
683BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie {
684 uint8 id;
685 uint8 length;
686 uint16 station_count;
687 uint8 channel_utilization;
688 uint16 aac;
689} BWL_POST_PACKED_STRUCT;
690typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t;
691
692
693#define FIXED_MSDU_SIZE 0x8000
694#define MSDU_SIZE_MASK 0x7fff
695
696
697
698#define INTEGER_SHIFT 13
699#define FRACTION_MASK 0x1FFF
700
701
702BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
703 uint8 category;
704 uint8 action;
705 uint8 token;
706 uint8 status;
707 uint8 data[1];
708} BWL_POST_PACKED_STRUCT;
709#define DOT11_MGMT_NOTIFICATION_LEN 4
710
711
712#define WME_ADDTS_REQUEST 0
713#define WME_ADDTS_RESPONSE 1
714#define WME_DELTS_REQUEST 2
715
716
717#define WME_ADMISSION_ACCEPTED 0
718#define WME_INVALID_PARAMETERS 1
719#define WME_ADMISSION_REFUSED 3
720
721
722#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN)
723
724
725#define DOT11_OPEN_SYSTEM 0
726#define DOT11_SHARED_KEY 1
727#define DOT11_OPEN_SHARED 2
728#define DOT11_FAST_BSS 3
729#define DOT11_CHALLENGE_LEN 128
730
731
732#define FC_PVER_MASK 0x3
733#define FC_PVER_SHIFT 0
734#define FC_TYPE_MASK 0xC
735#define FC_TYPE_SHIFT 2
736#define FC_SUBTYPE_MASK 0xF0
737#define FC_SUBTYPE_SHIFT 4
738#define FC_TODS 0x100
739#define FC_TODS_SHIFT 8
740#define FC_FROMDS 0x200
741#define FC_FROMDS_SHIFT 9
742#define FC_MOREFRAG 0x400
743#define FC_MOREFRAG_SHIFT 10
744#define FC_RETRY 0x800
745#define FC_RETRY_SHIFT 11
746#define FC_PM 0x1000
747#define FC_PM_SHIFT 12
748#define FC_MOREDATA 0x2000
749#define FC_MOREDATA_SHIFT 13
750#define FC_WEP 0x4000
751#define FC_WEP_SHIFT 14
752#define FC_ORDER 0x8000
753#define FC_ORDER_SHIFT 15
754
755
756#define SEQNUM_SHIFT 4
757#define SEQNUM_MAX 0x1000
758#define FRAGNUM_MASK 0xF
759
760
761
762
763#define FC_TYPE_MNG 0
764#define FC_TYPE_CTL 1
765#define FC_TYPE_DATA 2
766
767
768#define FC_SUBTYPE_ASSOC_REQ 0
769#define FC_SUBTYPE_ASSOC_RESP 1
770#define FC_SUBTYPE_REASSOC_REQ 2
771#define FC_SUBTYPE_REASSOC_RESP 3
772#define FC_SUBTYPE_PROBE_REQ 4
773#define FC_SUBTYPE_PROBE_RESP 5
774#define FC_SUBTYPE_BEACON 8
775#define FC_SUBTYPE_ATIM 9
776#define FC_SUBTYPE_DISASSOC 10
777#define FC_SUBTYPE_AUTH 11
778#define FC_SUBTYPE_DEAUTH 12
779#define FC_SUBTYPE_ACTION 13
780#define FC_SUBTYPE_ACTION_NOACK 14
781
782
783#define FC_SUBTYPE_CTL_WRAPPER 7
784#define FC_SUBTYPE_BLOCKACK_REQ 8
785#define FC_SUBTYPE_BLOCKACK 9
786#define FC_SUBTYPE_PS_POLL 10
787#define FC_SUBTYPE_RTS 11
788#define FC_SUBTYPE_CTS 12
789#define FC_SUBTYPE_ACK 13
790#define FC_SUBTYPE_CF_END 14
791#define FC_SUBTYPE_CF_END_ACK 15
792
793
794#define FC_SUBTYPE_DATA 0
795#define FC_SUBTYPE_DATA_CF_ACK 1
796#define FC_SUBTYPE_DATA_CF_POLL 2
797#define FC_SUBTYPE_DATA_CF_ACK_POLL 3
798#define FC_SUBTYPE_NULL 4
799#define FC_SUBTYPE_CF_ACK 5
800#define FC_SUBTYPE_CF_POLL 6
801#define FC_SUBTYPE_CF_ACK_POLL 7
802#define FC_SUBTYPE_QOS_DATA 8
803#define FC_SUBTYPE_QOS_DATA_CF_ACK 9
804#define FC_SUBTYPE_QOS_DATA_CF_POLL 10
805#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11
806#define FC_SUBTYPE_QOS_NULL 12
807#define FC_SUBTYPE_QOS_CF_POLL 14
808#define FC_SUBTYPE_QOS_CF_ACK_POLL 15
809
810
811#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0)
812#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0)
813#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0)
814#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0)
815
816
817#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK)
818
819#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT))
820
821#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT)
822#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT)
823
824#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ)
825#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP)
826#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ)
827#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP)
828#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ)
829#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP)
830#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON)
831#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC)
832#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH)
833#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH)
834#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION)
835#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK)
836
837#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER)
838#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ)
839#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK)
840#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL)
841#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS)
842#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS)
843#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK)
844#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END)
845#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK)
846
847#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA)
848#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL)
849#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK)
850#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA)
851#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL)
852
853
854
855
856#define QOS_PRIO_SHIFT 0
857#define QOS_PRIO_MASK 0x0007
858#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT)
859
860
861#define QOS_TID_SHIFT 0
862#define QOS_TID_MASK 0x000f
863#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT)
864
865
866#define QOS_EOSP_SHIFT 4
867#define QOS_EOSP_MASK 0x0010
868#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT)
869
870
871#define QOS_ACK_NORMAL_ACK 0
872#define QOS_ACK_NO_ACK 1
873#define QOS_ACK_NO_EXP_ACK 2
874#define QOS_ACK_BLOCK_ACK 3
875#define QOS_ACK_SHIFT 5
876#define QOS_ACK_MASK 0x0060
877#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT)
878
879
880#define QOS_AMSDU_SHIFT 7
881#define QOS_AMSDU_MASK 0x0080
882
883
884
885
886
887
888#define DOT11_MNG_AUTH_ALGO_LEN 2
889#define DOT11_MNG_AUTH_SEQ_LEN 2
890#define DOT11_MNG_BEACON_INT_LEN 2
891#define DOT11_MNG_CAP_LEN 2
892#define DOT11_MNG_AP_ADDR_LEN 6
893#define DOT11_MNG_LISTEN_INT_LEN 2
894#define DOT11_MNG_REASON_LEN 2
895#define DOT11_MNG_AID_LEN 2
896#define DOT11_MNG_STATUS_LEN 2
897#define DOT11_MNG_TIMESTAMP_LEN 8
898
899
900#define DOT11_AID_MASK 0x3fff
901
902
903#define DOT11_RC_RESERVED 0
904#define DOT11_RC_UNSPECIFIED 1
905#define DOT11_RC_AUTH_INVAL 2
906#define DOT11_RC_DEAUTH_LEAVING 3
907#define DOT11_RC_INACTIVITY 4
908#define DOT11_RC_BUSY 5
909#define DOT11_RC_INVAL_CLASS_2 6
910#define DOT11_RC_INVAL_CLASS_3 7
911#define DOT11_RC_DISASSOC_LEAVING 8
912#define DOT11_RC_NOT_AUTH 9
913#define DOT11_RC_BAD_PC 10
914#define DOT11_RC_BAD_CHANNELS 11
915
916
917
918#define DOT11_RC_UNSPECIFIED_QOS 32
919#define DOT11_RC_INSUFFCIENT_BW 33
920#define DOT11_RC_EXCESSIVE_FRAMES 34
921#define DOT11_RC_TX_OUTSIDE_TXOP 35
922#define DOT11_RC_LEAVING_QBSS 36
923#define DOT11_RC_BAD_MECHANISM 37
924#define DOT11_RC_SETUP_NEEDED 38
925#define DOT11_RC_TIMEOUT 39
926
927#define DOT11_RC_MAX 23
928
929
930#define DOT11_SC_SUCCESS 0
931#define DOT11_SC_FAILURE 1
932#define DOT11_SC_CAP_MISMATCH 10
933#define DOT11_SC_REASSOC_FAIL 11
934#define DOT11_SC_ASSOC_FAIL 12
935#define DOT11_SC_AUTH_MISMATCH 13
936#define DOT11_SC_AUTH_SEQ 14
937#define DOT11_SC_AUTH_CHALLENGE_FAIL 15
938#define DOT11_SC_AUTH_TIMEOUT 16
939#define DOT11_SC_ASSOC_BUSY_FAIL 17
940#define DOT11_SC_ASSOC_RATE_MISMATCH 18
941#define DOT11_SC_ASSOC_SHORT_REQUIRED 19
942#define DOT11_SC_ASSOC_PBCC_REQUIRED 20
943#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21
944#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22
945#define DOT11_SC_ASSOC_BAD_POWER_CAP 23
946#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24
947#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25
948#define DOT11_SC_ASSOC_ERPBCC_REQUIRED 26
949#define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27
950
951#define DOT11_SC_DECLINED 37
952#define DOT11_SC_INVALID_PARAMS 38
953#define DOT11_SC_INVALID_AKMP 43
954#define DOT11_SC_INVALID_MDID 54
955#define DOT11_SC_INVALID_FTIE 55
956
957
958#define DOT11_MNG_DS_PARAM_LEN 1
959#define DOT11_MNG_IBSS_PARAM_LEN 2
960
961
962#define DOT11_MNG_TIM_FIXED_LEN 3
963#define DOT11_MNG_TIM_DTIM_COUNT 0
964#define DOT11_MNG_TIM_DTIM_PERIOD 1
965#define DOT11_MNG_TIM_BITMAP_CTL 2
966#define DOT11_MNG_TIM_PVB 3
967
968
969#define TLV_TAG_OFF 0
970#define TLV_LEN_OFF 1
971#define TLV_HDR_LEN 2
972#define TLV_BODY_OFF 2
973
974
975#define DOT11_MNG_SSID_ID 0
976#define DOT11_MNG_RATES_ID 1
977#define DOT11_MNG_FH_PARMS_ID 2
978#define DOT11_MNG_DS_PARMS_ID 3
979#define DOT11_MNG_CF_PARMS_ID 4
980#define DOT11_MNG_TIM_ID 5
981#define DOT11_MNG_IBSS_PARMS_ID 6
982#define DOT11_MNG_COUNTRY_ID 7
983#define DOT11_MNG_HOPPING_PARMS_ID 8
984#define DOT11_MNG_HOPPING_TABLE_ID 9
985#define DOT11_MNG_REQUEST_ID 10
986#define DOT11_MNG_QBSS_LOAD_ID 11
987#define DOT11_MNG_EDCA_PARAM_ID 12
988#define DOT11_MNG_CHALLENGE_ID 16
989#define DOT11_MNG_PWR_CONSTRAINT_ID 32
990#define DOT11_MNG_PWR_CAP_ID 33
991#define DOT11_MNG_TPC_REQUEST_ID 34
992#define DOT11_MNG_TPC_REPORT_ID 35
993#define DOT11_MNG_SUPP_CHANNELS_ID 36
994#define DOT11_MNG_CHANNEL_SWITCH_ID 37
995#define DOT11_MNG_MEASURE_REQUEST_ID 38
996#define DOT11_MNG_MEASURE_REPORT_ID 39
997#define DOT11_MNG_QUIET_ID 40
998#define DOT11_MNG_IBSS_DFS_ID 41
999#define DOT11_MNG_ERP_ID 42
1000#define DOT11_MNG_TS_DELAY_ID 43
1001#define DOT11_MNG_HT_CAP 45
1002#define DOT11_MNG_QOS_CAP_ID 46
1003#define DOT11_MNG_NONERP_ID 47
1004#define DOT11_MNG_RSN_ID 48
1005#define DOT11_MNG_EXT_RATES_ID 50
1006#define DOT11_MNG_AP_CHREP_ID 51
1007#define DOT11_MNG_NBR_REP_ID 52
1008#define DOT11_MNG_MDIE_ID 54
1009#define DOT11_MNG_FTIE_ID 55
1010#define DOT11_MNG_FT_TI_ID 56
1011#define DOT11_MNG_REGCLASS_ID 59
1012#define DOT11_MNG_EXT_CSA_ID 60
1013#define DOT11_MNG_HT_ADD 61
1014#define DOT11_MNG_EXT_CHANNEL_OFFSET 62
1015
1016
1017#define DOT11_MNG_RRM_CAP_ID 70
1018#define DOT11_MNG_HT_BSS_COEXINFO_ID 72
1019#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73
1020#define DOT11_MNG_HT_OBSS_ID 74
1021#define DOT11_MNG_EXT_CAP 127
1022#define DOT11_MNG_WPA_ID 221
1023#define DOT11_MNG_PROPR_ID 221
1024
1025#define DOT11_MNG_VS_ID 221
1026
1027
1028#define DOT11_RATE_BASIC 0x80
1029#define DOT11_RATE_MASK 0x7F
1030
1031
1032#define DOT11_MNG_ERP_LEN 1
1033#define DOT11_MNG_NONERP_PRESENT 0x01
1034#define DOT11_MNG_USE_PROTECTION 0x02
1035#define DOT11_MNG_BARKER_PREAMBLE 0x04
1036
1037#define DOT11_MGN_TS_DELAY_LEN 4
1038#define TS_DELAY_FIELD_SIZE 4
1039
1040
1041#define DOT11_CAP_ESS 0x0001
1042#define DOT11_CAP_IBSS 0x0002
1043#define DOT11_CAP_POLLABLE 0x0004
1044#define DOT11_CAP_POLL_RQ 0x0008
1045#define DOT11_CAP_PRIVACY 0x0010
1046#define DOT11_CAP_SHORT 0x0020
1047#define DOT11_CAP_PBCC 0x0040
1048#define DOT11_CAP_AGILITY 0x0080
1049#define DOT11_CAP_SPECTRUM 0x0100
1050#define DOT11_CAP_SHORTSLOT 0x0400
1051#define DOT11_CAP_RRM 0x1000
1052#define DOT11_CAP_CCK_OFDM 0x2000
1053
1054
1055#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01
1056
1057
1058#define DOT11_ACTION_HDR_LEN 2
1059#define DOT11_ACTION_CAT_OFF 0
1060#define DOT11_ACTION_ACT_OFF 1
1061
1062
1063#define DOT11_ACTION_CAT_ERR_MASK 0x80
1064#define DOT11_ACTION_CAT_MASK 0x7F
1065#define DOT11_ACTION_CAT_SPECT_MNG 0
1066#define DOT11_ACTION_CAT_QOS 1
1067#define DOT11_ACTION_CAT_DLS 2
1068#define DOT11_ACTION_CAT_BLOCKACK 3
1069#define DOT11_ACTION_CAT_PUBLIC 4
1070#define DOT11_ACTION_CAT_RRM 5
1071#define DOT11_ACTION_CAT_FBT 6
1072#define DOT11_ACTION_CAT_HT 7
1073#define DOT11_ACTION_CAT_BSSMGMT 10
1074#define DOT11_ACTION_NOTIFICATION 17
1075#define DOT11_ACTION_CAT_VS 127
1076
1077
1078#define DOT11_SM_ACTION_M_REQ 0
1079#define DOT11_SM_ACTION_M_REP 1
1080#define DOT11_SM_ACTION_TPC_REQ 2
1081#define DOT11_SM_ACTION_TPC_REP 3
1082#define DOT11_SM_ACTION_CHANNEL_SWITCH 4
1083#define DOT11_SM_ACTION_EXT_CSA 5
1084
1085
1086#define DOT11_ACTION_ID_HT_CH_WIDTH 0
1087#define DOT11_ACTION_ID_HT_MIMO_PS 1
1088
1089
1090#define DOT11_PUB_ACTION_BSS_COEX_MNG 0
1091#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4
1092
1093
1094#define DOT11_BA_ACTION_ADDBA_REQ 0
1095#define DOT11_BA_ACTION_ADDBA_RESP 1
1096#define DOT11_BA_ACTION_DELBA 2
1097
1098
1099#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001
1100#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002
1101#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1
1102#define DOT11_ADDBA_PARAM_TID_MASK 0x003c
1103#define DOT11_ADDBA_PARAM_TID_SHIFT 2
1104#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0
1105#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6
1106
1107#define DOT11_ADDBA_POLICY_DELAYED 0
1108#define DOT11_ADDBA_POLICY_IMMEDIATE 1
1109
1110BWL_PRE_PACKED_STRUCT struct dot11_addba_req {
1111 uint8 category;
1112 uint8 action;
1113 uint8 token;
1114 uint16 addba_param_set;
1115 uint16 timeout;
1116 uint16 start_seqnum;
1117} BWL_POST_PACKED_STRUCT;
1118typedef struct dot11_addba_req dot11_addba_req_t;
1119#define DOT11_ADDBA_REQ_LEN 9
1120
1121BWL_PRE_PACKED_STRUCT struct dot11_addba_resp {
1122 uint8 category;
1123 uint8 action;
1124 uint8 token;
1125 uint16 status;
1126 uint16 addba_param_set;
1127 uint16 timeout;
1128} BWL_POST_PACKED_STRUCT;
1129typedef struct dot11_addba_resp dot11_addba_resp_t;
1130#define DOT11_ADDBA_RESP_LEN 9
1131
1132
1133#define DOT11_DELBA_PARAM_INIT_MASK 0x0800
1134#define DOT11_DELBA_PARAM_INIT_SHIFT 11
1135#define DOT11_DELBA_PARAM_TID_MASK 0xf000
1136#define DOT11_DELBA_PARAM_TID_SHIFT 12
1137
1138BWL_PRE_PACKED_STRUCT struct dot11_delba {
1139 uint8 category;
1140 uint8 action;
1141 uint16 delba_param_set;
1142 uint16 reason;
1143} BWL_POST_PACKED_STRUCT;
1144typedef struct dot11_delba dot11_delba_t;
1145#define DOT11_DELBA_LEN 6
1146
1147
1148
1149
1150
1151#define DOT11_RRM_CAP_LEN 5
1152BWL_PRE_PACKED_STRUCT struct dot11_rrm_cap_ie {
1153 uint8 cap[DOT11_RRM_CAP_LEN];
1154} BWL_POST_PACKED_STRUCT;
1155typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t;
1156
1157
1158#define DOT11_RRM_CAP_LINK 0
1159#define DOT11_RRM_CAP_NEIGHBOR_REPORT 1
1160#define DOT11_RRM_CAP_PARALLEL 2
1161#define DOT11_RRM_CAP_REPEATED 3
1162#define DOT11_RRM_CAP_BCN_PASSIVE 4
1163#define DOT11_RRM_CAP_BCN_ACTIVE 5
1164#define DOT11_RRM_CAP_BCN_TABLE 6
1165#define DOT11_RRM_CAP_BCN_REP_COND 7
1166#define DOT11_RRM_CAP_AP_CHANREP 16
1167
1168
1169#define DOT11_RM_ACTION_RM_REQ 0
1170#define DOT11_RM_ACTION_RM_REP 1
1171#define DOT11_RM_ACTION_LM_REQ 2
1172#define DOT11_RM_ACTION_LM_REP 3
1173#define DOT11_RM_ACTION_NR_REQ 4
1174#define DOT11_RM_ACTION_NR_REP 5
1175
1176
1177BWL_PRE_PACKED_STRUCT struct dot11_rm_action {
1178 uint8 category;
1179 uint8 action;
1180 uint8 token;
1181 uint8 data[1];
1182} BWL_POST_PACKED_STRUCT;
1183typedef struct dot11_rm_action dot11_rm_action_t;
1184#define DOT11_RM_ACTION_LEN 3
1185
1186BWL_PRE_PACKED_STRUCT struct dot11_rmreq {
1187 uint8 category;
1188 uint8 action;
1189 uint8 token;
1190 uint16 reps;
1191} BWL_POST_PACKED_STRUCT;
1192typedef struct dot11_rmreq dot11_rmreq_t;
1193#define DOT11_RMREQ_LEN 5
1194
1195BWL_PRE_PACKED_STRUCT struct dot11_rm_ie {
1196 uint8 id;
1197 uint8 len;
1198 uint8 token;
1199 uint8 mode;
1200 uint8 type;
1201} BWL_POST_PACKED_STRUCT;
1202typedef struct dot11_rm_ie dot11_rm_ie_t;
1203#define DOT11_RM_IE_LEN 5
1204
1205
1206#define DOT11_RMREQ_MODE_PARALLEL 1
1207#define DOT11_RMREQ_MODE_ENABLE 2
1208#define DOT11_RMREQ_MODE_REQUEST 4
1209#define DOT11_RMREQ_MODE_REPORT 8
1210#define DOT11_RMREQ_MODE_DURMAND 0x10
1211
1212
1213#define DOT11_RMREP_MODE_LATE 1
1214#define DOT11_RMREP_MODE_INCAPABLE 2
1215#define DOT11_RMREP_MODE_REFUSED 4
1216
1217BWL_PRE_PACKED_STRUCT struct dot11_rmreq_bcn {
1218 uint8 id;
1219 uint8 len;
1220 uint8 token;
1221 uint8 mode;
1222 uint8 type;
1223 uint8 reg;
1224 uint8 channel;
1225 uint16 interval;
1226 uint16 duration;
1227 uint8 bcn_mode;
1228 struct ether_addr bssid;
1229} BWL_POST_PACKED_STRUCT;
1230typedef struct dot11_rmreq_bcn dot11_rmreq_bcn_t;
1231#define DOT11_RMREQ_BCN_LEN 18
1232
1233BWL_PRE_PACKED_STRUCT struct dot11_rmrep_bcn {
1234 uint8 reg;
1235 uint8 channel;
1236 uint32 starttime[2];
1237 uint16 duration;
1238 uint8 frame_info;
1239 uint8 rcpi;
1240 uint8 rsni;
1241 struct ether_addr bssid;
1242 uint8 antenna_id;
1243 uint32 parent_tsf;
1244} BWL_POST_PACKED_STRUCT;
1245typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t;
1246#define DOT11_RMREP_BCN_LEN 26
1247
1248
1249#define DOT11_RMREQ_BCN_PASSIVE 0
1250#define DOT11_RMREQ_BCN_ACTIVE 1
1251#define DOT11_RMREQ_BCN_TABLE 2
1252
1253
1254#define DOT11_RMREQ_BCN_SSID_ID 0
1255#define DOT11_RMREQ_BCN_REPINFO_ID 1
1256#define DOT11_RMREQ_BCN_REPDET_ID 2
1257#define DOT11_RMREQ_BCN_REQUEST_ID 10
1258#define DOT11_RMREQ_BCN_APCHREP_ID 51
1259
1260
1261#define DOT11_RMREQ_BCN_REPDET_FIXED 0
1262#define DOT11_RMREQ_BCN_REPDET_REQUEST 1
1263#define DOT11_RMREQ_BCN_REPDET_ALL 2
1264
1265
1266#define DOT11_RMREP_BCN_FRM_BODY 1
1267
1268
1269BWL_PRE_PACKED_STRUCT struct dot11_rmrep_nbr {
1270 struct ether_addr bssid;
1271 uint32 bssid_info;
1272 uint8 reg;
1273 uint8 channel;
1274 uint8 phytype;
1275} BWL_POST_PACKED_STRUCT;
1276typedef struct dot11_rmrep_nbr dot11_rmrep_nbr_t;
1277#define DOT11_RMREP_NBR_LEN 13
1278
1279
1280#define DOT11_BSSTYPE_INFRASTRUCTURE 0
1281#define DOT11_BSSTYPE_INDEPENDENT 1
1282#define DOT11_BSSTYPE_ANY 2
1283#define DOT11_SCANTYPE_ACTIVE 0
1284#define DOT11_SCANTYPE_PASSIVE 1
1285
1286
1287BWL_PRE_PACKED_STRUCT struct dot11_lmreq {
1288 uint8 category;
1289 uint8 action;
1290 uint8 token;
1291 uint8 txpwr;
1292 uint8 maxtxpwr;
1293} BWL_POST_PACKED_STRUCT;
1294typedef struct dot11_lmreq dot11_lmreq_t;
1295#define DOT11_LMREQ_LEN 5
1296
1297BWL_PRE_PACKED_STRUCT struct dot11_lmrep {
1298 uint8 category;
1299 uint8 action;
1300 uint8 token;
1301 dot11_tpc_rep_t tpc;
1302 uint8 rxant;
1303 uint8 txant;
1304 uint8 rcpi;
1305 uint8 rsni;
1306} BWL_POST_PACKED_STRUCT;
1307typedef struct dot11_lmrep dot11_lmrep_t;
1308#define DOT11_LMREP_LEN 11
1309
1310
1311#define PREN_PREAMBLE 24
1312#define PREN_MM_EXT 12
1313#define PREN_PREAMBLE_EXT 4
1314
1315
1316#define RIFS_11N_TIME 2
1317
1318
1319
1320#define HT_SIG1_MCS_MASK 0x00007F
1321#define HT_SIG1_CBW 0x000080
1322#define HT_SIG1_HT_LENGTH 0xFFFF00
1323
1324
1325#define HT_SIG2_SMOOTHING 0x000001
1326#define HT_SIG2_NOT_SOUNDING 0x000002
1327#define HT_SIG2_RESERVED 0x000004
1328#define HT_SIG2_AGGREGATION 0x000008
1329#define HT_SIG2_STBC_MASK 0x000030
1330#define HT_SIG2_STBC_SHIFT 4
1331#define HT_SIG2_FEC_CODING 0x000040
1332#define HT_SIG2_SHORT_GI 0x000080
1333#define HT_SIG2_ESS_MASK 0x000300
1334#define HT_SIG2_ESS_SHIFT 8
1335#define HT_SIG2_CRC 0x03FC00
1336#define HT_SIG2_TAIL 0x1C0000
1337
1338
1339#define APHY_SLOT_TIME 9
1340#define APHY_SIFS_TIME 16
1341#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME))
1342#define APHY_PREAMBLE_TIME 16
1343#define APHY_SIGNAL_TIME 4
1344#define APHY_SYMBOL_TIME 4
1345#define APHY_SERVICE_NBITS 16
1346#define APHY_TAIL_NBITS 6
1347#define APHY_CWMIN 15
1348
1349
1350#define BPHY_SLOT_TIME 20
1351#define BPHY_SIFS_TIME 10
1352#define BPHY_DIFS_TIME 50
1353#define BPHY_PLCP_TIME 192
1354#define BPHY_PLCP_SHORT_TIME 96
1355#define BPHY_CWMIN 31
1356
1357
1358#define DOT11_OFDM_SIGNAL_EXTENSION 6
1359
1360#define PHY_CWMAX 1023
1361
1362#define DOT11_MAXNUMFRAGS 16
1363
1364
1365typedef struct d11cnt {
1366 uint32 txfrag;
1367 uint32 txmulti;
1368 uint32 txfail;
1369 uint32 txretry;
1370 uint32 txretrie;
1371 uint32 rxdup;
1372 uint32 txrts;
1373 uint32 txnocts;
1374 uint32 txnoack;
1375 uint32 rxfrag;
1376 uint32 rxmulti;
1377 uint32 rxcrc;
1378 uint32 txfrmsnt;
1379 uint32 rxundec;
1380} d11cnt_t;
1381
1382
1383#define BRCM_PROP_OUI "\x00\x90\x4C"
1384
1385
1386
1387#define BRCM_OUI "\x00\x10\x18"
1388
1389
1390BWL_PRE_PACKED_STRUCT struct brcm_ie {
1391 uint8 id;
1392 uint8 len;
1393 uint8 oui[3];
1394 uint8 ver;
1395 uint8 assoc;
1396 uint8 flags;
1397 uint8 flags1;
1398 uint16 amsdu_mtu_pref;
1399} BWL_POST_PACKED_STRUCT;
1400typedef struct brcm_ie brcm_ie_t;
1401#define BRCM_IE_LEN 11
1402#define BRCM_IE_VER 2
1403#define BRCM_IE_LEGACY_AES_VER 1
1404
1405
1406#ifdef WLAFTERBURNER
1407#define BRF_ABCAP 0x1
1408#define BRF_ABRQRD 0x2
1409#define BRF_ABCOUNTER_MASK 0xf0
1410#define BRF_ABCOUNTER_SHIFT 4
1411#endif
1412#define BRF_LZWDS 0x4
1413#define BRF_BLOCKACK 0x8
1414
1415
1416#define BRF1_AMSDU 0x1
1417#define BRF1_WMEPS 0x4
1418#define BRF1_PSOFIX 0x8
1419#define BRF1_RX_LARGE_AGG 0x10
1420#define BRF1_SOFTAP 0x40
1421
1422#ifdef WLAFTERBURNER
1423#define AB_WDS_TIMEOUT_MAX 15
1424#define AB_WDS_TIMEOUT_MIN 1
1425#endif
1426
1427#define AB_GUARDCOUNT 10
1428
1429
1430BWL_PRE_PACKED_STRUCT struct vndr_ie {
1431 uchar id;
1432 uchar len;
1433 uchar oui [3];
1434 uchar data [1];
1435} BWL_POST_PACKED_STRUCT;
1436typedef struct vndr_ie vndr_ie_t;
1437
1438#define VNDR_IE_HDR_LEN 2
1439#define VNDR_IE_MIN_LEN 3
1440#define VNDR_IE_MAX_LEN 256
1441
1442
1443#define MCSSET_LEN 16
1444#define MAX_MCS_NUM (128)
1445
1446BWL_PRE_PACKED_STRUCT struct ht_cap_ie {
1447 uint16 cap;
1448 uint8 params;
1449 uint8 supp_mcs[MCSSET_LEN];
1450 uint16 ext_htcap;
1451 uint32 txbf_cap;
1452 uint8 as_cap;
1453} BWL_POST_PACKED_STRUCT;
1454typedef struct ht_cap_ie ht_cap_ie_t;
1455
1456
1457
1458BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie {
1459 uint8 id;
1460 uint8 len;
1461 uint8 oui[3];
1462 uint8 type;
1463 ht_cap_ie_t cap_ie;
1464} BWL_POST_PACKED_STRUCT;
1465typedef struct ht_prop_cap_ie ht_prop_cap_ie_t;
1466
1467#define HT_PROP_IE_OVERHEAD 4
1468#define HT_CAP_IE_LEN 26
1469#define HT_CAP_IE_TYPE 51
1470
1471#define HT_CAP_LDPC_CODING 0x0001
1472#define HT_CAP_40MHZ 0x0002
1473#define HT_CAP_MIMO_PS_MASK 0x000C
1474#define HT_CAP_MIMO_PS_SHIFT 0x0002
1475#define HT_CAP_MIMO_PS_OFF 0x0003
1476#define HT_CAP_MIMO_PS_RTS 0x0001
1477#define HT_CAP_MIMO_PS_ON 0x0000
1478#define HT_CAP_GF 0x0010
1479#define HT_CAP_SHORT_GI_20 0x0020
1480#define HT_CAP_SHORT_GI_40 0x0040
1481#define HT_CAP_TX_STBC 0x0080
1482#define HT_CAP_RX_STBC_MASK 0x0300
1483#define HT_CAP_RX_STBC_SHIFT 8
1484#define HT_CAP_DELAYED_BA 0x0400
1485#define HT_CAP_MAX_AMSDU 0x0800
1486#define HT_CAP_DSSS_CCK 0x1000
1487#define HT_CAP_PSMP 0x2000
1488#define HT_CAP_40MHZ_INTOLERANT 0x4000
1489#define HT_CAP_LSIG_TXOP 0x8000
1490
1491#define HT_CAP_RX_STBC_NO 0x0
1492#define HT_CAP_RX_STBC_ONE_STREAM 0x1
1493#define HT_CAP_RX_STBC_TWO_STREAM 0x2
1494#define HT_CAP_RX_STBC_THREE_STREAM 0x3
1495
1496#define HT_MAX_AMSDU 7935
1497#define HT_MIN_AMSDU 3835
1498
1499#define HT_PARAMS_RX_FACTOR_MASK 0x03
1500#define HT_PARAMS_DENSITY_MASK 0x1C
1501#define HT_PARAMS_DENSITY_SHIFT 2
1502
1503
1504#define AMPDU_MAX_MPDU_DENSITY 7
1505#define AMPDU_RX_FACTOR_8K 0
1506#define AMPDU_RX_FACTOR_16K 1
1507#define AMPDU_RX_FACTOR_32K 2
1508#define AMPDU_RX_FACTOR_64K 3
1509#define AMPDU_RX_FACTOR_BASE 8*1024
1510
1511#define AMPDU_DELIMITER_LEN 4
1512#define AMPDU_DELIMITER_LEN_MAX 63
1513
1514BWL_PRE_PACKED_STRUCT struct ht_add_ie {
1515 uint8 ctl_ch;
1516 uint8 byte1;
1517 uint16 opmode;
1518 uint16 misc_bits;
1519 uint8 basic_mcs[MCSSET_LEN];
1520} BWL_POST_PACKED_STRUCT;
1521typedef struct ht_add_ie ht_add_ie_t;
1522
1523
1524
1525BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie {
1526 uint8 id;
1527 uint8 len;
1528 uint8 oui[3];
1529 uint8 type;
1530 ht_add_ie_t add_ie;
1531} BWL_POST_PACKED_STRUCT;
1532typedef struct ht_prop_add_ie ht_prop_add_ie_t;
1533
1534#define HT_ADD_IE_LEN 22
1535#define HT_ADD_IE_TYPE 52
1536
1537
1538#define HT_BW_ANY 0x04
1539#define HT_RIFS_PERMITTED 0x08
1540
1541
1542#define HT_OPMODE_MASK 0x0003
1543#define HT_OPMODE_SHIFT 0
1544#define HT_OPMODE_PURE 0x0000
1545#define HT_OPMODE_OPTIONAL 0x0001
1546#define HT_OPMODE_HT20IN40 0x0002
1547#define HT_OPMODE_MIXED 0x0003
1548#define HT_OPMODE_NONGF 0x0004
1549#define DOT11N_TXBURST 0x0008
1550#define DOT11N_OBSS_NONHT 0x0010
1551
1552
1553#define HT_BASIC_STBC_MCS 0x007f
1554#define HT_DUAL_STBC_PROT 0x0080
1555#define HT_SECOND_BCN 0x0100
1556#define HT_LSIG_TXOP 0x0200
1557#define HT_PCO_ACTIVE 0x0400
1558#define HT_PCO_PHASE 0x0800
1559
1560
1561#define DOT11N_2G_TXBURST_LIMIT 6160
1562#define DOT11N_5G_TXBURST_LIMIT 3080
1563
1564
1565#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \
1566 >> HT_OPMODE_SHIFT)
1567#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \
1568 == HT_OPMODE_MIXED)
1569#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \
1570 == HT_OPMODE_HT20IN40)
1571#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \
1572 == HT_OPMODE_OPTIONAL)
1573#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \
1574 HT_MIXEDMODE_PRESENT((add_ie)))
1575#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \
1576 == HT_OPMODE_NONGF)
1577#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \
1578 == DOT11N_TXBURST)
1579#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \
1580 == DOT11N_OBSS_NONHT)
1581
1582BWL_PRE_PACKED_STRUCT struct obss_params {
1583 uint16 passive_dwell;
1584 uint16 active_dwell;
1585 uint16 bss_widthscan_interval;
1586 uint16 passive_total;
1587 uint16 active_total;
1588 uint16 chanwidth_transition_dly;
1589 uint16 activity_threshold;
1590} BWL_POST_PACKED_STRUCT;
1591typedef struct obss_params obss_params_t;
1592
1593BWL_PRE_PACKED_STRUCT struct dot11_obss_ie {
1594 uint8 id;
1595 uint8 len;
1596 obss_params_t obss_params;
1597} BWL_POST_PACKED_STRUCT;
1598typedef struct dot11_obss_ie dot11_obss_ie_t;
1599#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t)
1600
1601
1602#define HT_CTRL_LA_TRQ 0x00000002
1603#define HT_CTRL_LA_MAI 0x0000003C
1604#define HT_CTRL_LA_MAI_SHIFT 2
1605#define HT_CTRL_LA_MAI_MRQ 0x00000004
1606#define HT_CTRL_LA_MAI_MSI 0x00000038
1607#define HT_CTRL_LA_MFSI 0x000001C0
1608#define HT_CTRL_LA_MFSI_SHIFT 6
1609#define HT_CTRL_LA_MFB_ASELC 0x0000FE00
1610#define HT_CTRL_LA_MFB_ASELC_SH 9
1611#define HT_CTRL_LA_ASELC_CMD 0x00000C00
1612#define HT_CTRL_LA_ASELC_DATA 0x0000F000
1613#define HT_CTRL_CAL_POS 0x00030000
1614#define HT_CTRL_CAL_SEQ 0x000C0000
1615#define HT_CTRL_CSI_STEERING 0x00C00000
1616#define HT_CTRL_CSI_STEER_SHIFT 22
1617#define HT_CTRL_CSI_STEER_NFB 0
1618#define HT_CTRL_CSI_STEER_CSI 1
1619#define HT_CTRL_CSI_STEER_NCOM 2
1620#define HT_CTRL_CSI_STEER_COM 3
1621#define HT_CTRL_NDP_ANNOUNCE 0x01000000
1622#define HT_CTRL_AC_CONSTRAINT 0x40000000
1623#define HT_CTRL_RDG_MOREPPDU 0x80000000
1624
1625#define HT_OPMODE_OPTIONAL 0x0001
1626#define HT_OPMODE_HT20IN40 0x0002
1627#define HT_OPMODE_MIXED 0x0003
1628#define HT_OPMODE_NONGF 0x0004
1629#define DOT11N_TXBURST 0x0008
1630#define DOT11N_OBSS_NONHT 0x0010
1631
1632
1633
1634#define WPA_OUI "\x00\x50\xF2"
1635#define WPA_OUI_LEN 3
1636#define WPA_OUI_TYPE 1
1637#define WPA_VERSION 1
1638#define WPA2_OUI "\x00\x0F\xAC"
1639#define WPA2_OUI_LEN 3
1640#define WPA2_VERSION 1
1641#define WPA2_VERSION_LEN 2
1642
1643
1644#define WPS_OUI "\x00\x50\xF2"
1645#define WPS_OUI_LEN 3
1646#define WPS_OUI_TYPE 4
1647
1648
1649#define WFA_OUI "\x50\x6F\x9A"
1650#define WFA_OUI_LEN 3
1651
1652#define WFA_OUI_TYPE_WPA 1
1653#define WFA_OUI_TYPE_WPS 4
1654#define WFA_OUI_TYPE_TPC 8
1655#define WFA_OUI_TYPE_P2P 9
1656
1657
1658#define RSN_AKM_NONE 0
1659#define RSN_AKM_UNSPECIFIED 1
1660#define RSN_AKM_PSK 2
1661#define RSN_AKM_FBT_1X 3
1662#define RSN_AKM_FBT_PSK 4
1663
1664
1665#define DOT11_MAX_DEFAULT_KEYS 4
1666#define DOT11_MAX_KEY_SIZE 32
1667#define DOT11_MAX_IV_SIZE 16
1668#define DOT11_EXT_IV_FLAG (1<<5)
1669#define DOT11_WPA_KEY_RSC_LEN 8
1670
1671#define WEP1_KEY_SIZE 5
1672#define WEP1_KEY_HEX_SIZE 10
1673#define WEP128_KEY_SIZE 13
1674#define WEP128_KEY_HEX_SIZE 26
1675#define TKIP_MIC_SIZE 8
1676#define TKIP_EOM_SIZE 7
1677#define TKIP_EOM_FLAG 0x5a
1678#define TKIP_KEY_SIZE 32
1679#define TKIP_MIC_AUTH_TX 16
1680#define TKIP_MIC_AUTH_RX 24
1681#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX
1682#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX
1683#define AES_KEY_SIZE 16
1684#define AES_MIC_SIZE 8
1685
1686
1687#define WCN_OUI "\x00\x50\xf2"
1688#define WCN_TYPE 4
1689
1690
1691
1692
1693
1694BWL_PRE_PACKED_STRUCT struct dot11_mdid_ie {
1695 uint8 id;
1696 uint8 len;
1697 uint16 mdid;
1698 uint8 cap;
1699} BWL_POST_PACKED_STRUCT;
1700typedef struct dot11_mdid_ie dot11_mdid_ie_t;
1701
1702#define FBT_MDID_CAP_OVERDS 0x01
1703#define FBT_MDID_CAP_RRP 0x02
1704
1705
1706BWL_PRE_PACKED_STRUCT struct dot11_ft_ie {
1707 uint8 id;
1708 uint8 len;
1709 uint16 mic_control;
1710 uint8 mic[16];
1711 uint8 anonce[32];
1712 uint8 snonce[32];
1713} BWL_POST_PACKED_STRUCT;
1714typedef struct dot11_ft_ie dot11_ft_ie_t;
1715
1716
1717BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie {
1718 uint8 id;
1719 uint8 len;
1720 uint16 key_info;
1721 uint8 key_len;
1722 uint8 rsc[8];
1723 uint8 data[1];
1724} BWL_POST_PACKED_STRUCT;
1725typedef struct dot11_gtk_ie dot11_gtk_ie_t;
1726
1727
1728
1729#include <packed_section_end.h>
1730
1731#endif
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h
new file mode 100644
index 00000000000..4ccfab02056
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h
@@ -0,0 +1,45 @@
1/*
2 * BT-AMP (BlueTooth Alternate Mac and Phy) 802.11 PAL (Protocol Adaptation Layer)
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: 802.11_bta.h,v 9.2 2008-10-28 23:27:13 Exp $
25*/
26
27#ifndef _802_11_BTA_H_
28#define _802_11_BTA_H_
29
30#define BT_SIG_SNAP_MPROT "\xAA\xAA\x03\x00\x19\x58"
31
32/* BT-AMP 802.11 PAL Protocols */
33#define BTA_PROT_L2CAP 1
34#define BTA_PROT_ACTIVITY_REPORT 2
35#define BTA_PROT_SECURITY 3
36#define BTA_PROT_LINK_SUPERVISION_REQUEST 4
37#define BTA_PROT_LINK_SUPERVISION_REPLY 5
38
39/* BT-AMP 802.11 PAL AMP_ASSOC Type IDs */
40#define BTA_TYPE_ID_MAC_ADDRESS 1
41#define BTA_TYPE_ID_PREFERRED_CHANNELS 2
42#define BTA_TYPE_ID_CONNECTED_CHANNELS 3
43#define BTA_TYPE_ID_CAPABILITIES 4
44#define BTA_TYPE_ID_VERSION 5
45#endif /* _802_11_bta_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h
new file mode 100644
index 00000000000..ce8ad083f28
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h
@@ -0,0 +1,131 @@
1/*
2 * 802.11e protocol header file
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: 802.11e.h,v 1.6 2008-12-01 22:55:11 Exp $
25 */
26
27#ifndef _802_11e_H_
28#define _802_11e_H_
29
30#ifndef _TYPEDEFS_H_
31#include <typedefs.h>
32#endif
33
34/* This marks the start of a packed structure section. */
35#include <packed_section_start.h>
36
37
38/* WME Traffic Specification (TSPEC) element */
39#define WME_TSPEC_HDR_LEN 2 /* WME TSPEC header length */
40#define WME_TSPEC_BODY_OFF 2 /* WME TSPEC body offset */
41
42#define WME_CATEGORY_CODE_OFFSET 0 /* WME Category code offset */
43#define WME_ACTION_CODE_OFFSET 1 /* WME Action code offset */
44#define WME_TOKEN_CODE_OFFSET 2 /* WME Token code offset */
45#define WME_STATUS_CODE_OFFSET 3 /* WME Status code offset */
46
47BWL_PRE_PACKED_STRUCT struct tsinfo {
48 uint8 octets[3];
49} BWL_POST_PACKED_STRUCT;
50
51typedef struct tsinfo tsinfo_t;
52
53/* 802.11e TSPEC IE */
54typedef BWL_PRE_PACKED_STRUCT struct tspec {
55 uint8 oui[DOT11_OUI_LEN]; /* WME_OUI */
56 uint8 type; /* WME_TYPE */
57 uint8 subtype; /* WME_SUBTYPE_TSPEC */
58 uint8 version; /* WME_VERSION */
59 tsinfo_t tsinfo; /* TS Info bit field */
60 uint16 nom_msdu_size; /* (Nominal or fixed) MSDU Size (bytes) */
61 uint16 max_msdu_size; /* Maximum MSDU Size (bytes) */
62 uint32 min_srv_interval; /* Minimum Service Interval (us) */
63 uint32 max_srv_interval; /* Maximum Service Interval (us) */
64 uint32 inactivity_interval; /* Inactivity Interval (us) */
65 uint32 suspension_interval; /* Suspension Interval (us) */
66 uint32 srv_start_time; /* Service Start Time (us) */
67 uint32 min_data_rate; /* Minimum Data Rate (bps) */
68 uint32 mean_data_rate; /* Mean Data Rate (bps) */
69 uint32 peak_data_rate; /* Peak Data Rate (bps) */
70 uint32 max_burst_size; /* Maximum Burst Size (bytes) */
71 uint32 delay_bound; /* Delay Bound (us) */
72 uint32 min_phy_rate; /* Minimum PHY Rate (bps) */
73 uint16 surplus_bw; /* Surplus Bandwidth Allowance (range 1.0-8.0) */
74 uint16 medium_time; /* Medium Time (32 us/s periods) */
75} BWL_POST_PACKED_STRUCT tspec_t;
76
77#define WME_TSPEC_LEN (sizeof(tspec_t)) /* not including 2-bytes of header */
78
79/* ts_info */
80/* 802.1D priority is duplicated - bits 13-11 AND bits 3-1 */
81#define TS_INFO_TID_SHIFT 1 /* TS info. TID shift */
82#define TS_INFO_TID_MASK (0xf << TS_INFO_TID_SHIFT) /* TS info. TID mask */
83#define TS_INFO_CONTENTION_SHIFT 7 /* TS info. contention shift */
84#define TS_INFO_CONTENTION_MASK (0x1 << TS_INFO_CONTENTION_SHIFT) /* TS info. contention mask */
85#define TS_INFO_DIRECTION_SHIFT 5 /* TS info. direction shift */
86#define TS_INFO_DIRECTION_MASK (0x3 << TS_INFO_DIRECTION_SHIFT) /* TS info. direction mask */
87#define TS_INFO_PSB_SHIFT 2 /* TS info. PSB bit Shift */
88#define TS_INFO_PSB_MASK (1 << TS_INFO_PSB_SHIFT) /* TS info. PSB mask */
89#define TS_INFO_UPLINK (0 << TS_INFO_DIRECTION_SHIFT) /* TS info. uplink */
90#define TS_INFO_DOWNLINK (1 << TS_INFO_DIRECTION_SHIFT) /* TS info. downlink */
91#define TS_INFO_BIDIRECTIONAL (3 << TS_INFO_DIRECTION_SHIFT) /* TS info. bidirectional */
92#define TS_INFO_USER_PRIO_SHIFT 3 /* TS info. user priority shift */
93/* TS info. user priority mask */
94#define TS_INFO_USER_PRIO_MASK (0x7 << TS_INFO_USER_PRIO_SHIFT)
95
96/* Macro to get/set bit(s) field in TSINFO */
97#define WLC_CAC_GET_TID(pt) ((((pt).octets[0]) & TS_INFO_TID_MASK) >> TS_INFO_TID_SHIFT)
98#define WLC_CAC_GET_DIR(pt) ((((pt).octets[0]) & \
99 TS_INFO_DIRECTION_MASK) >> TS_INFO_DIRECTION_SHIFT)
100#define WLC_CAC_GET_PSB(pt) ((((pt).octets[1]) & TS_INFO_PSB_MASK) >> TS_INFO_PSB_SHIFT)
101#define WLC_CAC_GET_USER_PRIO(pt) ((((pt).octets[1]) & \
102 TS_INFO_USER_PRIO_MASK) >> TS_INFO_USER_PRIO_SHIFT)
103
104#define WLC_CAC_SET_TID(pt, id) ((((pt).octets[0]) & (~TS_INFO_TID_MASK)) | \
105 ((id) << TS_INFO_TID_SHIFT))
106#define WLC_CAC_SET_USER_PRIO(pt, prio) ((((pt).octets[0]) & (~TS_INFO_USER_PRIO_MASK)) | \
107 ((prio) << TS_INFO_USER_PRIO_SHIFT))
108
109/* 802.11e QBSS Load IE */
110#define QBSS_LOAD_IE_LEN 5 /* QBSS Load IE length */
111#define QBSS_LOAD_AAC_OFF 3 /* AAC offset in IE */
112
113#define CAC_ADDTS_RESP_TIMEOUT 300 /* default ADDTS response timeout in ms */
114
115/* 802.11e ADDTS status code */
116#define DOT11E_STATUS_ADMISSION_ACCEPTED 0 /* TSPEC Admission accepted status */
117#define DOT11E_STATUS_ADDTS_INVALID_PARAM 1 /* TSPEC invalid parameter status */
118#define DOT11E_STATUS_ADDTS_REFUSED_NSBW 3 /* ADDTS refused (non-sufficient BW) */
119#define DOT11E_STATUS_ADDTS_REFUSED_AWHILE 47 /* ADDTS refused but could retry later */
120
121/* 802.11e DELTS status code */
122#define DOT11E_STATUS_QSTA_LEAVE_QBSS 36 /* STA leave QBSS */
123#define DOT11E_STATUS_END_TS 37 /* END TS */
124#define DOT11E_STATUS_UNKNOWN_TS 38 /* UNKNOWN TS */
125#define DOT11E_STATUS_QSTA_REQ_TIMEOUT 39 /* STA ADDTS request timeout */
126
127
128/* This marks the end of a packed structure section. */
129#include <packed_section_end.h>
130
131#endif /* _802_11e_CAC_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h
new file mode 100644
index 00000000000..cf206250246
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 1999-2011, Broadcom Corporation
3 *
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2 (the "GPL"),
7 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
8 * following added to such license:
9 *
10 * As a special exception, the copyright holders of this software give you
11 * permission to link this software with independent modules, and to copy and
12 * distribute the resulting executable under terms of your choice, provided that
13 * you also meet, for each linked independent module, the terms and conditions of
14 * the license of that module. An independent module is a module which is not
15 * derived from this software. The special exception does not apply to any
16 * modifications of the software.
17 *
18 * Notwithstanding the above, under no circumstances may you combine this
19 * software in any way with any other Broadcom software provided under a license
20 * other than the GPL, without Broadcom's express prior written consent.
21 *
22 * Fundamental types and constants relating to 802.1D
23 *
24 * $Id: 802.1d.h,v 9.3 2007-04-10 21:33:06 Exp $
25 */
26
27
28#ifndef _802_1_D_
29#define _802_1_D_
30
31
32#define PRIO_8021D_NONE 2
33#define PRIO_8021D_BK 1
34#define PRIO_8021D_BE 0
35#define PRIO_8021D_EE 3
36#define PRIO_8021D_CL 4
37#define PRIO_8021D_VI 5
38#define PRIO_8021D_VO 6
39#define PRIO_8021D_NC 7
40#define MAXPRIO 7
41#define NUMPRIO (MAXPRIO + 1)
42
43#define ALLPRIO -1
44
45
46#define PRIO2PREC(prio) \
47 (((prio) == PRIO_8021D_NONE || (prio) == PRIO_8021D_BE) ? ((prio^2)) : (prio))
48
49#endif
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
new file mode 100644
index 00000000000..46fa4c9f89e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h
@@ -0,0 +1,83 @@
1/*
2 * Broadcom Ethernettype protocol definitions
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bcmeth.h,v 9.12 2009-12-29 19:57:18 Exp $
25 */
26
27
28
29
30#ifndef _BCMETH_H_
31#define _BCMETH_H_
32
33#ifndef _TYPEDEFS_H_
34#include <typedefs.h>
35#endif
36
37
38#include <packed_section_start.h>
39
40
41
42
43
44
45
46#define BCMILCP_SUBTYPE_RATE 1
47#define BCMILCP_SUBTYPE_LINK 2
48#define BCMILCP_SUBTYPE_CSA 3
49#define BCMILCP_SUBTYPE_LARQ 4
50#define BCMILCP_SUBTYPE_VENDOR 5
51#define BCMILCP_SUBTYPE_FLH 17
52
53#define BCMILCP_SUBTYPE_VENDOR_LONG 32769
54#define BCMILCP_SUBTYPE_CERT 32770
55#define BCMILCP_SUBTYPE_SES 32771
56
57
58#define BCMILCP_BCM_SUBTYPE_RESERVED 0
59#define BCMILCP_BCM_SUBTYPE_EVENT 1
60#define BCMILCP_BCM_SUBTYPE_SES 2
61
62
63#define BCMILCP_BCM_SUBTYPE_DPT 4
64
65#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8
66#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0
67
68
69typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr
70{
71 uint16 subtype;
72 uint16 length;
73 uint8 version;
74 uint8 oui[3];
75
76 uint16 usr_subtype;
77} BWL_POST_PACKED_STRUCT bcmeth_hdr_t;
78
79
80
81#include <packed_section_end.h>
82
83#endif
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
new file mode 100644
index 00000000000..30ec848c40a
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h
@@ -0,0 +1,312 @@
1/*
2 * Broadcom Event protocol definitions
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * Dependencies: proto/bcmeth.h
25 *
26 * $Id: bcmevent.h,v 9.64.2.9 2011-02-01 06:24:21 Exp $
27 *
28 */
29
30
31
32
33#ifndef _BCMEVENT_H_
34#define _BCMEVENT_H_
35
36#ifndef _TYPEDEFS_H_
37#include <typedefs.h>
38#endif
39
40
41#include <packed_section_start.h>
42
43#define BCM_EVENT_MSG_VERSION 2
44#define BCM_MSG_IFNAME_MAX 16
45
46
47#define WLC_EVENT_MSG_LINK 0x01
48#define WLC_EVENT_MSG_FLUSHTXQ 0x02
49#define WLC_EVENT_MSG_GROUP 0x04
50#define WLC_EVENT_MSG_UNKBSS 0x08
51#define WLC_EVENT_MSG_UNKIF 0x10
52
53
54
55
56typedef BWL_PRE_PACKED_STRUCT struct
57{
58 uint16 version;
59 uint16 flags;
60 uint32 event_type;
61 uint32 status;
62 uint32 reason;
63 uint32 auth_type;
64 uint32 datalen;
65 struct ether_addr addr;
66 char ifname[BCM_MSG_IFNAME_MAX];
67} BWL_POST_PACKED_STRUCT wl_event_msg_v1_t;
68
69
70typedef BWL_PRE_PACKED_STRUCT struct
71{
72 uint16 version;
73 uint16 flags;
74 uint32 event_type;
75 uint32 status;
76 uint32 reason;
77 uint32 auth_type;
78 uint32 datalen;
79 struct ether_addr addr;
80 char ifname[BCM_MSG_IFNAME_MAX];
81 uint8 ifidx;
82 uint8 bsscfgidx;
83} BWL_POST_PACKED_STRUCT wl_event_msg_t;
84
85
86typedef BWL_PRE_PACKED_STRUCT struct bcm_event {
87 struct ether_header eth;
88 bcmeth_hdr_t bcm_hdr;
89 wl_event_msg_t event;
90
91} BWL_POST_PACKED_STRUCT bcm_event_t;
92
93#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header))
94
95
96#define WLC_E_SET_SSID 0
97#define WLC_E_JOIN 1
98#define WLC_E_START 2
99#define WLC_E_AUTH 3
100#define WLC_E_AUTH_IND 4
101#define WLC_E_DEAUTH 5
102#define WLC_E_DEAUTH_IND 6
103#define WLC_E_ASSOC 7
104#define WLC_E_ASSOC_IND 8
105#define WLC_E_REASSOC 9
106#define WLC_E_REASSOC_IND 10
107#define WLC_E_DISASSOC 11
108#define WLC_E_DISASSOC_IND 12
109#define WLC_E_QUIET_START 13
110#define WLC_E_QUIET_END 14
111#define WLC_E_BEACON_RX 15
112#define WLC_E_LINK 16
113#define WLC_E_MIC_ERROR 17
114#define WLC_E_NDIS_LINK 18
115#define WLC_E_ROAM 19
116#define WLC_E_TXFAIL 20
117#define WLC_E_PMKID_CACHE 21
118#define WLC_E_RETROGRADE_TSF 22
119#define WLC_E_PRUNE 23
120#define WLC_E_AUTOAUTH 24
121#define WLC_E_EAPOL_MSG 25
122#define WLC_E_SCAN_COMPLETE 26
123#define WLC_E_ADDTS_IND 27
124#define WLC_E_DELTS_IND 28
125#define WLC_E_BCNSENT_IND 29
126#define WLC_E_BCNRX_MSG 30
127#define WLC_E_BCNLOST_MSG 31
128#define WLC_E_ROAM_PREP 32
129#define WLC_E_PFN_NET_FOUND 33
130#define WLC_E_PFN_NET_LOST 34
131#define WLC_E_RESET_COMPLETE 35
132#define WLC_E_JOIN_START 36
133#define WLC_E_ROAM_START 37
134#define WLC_E_ASSOC_START 38
135#define WLC_E_IBSS_ASSOC 39
136#define WLC_E_RADIO 40
137#define WLC_E_PSM_WATCHDOG 41
138#define WLC_E_PROBREQ_MSG 44
139#define WLC_E_SCAN_CONFIRM_IND 45
140#define WLC_E_PSK_SUP 46
141#define WLC_E_COUNTRY_CODE_CHANGED 47
142#define WLC_E_EXCEEDED_MEDIUM_TIME 48
143#define WLC_E_ICV_ERROR 49
144#define WLC_E_UNICAST_DECODE_ERROR 50
145#define WLC_E_MULTICAST_DECODE_ERROR 51
146#define WLC_E_TRACE 52
147#define WLC_E_BTA_HCI_EVENT 53
148#define WLC_E_IF 54
149#ifdef WLP2P
150#define WLC_E_P2P_DISC_LISTEN_COMPLETE 55
151#endif
152#define WLC_E_RSSI 56
153#define WLC_E_PFN_SCAN_COMPLETE 57
154#define WLC_E_EXTLOG_MSG 58
155#define WLC_E_ACTION_FRAME 59
156#define WLC_E_ACTION_FRAME_COMPLETE 60
157#define WLC_E_PRE_ASSOC_IND 61
158#define WLC_E_PRE_REASSOC_IND 62
159#define WLC_E_CHANNEL_ADOPTED 63
160#define WLC_E_AP_STARTED 64
161#define WLC_E_DFS_AP_STOP 65
162#define WLC_E_DFS_AP_RESUME 66
163#define WLC_E_WAI_STA_EVENT 67
164#define WLC_E_WAI_MSG 68
165#define WLC_E_ESCAN_RESULT 69
166#define WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70
167#if defined(WLP2P)
168#define WLC_E_PROBRESP_MSG 71
169#define WLC_E_P2P_PROBREQ_MSG 72
170#endif
171#define WLC_E_DCS_REQUEST 73
172
173#define WLC_E_FIFO_CREDIT_MAP 74
174
175#define WLC_E_ACTION_FRAME_RX 75
176#define WLC_E_WAKE_EVENT 76
177#define WLC_E_RM_COMPLETE 77
178#define WLC_E_HTSFSYNC 78
179#define WLC_E_OVERLAY_REQ 79
180#define WLC_E_CSA_COMPLETE_IND 80
181#define WLC_E_EXCESS_PM_WAKE_EVENT 81
182#define WLC_E_PFN_SCAN_NONE 82
183#define WLC_E_PFN_SCAN_ALLGONE 83
184#define WLC_E_GTK_PLUMBED 84
185#define WLC_E_LAST 85
186
187
188typedef struct {
189 uint event;
190 const char *name;
191} bcmevent_name_t;
192
193extern const bcmevent_name_t bcmevent_names[];
194extern const int bcmevent_names_size;
195
196
197#define WLC_E_STATUS_SUCCESS 0
198#define WLC_E_STATUS_FAIL 1
199#define WLC_E_STATUS_TIMEOUT 2
200#define WLC_E_STATUS_NO_NETWORKS 3
201#define WLC_E_STATUS_ABORT 4
202#define WLC_E_STATUS_NO_ACK 5
203#define WLC_E_STATUS_UNSOLICITED 6
204#define WLC_E_STATUS_ATTEMPT 7
205#define WLC_E_STATUS_PARTIAL 8
206#define WLC_E_STATUS_NEWSCAN 9
207#define WLC_E_STATUS_NEWASSOC 10
208#define WLC_E_STATUS_11HQUIET 11
209#define WLC_E_STATUS_SUPPRESS 12
210#define WLC_E_STATUS_NOCHANS 13
211#define WLC_E_STATUS_CS_ABORT 15
212#define WLC_E_STATUS_ERROR 16
213
214
215#define WLC_E_REASON_INITIAL_ASSOC 0
216#define WLC_E_REASON_LOW_RSSI 1
217#define WLC_E_REASON_DEAUTH 2
218#define WLC_E_REASON_DISASSOC 3
219#define WLC_E_REASON_BCNS_LOST 4
220#define WLC_E_REASON_MINTXRATE 9
221#define WLC_E_REASON_TXFAIL 10
222
223
224#define WLC_E_REASON_FAST_ROAM_FAILED 5
225#define WLC_E_REASON_DIRECTED_ROAM 6
226#define WLC_E_REASON_TSPEC_REJECTED 7
227#define WLC_E_REASON_BETTER_AP 8
228
229
230#define WLC_E_PRUNE_ENCR_MISMATCH 1
231#define WLC_E_PRUNE_BCAST_BSSID 2
232#define WLC_E_PRUNE_MAC_DENY 3
233#define WLC_E_PRUNE_MAC_NA 4
234#define WLC_E_PRUNE_REG_PASSV 5
235#define WLC_E_PRUNE_SPCT_MGMT 6
236#define WLC_E_PRUNE_RADAR 7
237#define WLC_E_RSN_MISMATCH 8
238#define WLC_E_PRUNE_NO_COMMON_RATES 9
239#define WLC_E_PRUNE_BASIC_RATES 10
240#define WLC_E_PRUNE_CIPHER_NA 12
241#define WLC_E_PRUNE_KNOWN_STA 13
242#define WLC_E_PRUNE_WDS_PEER 15
243#define WLC_E_PRUNE_QBSS_LOAD 16
244#define WLC_E_PRUNE_HOME_AP 17
245
246
247#define WLC_E_SUP_OTHER 0
248#define WLC_E_SUP_DECRYPT_KEY_DATA 1
249#define WLC_E_SUP_BAD_UCAST_WEP128 2
250#define WLC_E_SUP_BAD_UCAST_WEP40 3
251#define WLC_E_SUP_UNSUP_KEY_LEN 4
252#define WLC_E_SUP_PW_KEY_CIPHER 5
253#define WLC_E_SUP_MSG3_TOO_MANY_IE 6
254#define WLC_E_SUP_MSG3_IE_MISMATCH 7
255#define WLC_E_SUP_NO_INSTALL_FLAG 8
256#define WLC_E_SUP_MSG3_NO_GTK 9
257#define WLC_E_SUP_GRP_KEY_CIPHER 10
258#define WLC_E_SUP_GRP_MSG1_NO_GTK 11
259#define WLC_E_SUP_GTK_DECRYPT_FAIL 12
260#define WLC_E_SUP_SEND_FAIL 13
261#define WLC_E_SUP_DEAUTH 14
262#define WLC_E_SUP_WPA_PSK_TMO 15
263
264
265
266typedef BWL_PRE_PACKED_STRUCT struct wl_event_rx_frame_data {
267 uint16 version;
268 uint16 channel;
269 int32 rssi;
270 uint32 mactime;
271 uint32 rate;
272} BWL_POST_PACKED_STRUCT wl_event_rx_frame_data_t;
273
274#define BCM_RX_FRAME_DATA_VERSION 1
275
276
277typedef struct wl_event_data_if {
278 uint8 ifidx;
279 uint8 opcode;
280 uint8 reserved;
281 uint8 bssidx;
282 uint8 role;
283} wl_event_data_if_t;
284
285
286#define WLC_E_IF_ADD 1
287#define WLC_E_IF_DEL 2
288#define WLC_E_IF_CHANGE 3
289
290
291#define WLC_E_IF_ROLE_STA 0
292#define WLC_E_IF_ROLE_AP 1
293#define WLC_E_IF_ROLE_WDS 2
294#define WLC_E_IF_ROLE_P2P_GO 3
295#define WLC_E_IF_ROLE_P2P_CLIENT 4
296#define WLC_E_IF_ROLE_BTA_CREATOR 5
297#define WLC_E_IF_ROLE_BTA_ACCEPTOR 6
298
299
300#define WLC_E_LINK_BCN_LOSS 1
301#define WLC_E_LINK_DISASSOC 2
302#define WLC_E_LINK_ASSOC_REC 3
303#define WLC_E_LINK_BSSCFG_DIS 4
304
305
306#define WLC_E_OVL_DOWNLOAD 0
307#define WLC_E_OVL_UPDATE_IND 1
308
309
310#include <packed_section_end.h>
311
312#endif
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h
new file mode 100644
index 00000000000..8a8f3146d56
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h
@@ -0,0 +1,154 @@
1/*
2 * Copyright (C) 1999-2011, Broadcom Corporation
3 *
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2 (the "GPL"),
7 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
8 * following added to such license:
9 *
10 * As a special exception, the copyright holders of this software give you
11 * permission to link this software with independent modules, and to copy and
12 * distribute the resulting executable under terms of your choice, provided that
13 * you also meet, for each linked independent module, the terms and conditions of
14 * the license of that module. An independent module is a module which is not
15 * derived from this software. The special exception does not apply to any
16 * modifications of the software.
17 *
18 * Notwithstanding the above, under no circumstances may you combine this
19 * software in any way with any other Broadcom software provided under a license
20 * other than the GPL, without Broadcom's express prior written consent.
21 *
22 * Fundamental constants relating to IP Protocol
23 *
24 * $Id: bcmip.h,v 9.19 2009-11-10 20:08:33 Exp $
25 */
26
27
28#ifndef _bcmip_h_
29#define _bcmip_h_
30
31#ifndef _TYPEDEFS_H_
32#include <typedefs.h>
33#endif
34
35
36#include <packed_section_start.h>
37
38
39
40#define IP_VER_OFFSET 0x0
41#define IP_VER_MASK 0xf0
42#define IP_VER_SHIFT 4
43#define IP_VER_4 4
44#define IP_VER_6 6
45
46#define IP_VER(ip_body) \
47 ((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT)
48
49#define IP_PROT_ICMP 0x1
50#define IP_PROT_TCP 0x6
51#define IP_PROT_UDP 0x11
52
53
54#define IPV4_VER_HL_OFFSET 0
55#define IPV4_TOS_OFFSET 1
56#define IPV4_PKTLEN_OFFSET 2
57#define IPV4_PKTFLAG_OFFSET 6
58#define IPV4_PROT_OFFSET 9
59#define IPV4_CHKSUM_OFFSET 10
60#define IPV4_SRC_IP_OFFSET 12
61#define IPV4_DEST_IP_OFFSET 16
62#define IPV4_OPTIONS_OFFSET 20
63
64
65#define IPV4_VER_MASK 0xf0
66#define IPV4_VER_SHIFT 4
67
68#define IPV4_HLEN_MASK 0x0f
69#define IPV4_HLEN(ipv4_body) (4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK))
70
71#define IPV4_ADDR_LEN 4
72
73#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \
74 ((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0)
75
76#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \
77 ((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff)
78
79#define IPV4_TOS_DSCP_MASK 0xfc
80#define IPV4_TOS_DSCP_SHIFT 2
81
82#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET])
83
84#define IPV4_TOS_PREC_MASK 0xe0
85#define IPV4_TOS_PREC_SHIFT 5
86
87#define IPV4_TOS_LOWDELAY 0x10
88#define IPV4_TOS_THROUGHPUT 0x8
89#define IPV4_TOS_RELIABILITY 0x4
90
91#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET])
92
93#define IPV4_FRAG_RESV 0x8000
94#define IPV4_FRAG_DONT 0x4000
95#define IPV4_FRAG_MORE 0x2000
96#define IPV4_FRAG_OFFSET_MASK 0x1fff
97
98#define IPV4_ADDR_STR_LEN 16
99
100
101BWL_PRE_PACKED_STRUCT struct ipv4_addr {
102 uint8 addr[IPV4_ADDR_LEN];
103} BWL_POST_PACKED_STRUCT;
104
105BWL_PRE_PACKED_STRUCT struct ipv4_hdr {
106 uint8 version_ihl;
107 uint8 tos;
108 uint16 tot_len;
109 uint16 id;
110 uint16 frag;
111 uint8 ttl;
112 uint8 prot;
113 uint16 hdr_chksum;
114 uint8 src_ip[IPV4_ADDR_LEN];
115 uint8 dst_ip[IPV4_ADDR_LEN];
116} BWL_POST_PACKED_STRUCT;
117
118
119#define IPV6_PAYLOAD_LEN_OFFSET 4
120#define IPV6_NEXT_HDR_OFFSET 6
121#define IPV6_HOP_LIMIT_OFFSET 7
122#define IPV6_SRC_IP_OFFSET 8
123#define IPV6_DEST_IP_OFFSET 24
124
125
126#define IPV6_TRAFFIC_CLASS(ipv6_body) \
127 (((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \
128 ((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4))
129
130#define IPV6_FLOW_LABEL(ipv6_body) \
131 (((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \
132 (((uint8 *)(ipv6_body))[2] << 8) | \
133 (((uint8 *)(ipv6_body))[3]))
134
135#define IPV6_PAYLOAD_LEN(ipv6_body) \
136 ((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \
137 ((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1])
138
139#define IPV6_NEXT_HDR(ipv6_body) \
140 (((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET])
141
142#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body)
143
144#define IPV6_ADDR_LEN 16
145
146
147#define IP_TOS46(ip_body) \
148 (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \
149 IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0)
150
151
152#include <packed_section_end.h>
153
154#endif
diff --git a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h
new file mode 100644
index 00000000000..89c11817915
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h
@@ -0,0 +1,442 @@
1/*
2 * BT-AMP (BlueTooth Alternate Mac and Phy) HCI (Host/Controller Interface)
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: bt_amp_hci.h,v 9.14.8.2 2010-09-10 18:37:47 Exp $
25*/
26
27#ifndef _bt_amp_hci_h
28#define _bt_amp_hci_h
29
30/* This marks the start of a packed structure section. */
31#include <packed_section_start.h>
32
33
34/* AMP HCI CMD packet format */
35typedef BWL_PRE_PACKED_STRUCT struct amp_hci_cmd {
36 uint16 opcode;
37 uint8 plen;
38 uint8 parms[1];
39} BWL_POST_PACKED_STRUCT amp_hci_cmd_t;
40
41#define HCI_CMD_PREAMBLE_SIZE OFFSETOF(amp_hci_cmd_t, parms)
42#define HCI_CMD_DATA_SIZE 255
43
44/* AMP HCI CMD opcode layout */
45#define HCI_CMD_OPCODE(ogf, ocf) ((((ogf) & 0x3F) << 10) | ((ocf) & 0x03FF))
46#define HCI_CMD_OGF(opcode) ((uint8)(((opcode) >> 10) & 0x3F))
47#define HCI_CMD_OCF(opcode) ((opcode) & 0x03FF)
48
49/* AMP HCI command opcodes */
50#define HCI_Read_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0001)
51#define HCI_Reset_Failed_Contact_Counter HCI_CMD_OPCODE(0x05, 0x0002)
52#define HCI_Read_Link_Quality HCI_CMD_OPCODE(0x05, 0x0003)
53#define HCI_Read_Local_AMP_Info HCI_CMD_OPCODE(0x05, 0x0009)
54#define HCI_Read_Local_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000A)
55#define HCI_Write_Remote_AMP_ASSOC HCI_CMD_OPCODE(0x05, 0x000B)
56#define HCI_Create_Physical_Link HCI_CMD_OPCODE(0x01, 0x0035)
57#define HCI_Accept_Physical_Link_Request HCI_CMD_OPCODE(0x01, 0x0036)
58#define HCI_Disconnect_Physical_Link HCI_CMD_OPCODE(0x01, 0x0037)
59#define HCI_Create_Logical_Link HCI_CMD_OPCODE(0x01, 0x0038)
60#define HCI_Accept_Logical_Link HCI_CMD_OPCODE(0x01, 0x0039)
61#define HCI_Disconnect_Logical_Link HCI_CMD_OPCODE(0x01, 0x003A)
62#define HCI_Logical_Link_Cancel HCI_CMD_OPCODE(0x01, 0x003B)
63#define HCI_Flow_Spec_Modify HCI_CMD_OPCODE(0x01, 0x003C)
64#define HCI_Write_Flow_Control_Mode HCI_CMD_OPCODE(0x01, 0x0067)
65#define HCI_Read_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x0069)
66#define HCI_Write_Best_Effort_Flush_Timeout HCI_CMD_OPCODE(0x01, 0x006A)
67#define HCI_Short_Range_Mode HCI_CMD_OPCODE(0x01, 0x006B)
68#define HCI_Reset HCI_CMD_OPCODE(0x03, 0x0003)
69#define HCI_Read_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0015)
70#define HCI_Write_Connection_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0016)
71#define HCI_Read_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0036)
72#define HCI_Write_Link_Supervision_Timeout HCI_CMD_OPCODE(0x03, 0x0037)
73#define HCI_Enhanced_Flush HCI_CMD_OPCODE(0x03, 0x005F)
74#define HCI_Read_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0061)
75#define HCI_Write_Logical_Link_Accept_Timeout HCI_CMD_OPCODE(0x03, 0x0062)
76#define HCI_Set_Event_Mask_Page_2 HCI_CMD_OPCODE(0x03, 0x0063)
77#define HCI_Read_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0064)
78#define HCI_Write_Location_Data_Command HCI_CMD_OPCODE(0x03, 0x0065)
79#define HCI_Read_Local_Version_Info HCI_CMD_OPCODE(0x04, 0x0001)
80#define HCI_Read_Local_Supported_Commands HCI_CMD_OPCODE(0x04, 0x0002)
81#define HCI_Read_Buffer_Size HCI_CMD_OPCODE(0x04, 0x0005)
82#define HCI_Read_Data_Block_Size HCI_CMD_OPCODE(0x04, 0x000A)
83
84/* AMP HCI command parameters */
85typedef BWL_PRE_PACKED_STRUCT struct read_local_cmd_parms {
86 uint8 plh;
87 uint8 offset[2]; /* length so far */
88 uint8 max_remote[2];
89} BWL_POST_PACKED_STRUCT read_local_cmd_parms_t;
90
91typedef BWL_PRE_PACKED_STRUCT struct write_remote_cmd_parms {
92 uint8 plh;
93 uint8 offset[2];
94 uint8 len[2];
95 uint8 frag[1];
96} BWL_POST_PACKED_STRUCT write_remote_cmd_parms_t;
97
98typedef BWL_PRE_PACKED_STRUCT struct phy_link_cmd_parms {
99 uint8 plh;
100 uint8 key_length;
101 uint8 key_type;
102 uint8 key[1];
103} BWL_POST_PACKED_STRUCT phy_link_cmd_parms_t;
104
105typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_cmd_parms {
106 uint8 plh;
107 uint8 reason;
108} BWL_POST_PACKED_STRUCT dis_phy_link_cmd_parms_t;
109
110typedef BWL_PRE_PACKED_STRUCT struct log_link_cmd_parms {
111 uint8 plh;
112 uint8 txflow[16];
113 uint8 rxflow[16];
114} BWL_POST_PACKED_STRUCT log_link_cmd_parms_t;
115
116typedef BWL_PRE_PACKED_STRUCT struct ext_flow_spec {
117 uint8 id;
118 uint8 service_type;
119 uint8 max_sdu[2];
120 uint8 sdu_ia_time[4];
121 uint8 access_latency[4];
122 uint8 flush_timeout[4];
123} BWL_POST_PACKED_STRUCT ext_flow_spec_t;
124
125typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_cmd_parms {
126 uint8 plh;
127 uint8 tx_fs_ID;
128} BWL_POST_PACKED_STRUCT log_link_cancel_cmd_parms_t;
129
130typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_cmd_parms {
131 uint8 llh[2];
132 uint8 txflow[16];
133 uint8 rxflow[16];
134} BWL_POST_PACKED_STRUCT flow_spec_mod_cmd_parms_t;
135
136typedef BWL_PRE_PACKED_STRUCT struct plh_pad {
137 uint8 plh;
138 uint8 pad;
139} BWL_POST_PACKED_STRUCT plh_pad_t;
140
141typedef BWL_PRE_PACKED_STRUCT union hci_handle {
142 uint16 bredr;
143 plh_pad_t amp;
144} BWL_POST_PACKED_STRUCT hci_handle_t;
145
146typedef BWL_PRE_PACKED_STRUCT struct ls_to_cmd_parms {
147 hci_handle_t handle;
148 uint8 timeout[2];
149} BWL_POST_PACKED_STRUCT ls_to_cmd_parms_t;
150
151typedef BWL_PRE_PACKED_STRUCT struct befto_cmd_parms {
152 uint8 llh[2];
153 uint8 befto[4];
154} BWL_POST_PACKED_STRUCT befto_cmd_parms_t;
155
156typedef BWL_PRE_PACKED_STRUCT struct srm_cmd_parms {
157 uint8 plh;
158 uint8 srm;
159} BWL_POST_PACKED_STRUCT srm_cmd_parms_t;
160
161typedef BWL_PRE_PACKED_STRUCT struct ld_cmd_parms {
162 uint8 ld_aware;
163 uint8 ld[2];
164 uint8 ld_opts;
165 uint8 l_opts;
166} BWL_POST_PACKED_STRUCT ld_cmd_parms_t;
167
168typedef BWL_PRE_PACKED_STRUCT struct eflush_cmd_parms {
169 uint8 llh[2];
170 uint8 packet_type;
171} BWL_POST_PACKED_STRUCT eflush_cmd_parms_t;
172
173/* Generic AMP extended flow spec service types */
174#define EFS_SVCTYPE_NO_TRAFFIC 0
175#define EFS_SVCTYPE_BEST_EFFORT 1
176#define EFS_SVCTYPE_GUARANTEED 2
177
178/* AMP HCI event packet format */
179typedef BWL_PRE_PACKED_STRUCT struct amp_hci_event {
180 uint8 ecode;
181 uint8 plen;
182 uint8 parms[1];
183} BWL_POST_PACKED_STRUCT amp_hci_event_t;
184
185#define HCI_EVT_PREAMBLE_SIZE OFFSETOF(amp_hci_event_t, parms)
186
187/* AMP HCI event codes */
188#define HCI_Command_Complete 0x0E
189#define HCI_Command_Status 0x0F
190#define HCI_Flush_Occurred 0x11
191#define HCI_Enhanced_Flush_Complete 0x39
192#define HCI_Physical_Link_Complete 0x40
193#define HCI_Channel_Select 0x41
194#define HCI_Disconnect_Physical_Link_Complete 0x42
195#define HCI_Logical_Link_Complete 0x45
196#define HCI_Disconnect_Logical_Link_Complete 0x46
197#define HCI_Flow_Spec_Modify_Complete 0x47
198#define HCI_Number_of_Completed_Data_Blocks 0x48
199#define HCI_Short_Range_Mode_Change_Complete 0x4C
200#define HCI_Status_Change_Event 0x4D
201#define HCI_Vendor_Specific 0xFF
202
203/* AMP HCI event mask bit positions */
204#define HCI_Physical_Link_Complete_Event_Mask 0x0001
205#define HCI_Channel_Select_Event_Mask 0x0002
206#define HCI_Disconnect_Physical_Link_Complete_Event_Mask 0x0004
207#define HCI_Logical_Link_Complete_Event_Mask 0x0020
208#define HCI_Disconnect_Logical_Link_Complete_Event_Mask 0x0040
209#define HCI_Flow_Spec_Modify_Complete_Event_Mask 0x0080
210#define HCI_Number_of_Completed_Data_Blocks_Event_Mask 0x0100
211#define HCI_Short_Range_Mode_Change_Complete_Event_Mask 0x1000
212#define HCI_Status_Change_Event_Mask 0x2000
213#define HCI_All_Event_Mask 0x31e7
214
215/* AMP HCI event parameters */
216typedef BWL_PRE_PACKED_STRUCT struct cmd_status_parms {
217 uint8 status;
218 uint8 cmdpkts;
219 uint16 opcode;
220} BWL_POST_PACKED_STRUCT cmd_status_parms_t;
221
222typedef BWL_PRE_PACKED_STRUCT struct cmd_complete_parms {
223 uint8 cmdpkts;
224 uint16 opcode;
225 uint8 parms[1];
226} BWL_POST_PACKED_STRUCT cmd_complete_parms_t;
227
228typedef BWL_PRE_PACKED_STRUCT struct flush_occurred_evt_parms {
229 uint16 handle;
230} BWL_POST_PACKED_STRUCT flush_occurred_evt_parms_t;
231
232typedef BWL_PRE_PACKED_STRUCT struct write_remote_evt_parms {
233 uint8 status;
234 uint8 plh;
235} BWL_POST_PACKED_STRUCT write_remote_evt_parms_t;
236
237typedef BWL_PRE_PACKED_STRUCT struct read_local_evt_parms {
238 uint8 status;
239 uint8 plh;
240 uint16 len;
241 uint8 frag[1];
242} BWL_POST_PACKED_STRUCT read_local_evt_parms_t;
243
244typedef BWL_PRE_PACKED_STRUCT struct read_local_info_evt_parms {
245 uint8 status;
246 uint8 AMP_status;
247 uint32 bandwidth;
248 uint32 gbandwidth;
249 uint32 latency;
250 uint32 PDU_size;
251 uint8 ctrl_type;
252 uint16 PAL_cap;
253 uint16 AMP_ASSOC_len;
254 uint32 max_flush_timeout;
255 uint32 be_flush_timeout;
256} BWL_POST_PACKED_STRUCT read_local_info_evt_parms_t;
257
258typedef BWL_PRE_PACKED_STRUCT struct log_link_evt_parms {
259 uint8 status;
260 uint16 llh;
261 uint8 plh;
262 uint8 tx_fs_ID;
263} BWL_POST_PACKED_STRUCT log_link_evt_parms_t;
264
265typedef BWL_PRE_PACKED_STRUCT struct disc_log_link_evt_parms {
266 uint8 status;
267 uint16 llh;
268 uint8 reason;
269} BWL_POST_PACKED_STRUCT disc_log_link_evt_parms_t;
270
271typedef BWL_PRE_PACKED_STRUCT struct log_link_cancel_evt_parms {
272 uint8 status;
273 uint8 plh;
274 uint8 tx_fs_ID;
275} BWL_POST_PACKED_STRUCT log_link_cancel_evt_parms_t;
276
277typedef BWL_PRE_PACKED_STRUCT struct flow_spec_mod_evt_parms {
278 uint8 status;
279 uint16 llh;
280} BWL_POST_PACKED_STRUCT flow_spec_mod_evt_parms_t;
281
282typedef BWL_PRE_PACKED_STRUCT struct phy_link_evt_parms {
283 uint8 status;
284 uint8 plh;
285} BWL_POST_PACKED_STRUCT phy_link_evt_parms_t;
286
287typedef BWL_PRE_PACKED_STRUCT struct dis_phy_link_evt_parms {
288 uint8 status;
289 uint8 plh;
290 uint8 reason;
291} BWL_POST_PACKED_STRUCT dis_phy_link_evt_parms_t;
292
293typedef BWL_PRE_PACKED_STRUCT struct read_ls_to_evt_parms {
294 uint8 status;
295 hci_handle_t handle;
296 uint16 timeout;
297} BWL_POST_PACKED_STRUCT read_ls_to_evt_parms_t;
298
299typedef BWL_PRE_PACKED_STRUCT struct read_lla_ca_to_evt_parms {
300 uint8 status;
301 uint16 timeout;
302} BWL_POST_PACKED_STRUCT read_lla_ca_to_evt_parms_t;
303
304typedef BWL_PRE_PACKED_STRUCT struct read_data_block_size_evt_parms {
305 uint8 status;
306 uint16 ACL_pkt_len;
307 uint16 data_block_len;
308 uint16 data_block_num;
309} BWL_POST_PACKED_STRUCT read_data_block_size_evt_parms_t;
310
311typedef BWL_PRE_PACKED_STRUCT struct data_blocks {
312 uint16 handle;
313 uint16 pkts;
314 uint16 blocks;
315} BWL_POST_PACKED_STRUCT data_blocks_t;
316
317typedef BWL_PRE_PACKED_STRUCT struct num_completed_data_blocks_evt_parms {
318 uint16 num_blocks;
319 uint8 num_handles;
320 data_blocks_t completed[1];
321} BWL_POST_PACKED_STRUCT num_completed_data_blocks_evt_parms_t;
322
323typedef BWL_PRE_PACKED_STRUCT struct befto_evt_parms {
324 uint8 status;
325 uint32 befto;
326} BWL_POST_PACKED_STRUCT befto_evt_parms_t;
327
328typedef BWL_PRE_PACKED_STRUCT struct srm_evt_parms {
329 uint8 status;
330 uint8 plh;
331 uint8 srm;
332} BWL_POST_PACKED_STRUCT srm_evt_parms_t;
333
334typedef BWL_PRE_PACKED_STRUCT struct contact_counter_evt_parms {
335 uint8 status;
336 uint8 llh[2];
337 uint16 counter;
338} BWL_POST_PACKED_STRUCT contact_counter_evt_parms_t;
339
340typedef BWL_PRE_PACKED_STRUCT struct contact_counter_reset_evt_parms {
341 uint8 status;
342 uint8 llh[2];
343} BWL_POST_PACKED_STRUCT contact_counter_reset_evt_parms_t;
344
345typedef BWL_PRE_PACKED_STRUCT struct read_linkq_evt_parms {
346 uint8 status;
347 hci_handle_t handle;
348 uint8 link_quality;
349} BWL_POST_PACKED_STRUCT read_linkq_evt_parms_t;
350
351typedef BWL_PRE_PACKED_STRUCT struct ld_evt_parms {
352 uint8 status;
353 uint8 ld_aware;
354 uint8 ld[2];
355 uint8 ld_opts;
356 uint8 l_opts;
357} BWL_POST_PACKED_STRUCT ld_evt_parms_t;
358
359typedef BWL_PRE_PACKED_STRUCT struct eflush_complete_evt_parms {
360 uint16 handle;
361} BWL_POST_PACKED_STRUCT eflush_complete_evt_parms_t;
362
363typedef BWL_PRE_PACKED_STRUCT struct vendor_specific_evt_parms {
364 uint8 len;
365 uint8 parms[1];
366} BWL_POST_PACKED_STRUCT vendor_specific_evt_parms_t;
367
368typedef BWL_PRE_PACKED_STRUCT struct local_version_info_evt_parms {
369 uint8 status;
370 uint8 hci_version;
371 uint16 hci_revision;
372 uint8 pal_version;
373 uint16 mfg_name;
374 uint16 pal_subversion;
375} BWL_POST_PACKED_STRUCT local_version_info_evt_parms_t;
376
377#define MAX_SUPPORTED_CMD_BYTE 64
378typedef BWL_PRE_PACKED_STRUCT struct local_supported_cmd_evt_parms {
379 uint8 status;
380 uint8 cmd[MAX_SUPPORTED_CMD_BYTE];
381} BWL_POST_PACKED_STRUCT local_supported_cmd_evt_parms_t;
382
383typedef BWL_PRE_PACKED_STRUCT struct status_change_evt_parms {
384 uint8 status;
385 uint8 amp_status;
386} BWL_POST_PACKED_STRUCT status_change_evt_parms_t;
387
388/* AMP HCI error codes */
389#define HCI_SUCCESS 0x00
390#define HCI_ERR_ILLEGAL_COMMAND 0x01
391#define HCI_ERR_NO_CONNECTION 0x02
392#define HCI_ERR_MEMORY_FULL 0x07
393#define HCI_ERR_CONNECTION_TIMEOUT 0x08
394#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09
395#define HCI_ERR_CONNECTION_EXISTS 0x0B
396#define HCI_ERR_CONNECTION_DISALLOWED 0x0C
397#define HCI_ERR_CONNECTION_ACCEPT_TIMEOUT 0x10
398#define HCI_ERR_UNSUPPORTED_VALUE 0x11
399#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12
400#define HCI_ERR_CONN_TERM_BY_LOCAL_HOST 0x16
401#define HCI_ERR_UNSPECIFIED 0x1F
402#define HCI_ERR_UNIT_KEY_USED 0x26
403#define HCI_ERR_QOS_REJECTED 0x2D
404#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30
405#define HCI_ERR_NO_SUITABLE_CHANNEL 0x39
406#define HCI_ERR_CHANNEL_MOVE 0xFF
407
408/* AMP HCI ACL Data packet format */
409typedef BWL_PRE_PACKED_STRUCT struct amp_hci_ACL_data {
410 uint16 handle; /* 12-bit connection handle + 2-bit PB and 2-bit BC flags */
411 uint16 dlen; /* data total length */
412 uint8 data[1];
413} BWL_POST_PACKED_STRUCT amp_hci_ACL_data_t;
414
415#define HCI_ACL_DATA_PREAMBLE_SIZE OFFSETOF(amp_hci_ACL_data_t, data)
416
417#define HCI_ACL_DATA_BC_FLAGS (0x0 << 14)
418#define HCI_ACL_DATA_PB_FLAGS (0x3 << 12)
419
420#define HCI_ACL_DATA_HANDLE(handle) ((handle) & 0x0fff)
421#define HCI_ACL_DATA_FLAGS(handle) ((handle) >> 12)
422
423/* AMP Activity Report packet formats */
424typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report {
425 uint8 ScheduleKnown;
426 uint8 NumReports;
427 uint8 data[1];
428} BWL_POST_PACKED_STRUCT amp_hci_activity_report_t;
429
430typedef BWL_PRE_PACKED_STRUCT struct amp_hci_activity_report_triple {
431 uint32 StartTime;
432 uint32 Duration;
433 uint32 Periodicity;
434} BWL_POST_PACKED_STRUCT amp_hci_activity_report_triple_t;
435
436#define HCI_AR_SCHEDULE_KNOWN 0x01
437
438
439/* This marks the end of a packed structure section. */
440#include <packed_section_end.h>
441
442#endif /* _bt_amp_hci_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/eapol.h b/drivers/net/wireless/bcmdhd/include/proto/eapol.h
new file mode 100644
index 00000000000..5781d1312e3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/eapol.h
@@ -0,0 +1,173 @@
1/*
2 * 802.1x EAPOL definitions
3 *
4 * See
5 * IEEE Std 802.1X-2001
6 * IEEE 802.1X RADIUS Usage Guidelines
7 *
8 * Copyright (C) 2002 Broadcom Corporation
9 *
10 * $Id: eapol.h,v 9.23.86.1 2010-09-02 18:09:39 Exp $
11 */
12
13#ifndef _eapol_h_
14#define _eapol_h_
15
16#ifndef _TYPEDEFS_H_
17#include <typedefs.h>
18#endif
19
20/* This marks the start of a packed structure section. */
21#include <packed_section_start.h>
22
23#include <bcmcrypto/aeskeywrap.h>
24
25/* EAPOL for 802.3/Ethernet */
26typedef struct {
27 struct ether_header eth; /* 802.3/Ethernet header */
28 unsigned char version; /* EAPOL protocol version */
29 unsigned char type; /* EAPOL type */
30 unsigned short length; /* Length of body */
31 unsigned char body[1]; /* Body (optional) */
32} eapol_header_t;
33
34#define EAPOL_HEADER_LEN 18
35
36/* EAPOL version */
37#define WPA2_EAPOL_VERSION 2
38#define WPA_EAPOL_VERSION 1
39#define LEAP_EAPOL_VERSION 1
40#define SES_EAPOL_VERSION 1
41
42/* EAPOL types */
43#define EAP_PACKET 0
44#define EAPOL_START 1
45#define EAPOL_LOGOFF 2
46#define EAPOL_KEY 3
47#define EAPOL_ASF 4
48
49/* EAPOL-Key types */
50#define EAPOL_RC4_KEY 1
51#define EAPOL_WPA2_KEY 2 /* 802.11i/WPA2 */
52#define EAPOL_WPA_KEY 254 /* WPA */
53
54/* RC4 EAPOL-Key header field sizes */
55#define EAPOL_KEY_REPLAY_LEN 8
56#define EAPOL_KEY_IV_LEN 16
57#define EAPOL_KEY_SIG_LEN 16
58
59/* RC4 EAPOL-Key */
60typedef BWL_PRE_PACKED_STRUCT struct {
61 unsigned char type; /* Key Descriptor Type */
62 unsigned short length; /* Key Length (unaligned) */
63 unsigned char replay[EAPOL_KEY_REPLAY_LEN]; /* Replay Counter */
64 unsigned char iv[EAPOL_KEY_IV_LEN]; /* Key IV */
65 unsigned char index; /* Key Flags & Index */
66 unsigned char signature[EAPOL_KEY_SIG_LEN]; /* Key Signature */
67 unsigned char key[1]; /* Key (optional) */
68} BWL_POST_PACKED_STRUCT eapol_key_header_t;
69
70#define EAPOL_KEY_HEADER_LEN 44
71
72/* RC4 EAPOL-Key flags */
73#define EAPOL_KEY_FLAGS_MASK 0x80
74#define EAPOL_KEY_BROADCAST 0
75#define EAPOL_KEY_UNICAST 0x80
76
77/* RC4 EAPOL-Key index */
78#define EAPOL_KEY_INDEX_MASK 0x7f
79
80/* WPA/802.11i/WPA2 EAPOL-Key header field sizes */
81#define EAPOL_WPA_KEY_REPLAY_LEN 8
82#define EAPOL_WPA_KEY_NONCE_LEN 32
83#define EAPOL_WPA_KEY_IV_LEN 16
84#define EAPOL_WPA_KEY_RSC_LEN 8
85#define EAPOL_WPA_KEY_ID_LEN 8
86#define EAPOL_WPA_KEY_MIC_LEN 16
87#define EAPOL_WPA_KEY_DATA_LEN (EAPOL_WPA_MAX_KEY_SIZE + AKW_BLOCK_LEN)
88#define EAPOL_WPA_MAX_KEY_SIZE 32
89
90/* WPA EAPOL-Key */
91typedef BWL_PRE_PACKED_STRUCT struct {
92 unsigned char type; /* Key Descriptor Type */
93 unsigned short key_info; /* Key Information (unaligned) */
94 unsigned short key_len; /* Key Length (unaligned) */
95 unsigned char replay[EAPOL_WPA_KEY_REPLAY_LEN]; /* Replay Counter */
96 unsigned char nonce[EAPOL_WPA_KEY_NONCE_LEN]; /* Nonce */
97 unsigned char iv[EAPOL_WPA_KEY_IV_LEN]; /* Key IV */
98 unsigned char rsc[EAPOL_WPA_KEY_RSC_LEN]; /* Key RSC */
99 unsigned char id[EAPOL_WPA_KEY_ID_LEN]; /* WPA:Key ID, 802.11i/WPA2: Reserved */
100 unsigned char mic[EAPOL_WPA_KEY_MIC_LEN]; /* Key MIC */
101 unsigned short data_len; /* Key Data Length */
102 unsigned char data[EAPOL_WPA_KEY_DATA_LEN]; /* Key data */
103} BWL_POST_PACKED_STRUCT eapol_wpa_key_header_t;
104
105#define EAPOL_WPA_KEY_LEN 95
106
107/* WPA/802.11i/WPA2 KEY KEY_INFO bits */
108#define WPA_KEY_DESC_V1 0x01
109#define WPA_KEY_DESC_V2 0x02
110#define WPA_KEY_DESC_V3 0x03
111#define WPA_KEY_PAIRWISE 0x08
112#define WPA_KEY_INSTALL 0x40
113#define WPA_KEY_ACK 0x80
114#define WPA_KEY_MIC 0x100
115#define WPA_KEY_SECURE 0x200
116#define WPA_KEY_ERROR 0x400
117#define WPA_KEY_REQ 0x800
118
119/* WPA-only KEY KEY_INFO bits */
120#define WPA_KEY_INDEX_0 0x00
121#define WPA_KEY_INDEX_1 0x10
122#define WPA_KEY_INDEX_2 0x20
123#define WPA_KEY_INDEX_3 0x30
124#define WPA_KEY_INDEX_MASK 0x30
125#define WPA_KEY_INDEX_SHIFT 0x04
126
127/* 802.11i/WPA2-only KEY KEY_INFO bits */
128#define WPA_KEY_ENCRYPTED_DATA 0x1000
129
130/* Key Data encapsulation */
131typedef BWL_PRE_PACKED_STRUCT struct {
132 uint8 type;
133 uint8 length;
134 uint8 oui[3];
135 uint8 subtype;
136 uint8 data[1];
137} BWL_POST_PACKED_STRUCT eapol_wpa2_encap_data_t;
138
139#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6
140
141#define WPA2_KEY_DATA_SUBTYPE_GTK 1
142#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2
143#define WPA2_KEY_DATA_SUBTYPE_MAC 3
144#define WPA2_KEY_DATA_SUBTYPE_PMKID 4
145
146/* GTK encapsulation */
147typedef BWL_PRE_PACKED_STRUCT struct {
148 uint8 flags;
149 uint8 reserved;
150 uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE];
151} BWL_POST_PACKED_STRUCT eapol_wpa2_key_gtk_encap_t;
152
153#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2
154
155#define WPA2_GTK_INDEX_MASK 0x03
156#define WPA2_GTK_INDEX_SHIFT 0x00
157
158#define WPA2_GTK_TRANSMIT 0x04
159
160/* STAKey encapsulation */
161typedef BWL_PRE_PACKED_STRUCT struct {
162 uint8 reserved[2];
163 uint8 mac[ETHER_ADDR_LEN];
164 uint8 stakey[EAPOL_WPA_MAX_KEY_SIZE];
165} BWL_POST_PACKED_STRUCT eapol_wpa2_key_stakey_encap_t;
166
167#define WPA2_KEY_DATA_PAD 0xdd
168
169
170/* This marks the end of a packed structure section. */
171#include <packed_section_end.h>
172
173#endif /* _eapol_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h
new file mode 100644
index 00000000000..6a6dd14c1bb
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h
@@ -0,0 +1,162 @@
1/*
2 * From FreeBSD 2.2.7: Fundamental constants relating to ethernet.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: ethernet.h,v 9.56 2009-10-15 22:54:58 Exp $
25 */
26
27
28#ifndef _NET_ETHERNET_H_
29#define _NET_ETHERNET_H_
30
31#ifndef _TYPEDEFS_H_
32#include "typedefs.h"
33#endif
34
35
36#include <packed_section_start.h>
37
38
39
40#define ETHER_ADDR_LEN 6
41
42
43#define ETHER_TYPE_LEN 2
44
45
46#define ETHER_CRC_LEN 4
47
48
49#define ETHER_HDR_LEN (ETHER_ADDR_LEN * 2 + ETHER_TYPE_LEN)
50
51
52#define ETHER_MIN_LEN 64
53
54
55#define ETHER_MIN_DATA 46
56
57
58#define ETHER_MAX_LEN 1518
59
60
61#define ETHER_MAX_DATA 1500
62
63
64#define ETHER_TYPE_MIN 0x0600
65#define ETHER_TYPE_IP 0x0800
66#define ETHER_TYPE_ARP 0x0806
67#define ETHER_TYPE_8021Q 0x8100
68#define ETHER_TYPE_BRCM 0x886c
69#define ETHER_TYPE_802_1X 0x888e
70#define ETHER_TYPE_802_1X_PREAUTH 0x88c7
71#define ETHER_TYPE_WAI 0x88b4
72
73
74
75#define ETHER_BRCM_SUBTYPE_LEN 4
76#define ETHER_BRCM_CRAM 1
77
78
79#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN)
80#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN)
81#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN)
82
83
84#define ETHER_IS_VALID_LEN(foo) \
85 ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN)
86
87#define ETHER_FILL_MCAST_ADDR_FROM_IP(ea, mgrp_ip) { \
88 ((uint8 *)ea)[0] = 0x01; \
89 ((uint8 *)ea)[1] = 0x00; \
90 ((uint8 *)ea)[2] = 0x5e; \
91 ((uint8 *)ea)[3] = ((mgrp_ip) >> 16) & 0x7f; \
92 ((uint8 *)ea)[4] = ((mgrp_ip) >> 8) & 0xff; \
93 ((uint8 *)ea)[5] = ((mgrp_ip) >> 0) & 0xff; \
94}
95
96#ifndef __INCif_etherh
97
98BWL_PRE_PACKED_STRUCT struct ether_header {
99 uint8 ether_dhost[ETHER_ADDR_LEN];
100 uint8 ether_shost[ETHER_ADDR_LEN];
101 uint16 ether_type;
102} BWL_POST_PACKED_STRUCT;
103
104
105BWL_PRE_PACKED_STRUCT struct ether_addr {
106 uint8 octet[ETHER_ADDR_LEN];
107} BWL_POST_PACKED_STRUCT;
108#endif
109
110
111#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2))
112#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2)
113#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xd))
114#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2))
115
116
117#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1))
118
119
120#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1)
121
122
123
124#define ether_cmp(a, b) (!(((short*)a)[0] == ((short*)b)[0]) | \
125 !(((short*)a)[1] == ((short*)b)[1]) | \
126 !(((short*)a)[2] == ((short*)b)[2]))
127
128
129#define ether_copy(s, d) { \
130 ((short*)d)[0] = ((short*)s)[0]; \
131 ((short*)d)[1] = ((short*)s)[1]; \
132 ((short*)d)[2] = ((short*)s)[2]; }
133
134
135static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}};
136static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}};
137
138#define ETHER_ISBCAST(ea) ((((uint8 *)(ea))[0] & \
139 ((uint8 *)(ea))[1] & \
140 ((uint8 *)(ea))[2] & \
141 ((uint8 *)(ea))[3] & \
142 ((uint8 *)(ea))[4] & \
143 ((uint8 *)(ea))[5]) == 0xff)
144#define ETHER_ISNULLADDR(ea) ((((uint8 *)(ea))[0] | \
145 ((uint8 *)(ea))[1] | \
146 ((uint8 *)(ea))[2] | \
147 ((uint8 *)(ea))[3] | \
148 ((uint8 *)(ea))[4] | \
149 ((uint8 *)(ea))[5]) == 0)
150
151
152#define ETHER_MOVE_HDR(d, s) \
153do { \
154 struct ether_header t; \
155 t = *(struct ether_header *)(s); \
156 *(struct ether_header *)(d) = t; \
157} while (0)
158
159
160#include <packed_section_end.h>
161
162#endif
diff --git a/drivers/net/wireless/bcmdhd/include/proto/p2p.h b/drivers/net/wireless/bcmdhd/include/proto/p2p.h
new file mode 100644
index 00000000000..4a0c9d1ddc3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/p2p.h
@@ -0,0 +1,512 @@
1/*
2 * Copyright (C) 1999-2011, Broadcom Corporation
3 *
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2 (the "GPL"),
7 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
8 * following added to such license:
9 *
10 * As a special exception, the copyright holders of this software give you
11 * permission to link this software with independent modules, and to copy and
12 * distribute the resulting executable under terms of your choice, provided that
13 * you also meet, for each linked independent module, the terms and conditions of
14 * the license of that module. An independent module is a module which is not
15 * derived from this software. The special exception does not apply to any
16 * modifications of the software.
17 *
18 * Notwithstanding the above, under no circumstances may you combine this
19 * software in any way with any other Broadcom software provided under a license
20 * other than the GPL, without Broadcom's express prior written consent.
21 *
22 * Fundamental types and constants relating to WFA P2P (aka WiFi Direct)
23 *
24 * $Id: p2p.h,v 9.17.2.4 2010-12-15 21:41:21 Exp $
25 */
26
27#ifndef _P2P_H_
28#define _P2P_H_
29
30#ifndef _TYPEDEFS_H_
31#include <typedefs.h>
32#endif
33#include <wlioctl.h>
34#include <proto/802.11.h>
35
36/* This marks the start of a packed structure section. */
37#include <packed_section_start.h>
38
39
40/* WiFi P2P OUI values */
41#define P2P_OUI WFA_OUI /* WiFi P2P OUI */
42#define P2P_VER WFA_OUI_TYPE_P2P /* P2P version: 9=WiFi P2P v1.0 */
43
44#define P2P_IE_ID 0xdd /* P2P IE element ID */
45
46/* WiFi P2P IE */
47BWL_PRE_PACKED_STRUCT struct wifi_p2p_ie {
48 uint8 id; /* IE ID: 0xDD */
49 uint8 len; /* IE length */
50 uint8 OUI[3]; /* WiFi P2P specific OUI: P2P_OUI */
51 uint8 oui_type; /* Identifies P2P version: P2P_VER */
52 uint8 subelts[1]; /* variable length subelements */
53} BWL_POST_PACKED_STRUCT;
54typedef struct wifi_p2p_ie wifi_p2p_ie_t;
55
56#define P2P_IE_FIXED_LEN 6
57
58#define P2P_ATTR_ID_OFF 0
59#define P2P_ATTR_LEN_OFF 1
60#define P2P_ATTR_DATA_OFF 3
61
62#define P2P_ATTR_HDR_LEN 3 /* ID + 2-byte length field spec 1.02 */
63
64/* P2P IE Subelement IDs from WiFi P2P Technical Spec 1.00 */
65#define P2P_SEID_STATUS 0 /* Status */
66#define P2P_SEID_MINOR_RC 1 /* Minor Reason Code */
67#define P2P_SEID_P2P_INFO 2 /* P2P Capability (capabilities info) */
68#define P2P_SEID_DEV_ID 3 /* P2P Device ID */
69#define P2P_SEID_INTENT 4 /* Group Owner Intent */
70#define P2P_SEID_CFG_TIMEOUT 5 /* Configuration Timeout */
71#define P2P_SEID_CHANNEL 6 /* Channel */
72#define P2P_SEID_GRP_BSSID 7 /* P2P Group BSSID */
73#define P2P_SEID_XT_TIMING 8 /* Extended Listen Timing */
74#define P2P_SEID_INTINTADDR 9 /* Intended P2P Interface Address */
75#define P2P_SEID_P2P_MGBTY 10 /* P2P Manageability */
76#define P2P_SEID_CHAN_LIST 11 /* Channel List */
77#define P2P_SEID_ABSENCE 12 /* Notice of Absence */
78#define P2P_SEID_DEV_INFO 13 /* Device Info */
79#define P2P_SEID_GROUP_INFO 14 /* Group Info */
80#define P2P_SEID_GROUP_ID 15 /* Group ID */
81#define P2P_SEID_P2P_IF 16 /* P2P Interface */
82#define P2P_SEID_VNDR 221 /* Vendor-specific subelement */
83
84#define P2P_SE_VS_ID_SERVICES 0x1b /* BRCM proprietary subel: L2 Services */
85
86
87/* WiFi P2P IE subelement: P2P Capability (capabilities info) */
88BWL_PRE_PACKED_STRUCT struct wifi_p2p_info_se_s {
89 uint8 eltId; /* SE ID: P2P_SEID_P2P_INFO */
90 uint8 len[2]; /* SE length not including eltId, len fields */
91 uint8 dev; /* Device Capability Bitmap */
92 uint8 group; /* Group Capability Bitmap */
93} BWL_POST_PACKED_STRUCT;
94typedef struct wifi_p2p_info_se_s wifi_p2p_info_se_t;
95
96/* P2P Capability subelement's Device Capability Bitmap bit values */
97#define P2P_CAPSE_DEV_SERVICE_DIS 0x1 /* Service Discovery */
98#define P2P_CAPSE_DEV_CLIENT_DIS 0x2 /* Client Discoverability */
99#define P2P_CAPSE_DEV_CONCURRENT 0x4 /* Concurrent Operation */
100#define P2P_CAPSE_DEV_INFRA_MAN 0x8 /* P2P Infrastructure Managed */
101#define P2P_CAPSE_DEV_LIMIT 0x10 /* P2P Device Limit */
102#define P2P_CAPSE_INVITE_PROC 0x20 /* P2P Invitation Procedure */
103
104/* P2P Capability subelement's Group Capability Bitmap bit values */
105#define P2P_CAPSE_GRP_OWNER 0x1 /* P2P Group Owner */
106#define P2P_CAPSE_PERSIST_GRP 0x2 /* Persistent P2P Group */
107#define P2P_CAPSE_GRP_LIMIT 0x4 /* P2P Group Limit */
108#define P2P_CAPSE_GRP_INTRA_BSS 0x8 /* Intra-BSS Distribution */
109#define P2P_CAPSE_GRP_X_CONNECT 0x10 /* Cross Connection */
110#define P2P_CAPSE_GRP_PERSISTENT 0x20 /* Persistent Reconnect */
111#define P2P_CAPSE_GRP_FORMATION 0x40 /* Group Formation */
112
113
114/* WiFi P2P IE subelement: Group Owner Intent */
115BWL_PRE_PACKED_STRUCT struct wifi_p2p_intent_se_s {
116 uint8 eltId; /* SE ID: P2P_SEID_INTENT */
117 uint8 len[2]; /* SE length not including eltId, len fields */
118 uint8 intent; /* Intent Value 0...15 (0=legacy 15=master only) */
119} BWL_POST_PACKED_STRUCT;
120typedef struct wifi_p2p_intent_se_s wifi_p2p_intent_se_t;
121
122/* WiFi P2P IE subelement: Configuration Timeout */
123BWL_PRE_PACKED_STRUCT struct wifi_p2p_cfg_tmo_se_s {
124 uint8 eltId; /* SE ID: P2P_SEID_CFG_TIMEOUT */
125 uint8 len[2]; /* SE length not including eltId, len fields */
126 uint8 go_tmo; /* GO config timeout in units of 10 ms */
127 uint8 client_tmo; /* Client config timeout in units of 10 ms */
128} BWL_POST_PACKED_STRUCT;
129typedef struct wifi_p2p_cfg_tmo_se_s wifi_p2p_cfg_tmo_se_t;
130
131
132/* WiFi P2P IE subelement: Status */
133BWL_PRE_PACKED_STRUCT struct wifi_p2p_status_se_s {
134 uint8 eltId; /* SE ID: P2P_SEID_STATUS */
135 uint8 len[2]; /* SE length not including eltId, len fields */
136 uint8 status; /* Status Code: P2P_STATSE_* */
137} BWL_POST_PACKED_STRUCT;
138typedef struct wifi_p2p_status_se_s wifi_p2p_status_se_t;
139
140/* Status subelement Status Code definitions */
141#define P2P_STATSE_SUCCESS 0
142 /* Success */
143#define P2P_STATSE_FAIL_INFO_CURR_UNAVAIL 1
144 /* Failed, information currently unavailable */
145#define P2P_STATSE_PASSED_UP P2P_STATSE_FAIL_INFO_CURR_UNAVAIL
146 /* Old name for above in P2P spec 1.08 and older */
147#define P2P_STATSE_FAIL_INCOMPAT_PARAMS 2
148 /* Failed, incompatible parameters */
149#define P2P_STATSE_FAIL_LIMIT_REACHED 3
150 /* Failed, limit reached */
151#define P2P_STATSE_FAIL_INVALID_PARAMS 4
152 /* Failed, invalid parameters */
153#define P2P_STATSE_FAIL_UNABLE_TO_ACCOM 5
154 /* Failed, unable to accomodate request */
155#define P2P_STATSE_FAIL_PROTO_ERROR 6
156 /* Failed, previous protocol error or disruptive behaviour */
157#define P2P_STATSE_FAIL_NO_COMMON_CHAN 7
158 /* Failed, no common channels */
159#define P2P_STATSE_FAIL_UNKNOWN_GROUP 8
160 /* Failed, unknown P2P Group */
161#define P2P_STATSE_FAIL_INTENT 9
162 /* Failed, both peers indicated Intent 15 in GO Negotiation */
163#define P2P_STATSE_FAIL_INCOMPAT_PROVIS 10
164 /* Failed, incompatible provisioning method */
165#define P2P_STATSE_FAIL_USER_REJECT 11
166 /* Failed, rejected by user */
167
168/* WiFi P2P IE attribute: Extended Listen Timing */
169BWL_PRE_PACKED_STRUCT struct wifi_p2p_ext_se_s {
170 uint8 eltId; /* ID: P2P_SEID_EXT_TIMING */
171 uint8 len[2]; /* length not including eltId, len fields */
172 uint8 avail[2]; /* availibility period */
173 uint8 interval[2]; /* availibility interval */
174} BWL_POST_PACKED_STRUCT;
175typedef struct wifi_p2p_ext_se_s wifi_p2p_ext_se_t;
176
177#define P2P_EXT_MIN 10 /* minimum 10ms */
178
179/* WiFi P2P IE subelement: Intended P2P Interface Address */
180BWL_PRE_PACKED_STRUCT struct wifi_p2p_intintad_se_s {
181 uint8 eltId; /* SE ID: P2P_SEID_INTINTADDR */
182 uint8 len[2]; /* SE length not including eltId, len fields */
183 uint8 mac[6]; /* intended P2P interface MAC address */
184} BWL_POST_PACKED_STRUCT;
185typedef struct wifi_p2p_intintad_se_s wifi_p2p_intintad_se_t;
186
187/* WiFi P2P IE subelement: Channel */
188BWL_PRE_PACKED_STRUCT struct wifi_p2p_channel_se_s {
189 uint8 eltId; /* SE ID: P2P_SEID_STATUS */
190 uint8 len[2]; /* SE length not including eltId, len fields */
191 uint8 band; /* Regulatory Class (band) */
192 uint8 channel; /* Channel */
193} BWL_POST_PACKED_STRUCT;
194typedef struct wifi_p2p_channel_se_s wifi_p2p_channel_se_t;
195
196
197/* Channel Entry structure within the Channel List SE */
198BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_entry_s {
199 uint8 band; /* Regulatory Class (band) */
200 uint8 num_channels; /* # of channels in the channel list */
201 uint8 channels[WL_NUMCHANNELS]; /* Channel List */
202} BWL_POST_PACKED_STRUCT;
203typedef struct wifi_p2p_chanlist_entry_s wifi_p2p_chanlist_entry_t;
204#define WIFI_P2P_CHANLIST_SE_MAX_ENTRIES 2
205
206/* WiFi P2P IE subelement: Channel List */
207BWL_PRE_PACKED_STRUCT struct wifi_p2p_chanlist_se_s {
208 uint8 eltId; /* SE ID: P2P_SEID_STATUS */
209 uint8 len[2]; /* SE length not including eltId, len fields */
210 uint8 country[3]; /* Country String */
211 uint8 num_entries; /* # of channel entries */
212 wifi_p2p_chanlist_entry_t entries[WIFI_P2P_CHANLIST_SE_MAX_ENTRIES];
213 /* Channel Entry List */
214} BWL_POST_PACKED_STRUCT;
215typedef struct wifi_p2p_chanlist_se_s wifi_p2p_chanlist_se_t;
216
217/* WiFi P2P IE's Device Info subelement */
218BWL_PRE_PACKED_STRUCT struct wifi_p2p_devinfo_se_s {
219 uint8 eltId; /* SE ID: P2P_SEID_DEVINFO */
220 uint8 len[2]; /* SE length not including eltId, len fields */
221 uint8 mac[6]; /* P2P Device MAC address */
222 uint16 wps_cfg_meths; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */
223 uint8 pri_devtype[8]; /* Primary Device Type */
224} BWL_POST_PACKED_STRUCT;
225typedef struct wifi_p2p_devinfo_se_s wifi_p2p_devinfo_se_t;
226
227#define P2P_DEV_TYPE_LEN 8
228
229/* WiFi P2P IE's Group Info subelement Client Info Descriptor */
230BWL_PRE_PACKED_STRUCT struct wifi_p2p_cid_fixed_s {
231 uint8 len;
232 uint8 devaddr[ETHER_ADDR_LEN]; /* P2P Device Address */
233 uint8 ifaddr[ETHER_ADDR_LEN]; /* P2P Interface Address */
234 uint8 devcap; /* Device Capability */
235 uint8 cfg_meths[2]; /* Config Methods: reg_prototlv.h WPS_CONFMET_* */
236 uint8 pridt[P2P_DEV_TYPE_LEN]; /* Primary Device Type */
237 uint8 secdts; /* Number of Secondary Device Types */
238} BWL_POST_PACKED_STRUCT;
239typedef struct wifi_p2p_cid_fixed_s wifi_p2p_cid_fixed_t;
240
241/* WiFi P2P IE's Device ID subelement */
242BWL_PRE_PACKED_STRUCT struct wifi_p2p_devid_se_s {
243 uint8 eltId;
244 uint8 len[2];
245 struct ether_addr addr; /* P2P Device MAC address */
246} BWL_POST_PACKED_STRUCT;
247typedef struct wifi_p2p_devid_se_s wifi_p2p_devid_se_t;
248
249/* WiFi P2P IE subelement: P2P Manageability */
250BWL_PRE_PACKED_STRUCT struct wifi_p2p_mgbt_se_s {
251 uint8 eltId; /* SE ID: P2P_SEID_P2P_MGBTY */
252 uint8 len[2]; /* SE length not including eltId, len fields */
253 uint8 mg_bitmap; /* manageability bitmap */
254} BWL_POST_PACKED_STRUCT;
255typedef struct wifi_p2p_mgbt_se_s wifi_p2p_mgbt_se_t;
256/* mg_bitmap field bit values */
257#define P2P_MGBTSE_P2PDEVMGMT_FLAG 0x1 /* AP supports Managed P2P Device */
258
259/* WiFi P2P IE subelement: Group Info */
260BWL_PRE_PACKED_STRUCT struct wifi_p2p_grpinfo_se_s {
261 uint8 eltId; /* SE ID: P2P_SEID_GROUP_INFO */
262 uint8 len[2]; /* SE length not including eltId, len fields */
263} BWL_POST_PACKED_STRUCT;
264typedef struct wifi_p2p_grpinfo_se_s wifi_p2p_grpinfo_se_t;
265
266
267/* WiFi P2P Action Frame */
268BWL_PRE_PACKED_STRUCT struct wifi_p2p_action_frame {
269 uint8 category; /* P2P_AF_CATEGORY */
270 uint8 OUI[3]; /* OUI - P2P_OUI */
271 uint8 type; /* OUI Type - P2P_VER */
272 uint8 subtype; /* OUI Subtype - P2P_AF_* */
273 uint8 dialog_token; /* nonzero, identifies req/resp tranaction */
274 uint8 elts[1]; /* Variable length information elements. Max size =
275 * ACTION_FRAME_SIZE - sizeof(this structure) - 1
276 */
277} BWL_POST_PACKED_STRUCT;
278typedef struct wifi_p2p_action_frame wifi_p2p_action_frame_t;
279#define P2P_AF_CATEGORY 0x7f
280
281#define P2P_AF_FIXED_LEN 7
282
283/* WiFi P2P Action Frame OUI Subtypes */
284#define P2P_AF_NOTICE_OF_ABSENCE 0 /* Notice of Absence */
285#define P2P_AF_PRESENCE_REQ 1 /* P2P Presence Request */
286#define P2P_AF_PRESENCE_RSP 2 /* P2P Presence Response */
287#define P2P_AF_GO_DISC_REQ 3 /* GO Discoverability Request */
288
289
290/* WiFi P2P Public Action Frame */
291BWL_PRE_PACKED_STRUCT struct wifi_p2p_pub_act_frame {
292 uint8 category; /* P2P_PUB_AF_CATEGORY */
293 uint8 action; /* P2P_PUB_AF_ACTION */
294 uint8 oui[3]; /* P2P_OUI */
295 uint8 oui_type; /* OUI type - P2P_VER */
296 uint8 subtype; /* OUI subtype - P2P_TYPE_* */
297 uint8 dialog_token; /* nonzero, identifies req/rsp transaction */
298 uint8 elts[1]; /* Variable length information elements. Max size =
299 * ACTION_FRAME_SIZE - sizeof(this structure) - 1
300 */
301} BWL_POST_PACKED_STRUCT;
302typedef struct wifi_p2p_pub_act_frame wifi_p2p_pub_act_frame_t;
303#define P2P_PUB_AF_FIXED_LEN 8
304#define P2P_PUB_AF_CATEGORY 0x04
305#define P2P_PUB_AF_ACTION 0x09
306
307/* WiFi P2P Public Action Frame OUI Subtypes */
308#define P2P_PAF_GON_REQ 0 /* Group Owner Negotiation Req */
309#define P2P_PAF_GON_RSP 1 /* Group Owner Negotiation Rsp */
310#define P2P_PAF_GON_CONF 2 /* Group Owner Negotiation Confirm */
311#define P2P_PAF_INVITE_REQ 3 /* P2P Invitation Request */
312#define P2P_PAF_INVITE_RSP 4 /* P2P Invitation Response */
313#define P2P_PAF_DEVDIS_REQ 5 /* Device Discoverability Request */
314#define P2P_PAF_DEVDIS_RSP 6 /* Device Discoverability Response */
315#define P2P_PAF_PROVDIS_REQ 7 /* Provision Discovery Request */
316#define P2P_PAF_PROVDIS_RSP 8 /* Provision Discovery Request */
317
318/* TODO: Stop using these obsolete aliases for P2P_PAF_GON_* */
319#define P2P_TYPE_MNREQ P2P_PAF_GON_REQ
320#define P2P_TYPE_MNRSP P2P_PAF_GON_RSP
321#define P2P_TYPE_MNCONF P2P_PAF_GON_CONF
322
323/* WiFi P2P IE subelement: Notice of Absence */
324BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_desc {
325 uint8 cnt_type; /* Count/Type */
326 uint32 duration; /* Duration */
327 uint32 interval; /* Interval */
328 uint32 start; /* Start Time */
329} BWL_POST_PACKED_STRUCT;
330typedef struct wifi_p2p_noa_desc wifi_p2p_noa_desc_t;
331
332BWL_PRE_PACKED_STRUCT struct wifi_p2p_noa_se {
333 uint8 eltId; /* Subelement ID */
334 uint8 len[2]; /* Length */
335 uint8 index; /* Index */
336 uint8 ops_ctw_parms; /* CTWindow and OppPS Parameters */
337 wifi_p2p_noa_desc_t desc[1]; /* Notice of Absence Descriptor(s) */
338} BWL_POST_PACKED_STRUCT;
339typedef struct wifi_p2p_noa_se wifi_p2p_noa_se_t;
340
341#define P2P_NOA_SE_FIXED_LEN 5
342
343/* cnt_type field values */
344#define P2P_NOA_DESC_CNT_RESERVED 0 /* reserved and should not be used */
345#define P2P_NOA_DESC_CNT_REPEAT 255 /* continuous schedule */
346#define P2P_NOA_DESC_TYPE_PREFERRED 1 /* preferred values */
347#define P2P_NOA_DESC_TYPE_ACCEPTABLE 2 /* acceptable limits */
348
349/* ctw_ops_parms field values */
350#define P2P_NOA_CTW_MASK 0x7f
351#define P2P_NOA_OPS_MASK 0x80
352#define P2P_NOA_OPS_SHIFT 7
353
354#define P2P_CTW_MIN 10 /* minimum 10TU */
355
356/*
357 * P2P Service Discovery related
358 */
359#define P2PSD_ACTION_CATEGORY 0x04
360 /* Public action frame */
361#define P2PSD_ACTION_ID_GAS_IREQ 0x0a
362 /* Action value for GAS Initial Request AF */
363#define P2PSD_ACTION_ID_GAS_IRESP 0x0b
364 /* Action value for GAS Initial Response AF */
365#define P2PSD_ACTION_ID_GAS_CREQ 0x0c
366 /* Action value for GAS Comback Request AF */
367#define P2PSD_ACTION_ID_GAS_CRESP 0x0d
368 /* Action value for GAS Comback Response AF */
369#define P2PSD_AD_EID 0x6c
370 /* Advertisement Protocol IE ID */
371#define P2PSD_ADP_TUPLE_QLMT_PAMEBI 0x00
372 /* Query Response Length Limit 7 bits plus PAME-BI 1 bit */
373#define P2PSD_ADP_PROTO_ID 0x00
374 /* Advertisement Protocol ID. Always 0 for P2P SD */
375#define P2PSD_GAS_OUI P2P_OUI
376 /* WFA OUI */
377#define P2PSD_GAS_OUI_SUBTYPE P2P_VER
378 /* OUI Subtype for GAS IE */
379#define P2PSD_GAS_NQP_INFOID 0xDDDD
380 /* NQP Query Info ID: 56797 */
381#define P2PSD_GAS_COMEBACKDEALY 0x00
382 /* Not used in the Native GAS protocol */
383
384/* Service Protocol Type */
385typedef enum p2psd_svc_protype {
386 SVC_RPOTYPE_ALL = 0,
387 SVC_RPOTYPE_BONJOUR = 1,
388 SVC_RPOTYPE_UPNP = 2,
389 SVC_RPOTYPE_WSD = 3,
390 SVC_RPOTYPE_VENDOR = 255
391} p2psd_svc_protype_t;
392
393/* Service Discovery response status code */
394typedef enum {
395 P2PSD_RESP_STATUS_SUCCESS = 0,
396 P2PSD_RESP_STATUS_PROTYPE_NA = 1,
397 P2PSD_RESP_STATUS_DATA_NA = 2,
398 P2PSD_RESP_STATUS_BAD_REQUEST = 3
399} p2psd_resp_status_t;
400
401/* Advertisement Protocol IE tuple field */
402BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_tpl {
403 uint8 llm_pamebi; /* Query Response Length Limit bit 0-6, set to 0 plus
404 * Pre-Associated Message Exchange BSSID Independent bit 7, set to 0
405 */
406 uint8 adp_id; /* Advertisement Protocol ID: 0 for NQP Native Query Protocol */
407} BWL_POST_PACKED_STRUCT;
408typedef struct wifi_p2psd_adp_tpl wifi_p2psd_adp_tpl_t;
409
410/* Advertisement Protocol IE */
411BWL_PRE_PACKED_STRUCT struct wifi_p2psd_adp_ie {
412 uint8 id; /* IE ID: 0x6c - 108 */
413 uint8 len; /* IE length */
414 wifi_p2psd_adp_tpl_t adp_tpl; /* Advertisement Protocol Tuple field. Only one
415 * tuple is defined for P2P Service Discovery
416 */
417} BWL_POST_PACKED_STRUCT;
418typedef struct wifi_p2psd_adp_ie wifi_p2psd_adp_ie_t;
419
420/* NQP Vendor-specific Content */
421BWL_PRE_PACKED_STRUCT struct wifi_p2psd_nqp_query_vsc {
422 uint8 oui_subtype; /* OUI Subtype: 0x09 */
423 uint16 svc_updi; /* Service Update Indicator */
424 uint8 svc_tlvs[1]; /* wifi_p2psd_qreq_tlv_t type for service request,
425 * wifi_p2psd_qresp_tlv_t type for service response
426 */
427} BWL_POST_PACKED_STRUCT;
428typedef struct wifi_p2psd_nqp_query_vsc wifi_p2psd_nqp_query_vsc_t;
429
430/* Service Request TLV */
431BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_tlv {
432 uint16 len; /* Length: 5 plus size of Query Data */
433 uint8 svc_prot; /* Service Protocol Type */
434 uint8 svc_tscid; /* Service Transaction ID */
435 uint8 query_data[1]; /* Query Data, passed in from above Layer 2 */
436} BWL_POST_PACKED_STRUCT;
437typedef struct wifi_p2psd_qreq_tlv wifi_p2psd_qreq_tlv_t;
438
439/* Query Request Frame, defined in generic format, instead of NQP specific */
440BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qreq_frame {
441 uint16 info_id; /* Info ID: 0xDDDD */
442 uint16 len; /* Length of service request TLV, 5 plus the size of request data */
443 uint8 oui[3]; /* WFA OUI: 0x0050F2 */
444 uint8 qreq_vsc[1]; /* Vendor-specific Content: wifi_p2psd_nqp_query_vsc_t type for NQP */
445
446} BWL_POST_PACKED_STRUCT;
447typedef struct wifi_p2psd_qreq_frame wifi_p2psd_qreq_frame_t;
448
449/* GAS Initial Request AF body, "elts" in wifi_p2p_pub_act_frame */
450BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_ireq_frame {
451 wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */
452 uint16 qreq_len; /* Query Request Length */
453 uint8 qreq_frm[1]; /* Query Request Frame wifi_p2psd_qreq_frame_t */
454} BWL_POST_PACKED_STRUCT;
455typedef struct wifi_p2psd_gas_ireq_frame wifi_p2psd_gas_ireq_frame_t;
456
457/* Service Response TLV */
458BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_tlv {
459 uint16 len; /* Length: 5 plus size of Query Data */
460 uint8 svc_prot; /* Service Protocol Type */
461 uint8 svc_tscid; /* Service Transaction ID */
462 uint8 status; /* Value defined in Table 57 of P2P spec. */
463 uint8 query_data[1]; /* Response Data, passed in from above Layer 2 */
464} BWL_POST_PACKED_STRUCT;
465typedef struct wifi_p2psd_qresp_tlv wifi_p2psd_qresp_tlv_t;
466
467/* Query Response Frame, defined in generic format, instead of NQP specific */
468BWL_PRE_PACKED_STRUCT struct wifi_p2psd_qresp_frame {
469 uint16 info_id; /* Info ID: 0xDDDD */
470 uint16 len; /* Lenth of service response TLV, 6 plus the size of resp data */
471 uint8 oui[3]; /* WFA OUI: 0x0050F2 */
472 uint8 qresp_vsc[1]; /* Vendor-specific Content: wifi_p2psd_qresp_tlv_t type for NQP */
473
474} BWL_POST_PACKED_STRUCT;
475typedef struct wifi_p2psd_qresp_frame wifi_p2psd_qresp_frame_t;
476
477/* GAS Initial Response AF body, "elts" in wifi_p2p_pub_act_frame */
478BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_iresp_frame {
479 uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */
480 uint16 cb_delay; /* GAS Comeback Delay */
481 wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */
482 uint16 qresp_len; /* Query Response Length */
483 uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */
484} BWL_POST_PACKED_STRUCT;
485typedef struct wifi_p2psd_gas_iresp_frame wifi_p2psd_gas_iresp_frame_t;
486
487/* GAS Comeback Response AF body, "elts" in wifi_p2p_pub_act_frame */
488BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_cresp_frame {
489 uint16 status; /* Value defined in Table 7-23 of IEEE P802.11u */
490 uint8 fragment_id; /* Fragmentation ID */
491 uint16 cb_delay; /* GAS Comeback Delay */
492 wifi_p2psd_adp_ie_t adp_ie; /* Advertisement Protocol IE */
493 uint16 qresp_len; /* Query Response Length */
494 uint8 qresp_frm[1]; /* Query Response Frame wifi_p2psd_qresp_frame_t */
495} BWL_POST_PACKED_STRUCT;
496typedef struct wifi_p2psd_gas_cresp_frame wifi_p2psd_gas_cresp_frame_t;
497
498/* Wi-Fi GAS Public Action Frame */
499BWL_PRE_PACKED_STRUCT struct wifi_p2psd_gas_pub_act_frame {
500 uint8 category; /* 0x04 Public Action Frame */
501 uint8 action; /* 0x6c Advertisement Protocol */
502 uint8 dialog_token; /* nonzero, identifies req/rsp transaction */
503 uint8 query_data[1]; /* Query Data. wifi_p2psd_gas_ireq_frame_t
504 * or wifi_p2psd_gas_iresp_frame_t format
505 */
506} BWL_POST_PACKED_STRUCT;
507typedef struct wifi_p2psd_gas_pub_act_frame wifi_p2psd_gas_pub_act_frame_t;
508
509/* This marks the end of a packed structure section. */
510#include <packed_section_end.h>
511
512#endif /* _P2P_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h
new file mode 100644
index 00000000000..7fe4fbce310
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h
@@ -0,0 +1,76 @@
1/*
2 * SD-SPI Protocol Standard
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: sdspi.h,v 9.2.120.1 2010-11-15 17:56:25 Exp $
25 */
26
27#ifndef _SD_SPI_H
28#define _SD_SPI_H
29
30#define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */
31#define SPI_START_S 31
32#define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */
33#define SPI_DIR_S 30
34#define SPI_CMD_INDEX_M BITFIELD_MASK(6) /* Bits [29:24] - Command number */
35#define SPI_CMD_INDEX_S 24
36#define SPI_RW_M BITFIELD_MASK(1) /* Bit [23] - Read=0, Write=1 */
37#define SPI_RW_S 23
38#define SPI_FUNC_M BITFIELD_MASK(3) /* Bits [22:20] - Function Number */
39#define SPI_FUNC_S 20
40#define SPI_RAW_M BITFIELD_MASK(1) /* Bit [19] - Read After Wr */
41#define SPI_RAW_S 19
42#define SPI_STUFF_M BITFIELD_MASK(1) /* Bit [18] - Stuff bit */
43#define SPI_STUFF_S 18
44#define SPI_BLKMODE_M BITFIELD_MASK(1) /* Bit [19] - Blockmode 1=blk */
45#define SPI_BLKMODE_S 19
46#define SPI_OPCODE_M BITFIELD_MASK(1) /* Bit [18] - OP Code */
47#define SPI_OPCODE_S 18
48#define SPI_ADDR_M BITFIELD_MASK(17) /* Bits [17:1] - Address */
49#define SPI_ADDR_S 1
50#define SPI_STUFF0_M BITFIELD_MASK(1) /* Bit [0] - Stuff bit */
51#define SPI_STUFF0_S 0
52
53#define SPI_RSP_START_M BITFIELD_MASK(1) /* Bit [7] - Start Bit (always 0) */
54#define SPI_RSP_START_S 7
55#define SPI_RSP_PARAM_ERR_M BITFIELD_MASK(1) /* Bit [6] - Parameter Error */
56#define SPI_RSP_PARAM_ERR_S 6
57#define SPI_RSP_RFU5_M BITFIELD_MASK(1) /* Bit [5] - RFU (Always 0) */
58#define SPI_RSP_RFU5_S 5
59#define SPI_RSP_FUNC_ERR_M BITFIELD_MASK(1) /* Bit [4] - Function number error */
60#define SPI_RSP_FUNC_ERR_S 4
61#define SPI_RSP_CRC_ERR_M BITFIELD_MASK(1) /* Bit [3] - COM CRC Error */
62#define SPI_RSP_CRC_ERR_S 3
63#define SPI_RSP_ILL_CMD_M BITFIELD_MASK(1) /* Bit [2] - Illegal Command error */
64#define SPI_RSP_ILL_CMD_S 2
65#define SPI_RSP_RFU1_M BITFIELD_MASK(1) /* Bit [1] - RFU (Always 0) */
66#define SPI_RSP_RFU1_S 1
67#define SPI_RSP_IDLE_M BITFIELD_MASK(1) /* Bit [0] - In idle state */
68#define SPI_RSP_IDLE_S 0
69
70/* SD-SPI Protocol Definitions */
71#define SDSPI_COMMAND_LEN 6 /* Number of bytes in an SD command */
72#define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */
73#define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */
74#define SDSPI_START_BIT_MASK 0x80
75
76#endif /* _SD_SPI_H */
diff --git a/drivers/net/wireless/bcmdhd/include/proto/vlan.h b/drivers/net/wireless/bcmdhd/include/proto/vlan.h
new file mode 100644
index 00000000000..07fa7e499c2
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/vlan.h
@@ -0,0 +1,70 @@
1/*
2 * 802.1Q VLAN protocol definitions
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: vlan.h,v 9.7 2009-03-13 01:11:50 Exp $
25 */
26
27
28#ifndef _vlan_h_
29#define _vlan_h_
30
31#ifndef _TYPEDEFS_H_
32#include <typedefs.h>
33#endif
34
35
36#include <packed_section_start.h>
37
38#define VLAN_VID_MASK 0xfff
39#define VLAN_CFI_SHIFT 12
40#define VLAN_PRI_SHIFT 13
41
42#define VLAN_PRI_MASK 7
43
44#define VLAN_TAG_LEN 4
45#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN)
46
47#define VLAN_TPID 0x8100
48
49struct ethervlan_header {
50 uint8 ether_dhost[ETHER_ADDR_LEN];
51 uint8 ether_shost[ETHER_ADDR_LEN];
52 uint16 vlan_type;
53 uint16 vlan_tag;
54 uint16 ether_type;
55};
56
57#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN)
58
59
60
61#include <packed_section_end.h>
62
63#define ETHERVLAN_MOVE_HDR(d, s) \
64do { \
65 struct ethervlan_header t; \
66 t = *(struct ethervlan_header *)(s); \
67 *(struct ethervlan_header *)(d) = t; \
68} while (0)
69
70#endif
diff --git a/drivers/net/wireless/bcmdhd/include/proto/wpa.h b/drivers/net/wireless/bcmdhd/include/proto/wpa.h
new file mode 100644
index 00000000000..1ff06dc7942
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/proto/wpa.h
@@ -0,0 +1,160 @@
1/*
2 * Fundamental types and constants relating to WPA
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wpa.h,v 1.19 2009-07-13 08:29:58 Exp $
25 */
26
27
28#ifndef _proto_wpa_h_
29#define _proto_wpa_h_
30
31#include <typedefs.h>
32#include <proto/ethernet.h>
33
34
35
36#include <packed_section_start.h>
37
38
39
40
41#define DOT11_RC_INVALID_WPA_IE 13
42#define DOT11_RC_MIC_FAILURE 14
43#define DOT11_RC_4WH_TIMEOUT 15
44#define DOT11_RC_GTK_UPDATE_TIMEOUT 16
45#define DOT11_RC_WPA_IE_MISMATCH 17
46#define DOT11_RC_INVALID_MC_CIPHER 18
47#define DOT11_RC_INVALID_UC_CIPHER 19
48#define DOT11_RC_INVALID_AKMP 20
49#define DOT11_RC_BAD_WPA_VERSION 21
50#define DOT11_RC_INVALID_WPA_CAP 22
51#define DOT11_RC_8021X_AUTH_FAIL 23
52
53#define WPA2_PMKID_LEN 16
54
55
56typedef BWL_PRE_PACKED_STRUCT struct
57{
58 uint8 tag;
59 uint8 length;
60 uint8 oui[3];
61 uint8 oui_type;
62 BWL_PRE_PACKED_STRUCT struct {
63 uint8 low;
64 uint8 high;
65 } BWL_POST_PACKED_STRUCT version;
66} BWL_POST_PACKED_STRUCT wpa_ie_fixed_t;
67#define WPA_IE_OUITYPE_LEN 4
68#define WPA_IE_FIXED_LEN 8
69#define WPA_IE_TAG_FIXED_LEN 6
70
71typedef BWL_PRE_PACKED_STRUCT struct {
72 uint8 tag;
73 uint8 length;
74 BWL_PRE_PACKED_STRUCT struct {
75 uint8 low;
76 uint8 high;
77 } BWL_POST_PACKED_STRUCT version;
78} BWL_POST_PACKED_STRUCT wpa_rsn_ie_fixed_t;
79#define WPA_RSN_IE_FIXED_LEN 4
80#define WPA_RSN_IE_TAG_FIXED_LEN 2
81typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN];
82
83
84typedef BWL_PRE_PACKED_STRUCT struct
85{
86 uint8 oui[3];
87 uint8 type;
88} BWL_POST_PACKED_STRUCT wpa_suite_t, wpa_suite_mcast_t;
89#define WPA_SUITE_LEN 4
90
91
92typedef BWL_PRE_PACKED_STRUCT struct
93{
94 BWL_PRE_PACKED_STRUCT struct {
95 uint8 low;
96 uint8 high;
97 } BWL_POST_PACKED_STRUCT count;
98 wpa_suite_t list[1];
99} BWL_POST_PACKED_STRUCT wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t;
100#define WPA_IE_SUITE_COUNT_LEN 2
101typedef BWL_PRE_PACKED_STRUCT struct
102{
103 BWL_PRE_PACKED_STRUCT struct {
104 uint8 low;
105 uint8 high;
106 } BWL_POST_PACKED_STRUCT count;
107 wpa_pmkid_t list[1];
108} BWL_POST_PACKED_STRUCT wpa_pmkid_list_t;
109
110
111#define WPA_CIPHER_NONE 0
112#define WPA_CIPHER_WEP_40 1
113#define WPA_CIPHER_TKIP 2
114#define WPA_CIPHER_AES_OCB 3
115#define WPA_CIPHER_AES_CCM 4
116#define WPA_CIPHER_WEP_104 5
117
118
119#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \
120 (cipher) == WPA_CIPHER_WEP_40 || \
121 (cipher) == WPA_CIPHER_WEP_104 || \
122 (cipher) == WPA_CIPHER_TKIP || \
123 (cipher) == WPA_CIPHER_AES_OCB || \
124 (cipher) == WPA_CIPHER_AES_CCM)
125
126
127#define WPA_TKIP_CM_DETECT 60
128#define WPA_TKIP_CM_BLOCK 60
129
130
131#define RSN_CAP_LEN 2
132
133
134#define RSN_CAP_PREAUTH 0x0001
135#define RSN_CAP_NOPAIRWISE 0x0002
136#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
137#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2
138#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030
139#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4
140#define RSN_CAP_1_REPLAY_CNTR 0
141#define RSN_CAP_2_REPLAY_CNTRS 1
142#define RSN_CAP_4_REPLAY_CNTRS 2
143#define RSN_CAP_16_REPLAY_CNTRS 3
144
145
146#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS
147#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS
148#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT
149#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK
150
151
152#define WPA_CAP_LEN RSN_CAP_LEN
153
154#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH
155
156
157
158#include <packed_section_end.h>
159
160#endif
diff --git a/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd/include/sbchipc.h
new file mode 100644
index 00000000000..cbd37490f1c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbchipc.h
@@ -0,0 +1,1615 @@
1/*
2 * SiliconBackplane Chipcommon core hardware definitions.
3 *
4 * The chipcommon core provides chip identification, SB control,
5 * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer,
6 * GPIO interface, extbus, and support for serial and parallel flashes.
7 *
8 * $Id: sbchipc.h,v 13.169.2.14 2011-02-10 23:43:55 Exp $
9 *
10 * Copyright (C) 1999-2011, Broadcom Corporation
11 *
12 * Unless you and Broadcom execute a separate written software license
13 * agreement governing use of this software, this software is licensed to you
14 * under the terms of the GNU General Public License version 2 (the "GPL"),
15 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
16 * following added to such license:
17 *
18 * As a special exception, the copyright holders of this software give you
19 * permission to link this software with independent modules, and to copy and
20 * distribute the resulting executable under terms of your choice, provided that
21 * you also meet, for each linked independent module, the terms and conditions of
22 * the license of that module. An independent module is a module which is not
23 * derived from this software. The special exception does not apply to any
24 * modifications of the software.
25 *
26 * Notwithstanding the above, under no circumstances may you combine this
27 * software in any way with any other Broadcom software provided under a license
28 * other than the GPL, without Broadcom's express prior written consent.
29 */
30
31
32#ifndef _SBCHIPC_H
33#define _SBCHIPC_H
34
35#ifndef _LANGUAGE_ASSEMBLY
36
37
38#ifndef PAD
39#define _PADLINE(line) pad ## line
40#define _XSTR(line) _PADLINE(line)
41#define PAD _XSTR(__LINE__)
42#endif
43
44typedef volatile struct {
45 uint32 chipid;
46 uint32 capabilities;
47 uint32 corecontrol;
48 uint32 bist;
49
50
51 uint32 otpstatus;
52 uint32 otpcontrol;
53 uint32 otpprog;
54 uint32 otplayout;
55
56
57 uint32 intstatus;
58 uint32 intmask;
59
60
61 uint32 chipcontrol;
62 uint32 chipstatus;
63
64
65 uint32 jtagcmd;
66 uint32 jtagir;
67 uint32 jtagdr;
68 uint32 jtagctrl;
69
70
71 uint32 flashcontrol;
72 uint32 flashaddress;
73 uint32 flashdata;
74 uint32 PAD[1];
75
76
77 uint32 broadcastaddress;
78 uint32 broadcastdata;
79
80
81 uint32 gpiopullup;
82 uint32 gpiopulldown;
83 uint32 gpioin;
84 uint32 gpioout;
85 uint32 gpioouten;
86 uint32 gpiocontrol;
87 uint32 gpiointpolarity;
88 uint32 gpiointmask;
89
90
91 uint32 gpioevent;
92 uint32 gpioeventintmask;
93
94
95 uint32 watchdog;
96
97
98 uint32 gpioeventintpolarity;
99
100
101 uint32 gpiotimerval;
102 uint32 gpiotimeroutmask;
103
104
105 uint32 clockcontrol_n;
106 uint32 clockcontrol_sb;
107 uint32 clockcontrol_pci;
108 uint32 clockcontrol_m2;
109 uint32 clockcontrol_m3;
110 uint32 clkdiv;
111 uint32 gpiodebugsel;
112 uint32 capabilities_ext;
113
114
115 uint32 pll_on_delay;
116 uint32 fref_sel_delay;
117 uint32 slow_clk_ctl;
118 uint32 PAD;
119
120
121 uint32 system_clk_ctl;
122 uint32 clkstatestretch;
123 uint32 PAD[2];
124
125
126 uint32 bp_addrlow;
127 uint32 bp_addrhigh;
128 uint32 bp_data;
129 uint32 PAD;
130 uint32 bp_indaccess;
131
132 uint32 gsioctrl;
133 uint32 gsioaddress;
134 uint32 gsiodata;
135
136
137 uint32 clkdiv2;
138 uint32 PAD[2];
139
140
141 uint32 eromptr;
142
143
144 uint32 pcmcia_config;
145 uint32 pcmcia_memwait;
146 uint32 pcmcia_attrwait;
147 uint32 pcmcia_iowait;
148 uint32 ide_config;
149 uint32 ide_memwait;
150 uint32 ide_attrwait;
151 uint32 ide_iowait;
152 uint32 prog_config;
153 uint32 prog_waitcount;
154 uint32 flash_config;
155 uint32 flash_waitcount;
156 uint32 PAD[4];
157 uint32 PAD[40];
158
159
160
161 uint32 clk_ctl_st;
162 uint32 hw_war;
163 uint32 PAD[70];
164
165
166 uint8 uart0data;
167 uint8 uart0imr;
168 uint8 uart0fcr;
169 uint8 uart0lcr;
170 uint8 uart0mcr;
171 uint8 uart0lsr;
172 uint8 uart0msr;
173 uint8 uart0scratch;
174 uint8 PAD[248];
175
176 uint8 uart1data;
177 uint8 uart1imr;
178 uint8 uart1fcr;
179 uint8 uart1lcr;
180 uint8 uart1mcr;
181 uint8 uart1lsr;
182 uint8 uart1msr;
183 uint8 uart1scratch;
184 uint32 PAD[126];
185
186
187
188 uint32 pmucontrol;
189 uint32 pmucapabilities;
190 uint32 pmustatus;
191 uint32 res_state;
192 uint32 res_pending;
193 uint32 pmutimer;
194 uint32 min_res_mask;
195 uint32 max_res_mask;
196 uint32 res_table_sel;
197 uint32 res_dep_mask;
198 uint32 res_updn_timer;
199 uint32 res_timer;
200 uint32 clkstretch;
201 uint32 pmuwatchdog;
202 uint32 gpiosel;
203 uint32 gpioenable;
204 uint32 res_req_timer_sel;
205 uint32 res_req_timer;
206 uint32 res_req_mask;
207 uint32 PAD;
208 uint32 chipcontrol_addr;
209 uint32 chipcontrol_data;
210 uint32 regcontrol_addr;
211 uint32 regcontrol_data;
212 uint32 pllcontrol_addr;
213 uint32 pllcontrol_data;
214 uint32 pmustrapopt;
215 uint32 pmu_xtalfreq;
216 uint32 PAD[100];
217 uint16 sromotp[768];
218} chipcregs_t;
219
220#endif
221
222
223#define CC_CHIPID 0
224#define CC_CAPABILITIES 4
225#define CC_CHIPST 0x2c
226#define CC_EROMPTR 0xfc
227
228
229#define CC_OTPST 0x10
230#define CC_JTAGCMD 0x30
231#define CC_JTAGIR 0x34
232#define CC_JTAGDR 0x38
233#define CC_JTAGCTRL 0x3c
234#define CC_GPIOPU 0x58
235#define CC_GPIOPD 0x5c
236#define CC_GPIOIN 0x60
237#define CC_GPIOOUT 0x64
238#define CC_GPIOOUTEN 0x68
239#define CC_GPIOCTRL 0x6c
240#define CC_GPIOPOL 0x70
241#define CC_GPIOINTM 0x74
242#define CC_WATCHDOG 0x80
243#define CC_CLKC_N 0x90
244#define CC_CLKC_M0 0x94
245#define CC_CLKC_M1 0x98
246#define CC_CLKC_M2 0x9c
247#define CC_CLKC_M3 0xa0
248#define CC_CLKDIV 0xa4
249#define CC_SYS_CLK_CTL 0xc0
250#define CC_CLK_CTL_ST SI_CLK_CTL_ST
251#define PMU_CTL 0x600
252#define PMU_CAP 0x604
253#define PMU_ST 0x608
254#define PMU_RES_STATE 0x60c
255#define PMU_TIMER 0x614
256#define PMU_MIN_RES_MASK 0x618
257#define PMU_MAX_RES_MASK 0x61c
258#define CC_CHIPCTL_ADDR 0x650
259#define CC_CHIPCTL_DATA 0x654
260#define PMU_REG_CONTROL_ADDR 0x658
261#define PMU_REG_CONTROL_DATA 0x65C
262#define PMU_PLL_CONTROL_ADDR 0x660
263#define PMU_PLL_CONTROL_DATA 0x664
264#define CC_SROM_OTP 0x800
265
266
267#define CID_ID_MASK 0x0000ffff
268#define CID_REV_MASK 0x000f0000
269#define CID_REV_SHIFT 16
270#define CID_PKG_MASK 0x00f00000
271#define CID_PKG_SHIFT 20
272#define CID_CC_MASK 0x0f000000
273#define CID_CC_SHIFT 24
274#define CID_TYPE_MASK 0xf0000000
275#define CID_TYPE_SHIFT 28
276
277
278#define CC_CAP_UARTS_MASK 0x00000003
279#define CC_CAP_MIPSEB 0x00000004
280#define CC_CAP_UCLKSEL 0x00000018
281#define CC_CAP_UINTCLK 0x00000008
282#define CC_CAP_UARTGPIO 0x00000020
283#define CC_CAP_EXTBUS_MASK 0x000000c0
284#define CC_CAP_EXTBUS_NONE 0x00000000
285#define CC_CAP_EXTBUS_FULL 0x00000040
286#define CC_CAP_EXTBUS_PROG 0x00000080
287#define CC_CAP_FLASH_MASK 0x00000700
288#define CC_CAP_PLL_MASK 0x00038000
289#define CC_CAP_PWR_CTL 0x00040000
290#define CC_CAP_OTPSIZE 0x00380000
291#define CC_CAP_OTPSIZE_SHIFT 19
292#define CC_CAP_OTPSIZE_BASE 5
293#define CC_CAP_JTAGP 0x00400000
294#define CC_CAP_ROM 0x00800000
295#define CC_CAP_BKPLN64 0x08000000
296#define CC_CAP_PMU 0x10000000
297#define CC_CAP_ECI 0x20000000
298#define CC_CAP_SROM 0x40000000
299#define CC_CAP_NFLASH 0x80000000
300
301#define CC_CAP2_SECI 0x00000001
302#define CC_CAP2_GSIO 0x00000002
303
304
305#define CC_CAP_EXT_SECI_PRESENT 0x00000001
306
307
308#define PLL_NONE 0x00000000
309#define PLL_TYPE1 0x00010000
310#define PLL_TYPE2 0x00020000
311#define PLL_TYPE3 0x00030000
312#define PLL_TYPE4 0x00008000
313#define PLL_TYPE5 0x00018000
314#define PLL_TYPE6 0x00028000
315#define PLL_TYPE7 0x00038000
316
317
318#define ILP_CLOCK 32000
319
320
321#define ALP_CLOCK 20000000
322
323
324#define HT_CLOCK 80000000
325
326
327#define CC_UARTCLKO 0x00000001
328#define CC_SE 0x00000002
329#define CC_ASYNCGPIO 0x00000004
330#define CC_UARTCLKEN 0x00000008
331
332
333#define CHIPCTRL_4321A0_DEFAULT 0x3a4
334#define CHIPCTRL_4321A1_DEFAULT 0x0a4
335#define CHIPCTRL_4321_PLL_DOWN 0x800000
336
337
338#define OTPS_OL_MASK 0x000000ff
339#define OTPS_OL_MFG 0x00000001
340#define OTPS_OL_OR1 0x00000002
341#define OTPS_OL_OR2 0x00000004
342#define OTPS_OL_GU 0x00000008
343#define OTPS_GUP_MASK 0x00000f00
344#define OTPS_GUP_SHIFT 8
345#define OTPS_GUP_HW 0x00000100
346#define OTPS_GUP_SW 0x00000200
347#define OTPS_GUP_CI 0x00000400
348#define OTPS_GUP_FUSE 0x00000800
349#define OTPS_READY 0x00001000
350#define OTPS_RV(x) (1 << (16 + (x)))
351#define OTPS_RV_MASK 0x0fff0000
352
353
354#define OTPC_PROGSEL 0x00000001
355#define OTPC_PCOUNT_MASK 0x0000000e
356#define OTPC_PCOUNT_SHIFT 1
357#define OTPC_VSEL_MASK 0x000000f0
358#define OTPC_VSEL_SHIFT 4
359#define OTPC_TMM_MASK 0x00000700
360#define OTPC_TMM_SHIFT 8
361#define OTPC_ODM 0x00000800
362#define OTPC_PROGEN 0x80000000
363
364
365#define OTPP_COL_MASK 0x000000ff
366#define OTPP_COL_SHIFT 0
367#define OTPP_ROW_MASK 0x0000ff00
368#define OTPP_ROW_SHIFT 8
369#define OTPP_OC_MASK 0x0f000000
370#define OTPP_OC_SHIFT 24
371#define OTPP_READERR 0x10000000
372#define OTPP_VALUE_MASK 0x20000000
373#define OTPP_VALUE_SHIFT 29
374#define OTPP_START_BUSY 0x80000000
375#define OTPP_READ 0x40000000
376
377
378#define OTP_CISFORMAT_NEW 0x80000000
379
380
381#define OTPPOC_READ 0
382#define OTPPOC_BIT_PROG 1
383#define OTPPOC_VERIFY 3
384#define OTPPOC_INIT 4
385#define OTPPOC_SET 5
386#define OTPPOC_RESET 6
387#define OTPPOC_OCST 7
388#define OTPPOC_ROW_LOCK 8
389#define OTPPOC_PRESCN_TEST 9
390
391
392
393#define JTAGM_CREV_OLD 10
394#define JTAGM_CREV_IRP 22
395#define JTAGM_CREV_RTI 28
396
397
398#define JCMD_START 0x80000000
399#define JCMD_BUSY 0x80000000
400#define JCMD_STATE_MASK 0x60000000
401#define JCMD_STATE_TLR 0x00000000
402#define JCMD_STATE_PIR 0x20000000
403#define JCMD_STATE_PDR 0x40000000
404#define JCMD_STATE_RTI 0x60000000
405#define JCMD0_ACC_MASK 0x0000f000
406#define JCMD0_ACC_IRDR 0x00000000
407#define JCMD0_ACC_DR 0x00001000
408#define JCMD0_ACC_IR 0x00002000
409#define JCMD0_ACC_RESET 0x00003000
410#define JCMD0_ACC_IRPDR 0x00004000
411#define JCMD0_ACC_PDR 0x00005000
412#define JCMD0_IRW_MASK 0x00000f00
413#define JCMD_ACC_MASK 0x000f0000
414#define JCMD_ACC_IRDR 0x00000000
415#define JCMD_ACC_DR 0x00010000
416#define JCMD_ACC_IR 0x00020000
417#define JCMD_ACC_RESET 0x00030000
418#define JCMD_ACC_IRPDR 0x00040000
419#define JCMD_ACC_PDR 0x00050000
420#define JCMD_ACC_PIR 0x00060000
421#define JCMD_ACC_IRDR_I 0x00070000
422#define JCMD_ACC_DR_I 0x00080000
423#define JCMD_IRW_MASK 0x00001f00
424#define JCMD_IRW_SHIFT 8
425#define JCMD_DRW_MASK 0x0000003f
426
427
428#define JCTRL_FORCE_CLK 4
429#define JCTRL_EXT_EN 2
430#define JCTRL_EN 1
431
432
433#define CLKD_SFLASH 0x0f000000
434#define CLKD_SFLASH_SHIFT 24
435#define CLKD_OTP 0x000f0000
436#define CLKD_OTP_SHIFT 16
437#define CLKD_JTAG 0x00000f00
438#define CLKD_JTAG_SHIFT 8
439#define CLKD_UART 0x000000ff
440
441#define CLKD2_SROM 0x00000003
442
443
444#define CI_GPIO 0x00000001
445#define CI_EI 0x00000002
446#define CI_TEMP 0x00000004
447#define CI_SIRQ 0x00000008
448#define CI_ECI 0x00000010
449#define CI_PMU 0x00000020
450#define CI_UART 0x00000040
451#define CI_WDRESET 0x80000000
452
453
454#define SCC_SS_MASK 0x00000007
455#define SCC_SS_LPO 0x00000000
456#define SCC_SS_XTAL 0x00000001
457#define SCC_SS_PCI 0x00000002
458#define SCC_LF 0x00000200
459#define SCC_LP 0x00000400
460#define SCC_FS 0x00000800
461#define SCC_IP 0x00001000
462#define SCC_XC 0x00002000
463#define SCC_XP 0x00004000
464#define SCC_CD_MASK 0xffff0000
465#define SCC_CD_SHIFT 16
466
467
468#define SYCC_IE 0x00000001
469#define SYCC_AE 0x00000002
470#define SYCC_FP 0x00000004
471#define SYCC_AR 0x00000008
472#define SYCC_HR 0x00000010
473#define SYCC_CD_MASK 0xffff0000
474#define SYCC_CD_SHIFT 16
475
476
477#define BPIA_BYTEEN 0x0000000f
478#define BPIA_SZ1 0x00000001
479#define BPIA_SZ2 0x00000003
480#define BPIA_SZ4 0x00000007
481#define BPIA_SZ8 0x0000000f
482#define BPIA_WRITE 0x00000100
483#define BPIA_START 0x00000200
484#define BPIA_BUSY 0x00000200
485#define BPIA_ERROR 0x00000400
486
487
488#define CF_EN 0x00000001
489#define CF_EM_MASK 0x0000000e
490#define CF_EM_SHIFT 1
491#define CF_EM_FLASH 0
492#define CF_EM_SYNC 2
493#define CF_EM_PCMCIA 4
494#define CF_DS 0x00000010
495#define CF_BS 0x00000020
496#define CF_CD_MASK 0x000000c0
497#define CF_CD_SHIFT 6
498#define CF_CD_DIV2 0x00000000
499#define CF_CD_DIV3 0x00000040
500#define CF_CD_DIV4 0x00000080
501#define CF_CE 0x00000100
502#define CF_SB 0x00000200
503
504
505#define PM_W0_MASK 0x0000003f
506#define PM_W1_MASK 0x00001f00
507#define PM_W1_SHIFT 8
508#define PM_W2_MASK 0x001f0000
509#define PM_W2_SHIFT 16
510#define PM_W3_MASK 0x1f000000
511#define PM_W3_SHIFT 24
512
513
514#define PA_W0_MASK 0x0000003f
515#define PA_W1_MASK 0x00001f00
516#define PA_W1_SHIFT 8
517#define PA_W2_MASK 0x001f0000
518#define PA_W2_SHIFT 16
519#define PA_W3_MASK 0x1f000000
520#define PA_W3_SHIFT 24
521
522
523#define PI_W0_MASK 0x0000003f
524#define PI_W1_MASK 0x00001f00
525#define PI_W1_SHIFT 8
526#define PI_W2_MASK 0x001f0000
527#define PI_W2_SHIFT 16
528#define PI_W3_MASK 0x1f000000
529#define PI_W3_SHIFT 24
530
531
532#define PW_W0_MASK 0x0000001f
533#define PW_W1_MASK 0x00001f00
534#define PW_W1_SHIFT 8
535#define PW_W2_MASK 0x001f0000
536#define PW_W2_SHIFT 16
537#define PW_W3_MASK 0x1f000000
538#define PW_W3_SHIFT 24
539
540#define PW_W0 0x0000000c
541#define PW_W1 0x00000a00
542#define PW_W2 0x00020000
543#define PW_W3 0x01000000
544
545
546#define FW_W0_MASK 0x0000003f
547#define FW_W1_MASK 0x00001f00
548#define FW_W1_SHIFT 8
549#define FW_W2_MASK 0x001f0000
550#define FW_W2_SHIFT 16
551#define FW_W3_MASK 0x1f000000
552#define FW_W3_SHIFT 24
553
554
555#define SRC_START 0x80000000
556#define SRC_BUSY 0x80000000
557#define SRC_OPCODE 0x60000000
558#define SRC_OP_READ 0x00000000
559#define SRC_OP_WRITE 0x20000000
560#define SRC_OP_WRDIS 0x40000000
561#define SRC_OP_WREN 0x60000000
562#define SRC_OTPSEL 0x00000010
563#define SRC_LOCK 0x00000008
564#define SRC_SIZE_MASK 0x00000006
565#define SRC_SIZE_1K 0x00000000
566#define SRC_SIZE_4K 0x00000002
567#define SRC_SIZE_16K 0x00000004
568#define SRC_SIZE_SHIFT 1
569#define SRC_PRESENT 0x00000001
570
571
572#define PCTL_ILP_DIV_MASK 0xffff0000
573#define PCTL_ILP_DIV_SHIFT 16
574#define PCTL_PLL_PLLCTL_UPD 0x00000400
575#define PCTL_NOILP_ON_WAIT 0x00000200
576#define PCTL_HT_REQ_EN 0x00000100
577#define PCTL_ALP_REQ_EN 0x00000080
578#define PCTL_XTALFREQ_MASK 0x0000007c
579#define PCTL_XTALFREQ_SHIFT 2
580#define PCTL_ILP_DIV_EN 0x00000002
581#define PCTL_LPO_SEL 0x00000001
582
583
584#define CSTRETCH_HT 0xffff0000
585#define CSTRETCH_ALP 0x0000ffff
586
587
588#define GPIO_ONTIME_SHIFT 16
589
590
591#define CN_N1_MASK 0x3f
592#define CN_N2_MASK 0x3f00
593#define CN_N2_SHIFT 8
594#define CN_PLLC_MASK 0xf0000
595#define CN_PLLC_SHIFT 16
596
597
598#define CC_M1_MASK 0x3f
599#define CC_M2_MASK 0x3f00
600#define CC_M2_SHIFT 8
601#define CC_M3_MASK 0x3f0000
602#define CC_M3_SHIFT 16
603#define CC_MC_MASK 0x1f000000
604#define CC_MC_SHIFT 24
605
606
607#define CC_F6_2 0x02
608#define CC_F6_3 0x03
609#define CC_F6_4 0x05
610#define CC_F6_5 0x09
611#define CC_F6_6 0x11
612#define CC_F6_7 0x21
613
614#define CC_F5_BIAS 5
615
616#define CC_MC_BYPASS 0x08
617#define CC_MC_M1 0x04
618#define CC_MC_M1M2 0x02
619#define CC_MC_M1M2M3 0x01
620#define CC_MC_M1M3 0x11
621
622
623#define CC_T2_BIAS 2
624#define CC_T2M2_BIAS 3
625
626#define CC_T2MC_M1BYP 1
627#define CC_T2MC_M2BYP 2
628#define CC_T2MC_M3BYP 4
629
630
631#define CC_T6_MMASK 1
632#define CC_T6_M0 120000000
633#define CC_T6_M1 100000000
634#define SB2MIPS_T6(sb) (2 * (sb))
635
636
637#define CC_CLOCK_BASE1 24000000
638#define CC_CLOCK_BASE2 12500000
639
640
641#define CLKC_5350_N 0x0311
642#define CLKC_5350_M 0x04020009
643
644
645#define FLASH_NONE 0x000
646#define SFLASH_ST 0x100
647#define SFLASH_AT 0x200
648#define PFLASH 0x700
649
650
651#define CC_CFG_EN 0x0001
652#define CC_CFG_EM_MASK 0x000e
653#define CC_CFG_EM_ASYNC 0x0000
654#define CC_CFG_EM_SYNC 0x0002
655#define CC_CFG_EM_PCMCIA 0x0004
656#define CC_CFG_EM_IDE 0x0006
657#define CC_CFG_DS 0x0010
658#define CC_CFG_CD_MASK 0x00e0
659#define CC_CFG_CE 0x0100
660#define CC_CFG_SB 0x0200
661#define CC_CFG_IS 0x0400
662
663
664#define CC_EB_BASE 0x1a000000
665#define CC_EB_PCMCIA_MEM 0x1a000000
666#define CC_EB_PCMCIA_IO 0x1a200000
667#define CC_EB_PCMCIA_CFG 0x1a400000
668#define CC_EB_IDE 0x1a800000
669#define CC_EB_PCMCIA1_MEM 0x1a800000
670#define CC_EB_PCMCIA1_IO 0x1aa00000
671#define CC_EB_PCMCIA1_CFG 0x1ac00000
672#define CC_EB_PROGIF 0x1b000000
673
674
675
676#define SFLASH_OPCODE 0x000000ff
677#define SFLASH_ACTION 0x00000700
678#define SFLASH_CS_ACTIVE 0x00001000
679#define SFLASH_START 0x80000000
680#define SFLASH_BUSY SFLASH_START
681
682
683#define SFLASH_ACT_OPONLY 0x0000
684#define SFLASH_ACT_OP1D 0x0100
685#define SFLASH_ACT_OP3A 0x0200
686#define SFLASH_ACT_OP3A1D 0x0300
687#define SFLASH_ACT_OP3A4D 0x0400
688#define SFLASH_ACT_OP3A4X4D 0x0500
689#define SFLASH_ACT_OP3A1X4D 0x0700
690
691
692#define SFLASH_ST_WREN 0x0006
693#define SFLASH_ST_WRDIS 0x0004
694#define SFLASH_ST_RDSR 0x0105
695#define SFLASH_ST_WRSR 0x0101
696#define SFLASH_ST_READ 0x0303
697#define SFLASH_ST_PP 0x0302
698#define SFLASH_ST_SE 0x02d8
699#define SFLASH_ST_BE 0x00c7
700#define SFLASH_ST_DP 0x00b9
701#define SFLASH_ST_RES 0x03ab
702#define SFLASH_ST_CSA 0x1000
703#define SFLASH_ST_SSE 0x0220
704
705
706#define SFLASH_ST_WIP 0x01
707#define SFLASH_ST_WEL 0x02
708#define SFLASH_ST_BP_MASK 0x1c
709#define SFLASH_ST_BP_SHIFT 2
710#define SFLASH_ST_SRWD 0x80
711
712
713#define SFLASH_AT_READ 0x07e8
714#define SFLASH_AT_PAGE_READ 0x07d2
715#define SFLASH_AT_BUF1_READ
716#define SFLASH_AT_BUF2_READ
717#define SFLASH_AT_STATUS 0x01d7
718#define SFLASH_AT_BUF1_WRITE 0x0384
719#define SFLASH_AT_BUF2_WRITE 0x0387
720#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283
721#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286
722#define SFLASH_AT_BUF1_PROGRAM 0x0288
723#define SFLASH_AT_BUF2_PROGRAM 0x0289
724#define SFLASH_AT_PAGE_ERASE 0x0281
725#define SFLASH_AT_BLOCK_ERASE 0x0250
726#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382
727#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385
728#define SFLASH_AT_BUF1_LOAD 0x0253
729#define SFLASH_AT_BUF2_LOAD 0x0255
730#define SFLASH_AT_BUF1_COMPARE 0x0260
731#define SFLASH_AT_BUF2_COMPARE 0x0261
732#define SFLASH_AT_BUF1_REPROGRAM 0x0258
733#define SFLASH_AT_BUF2_REPROGRAM 0x0259
734
735
736#define SFLASH_AT_READY 0x80
737#define SFLASH_AT_MISMATCH 0x40
738#define SFLASH_AT_ID_MASK 0x38
739#define SFLASH_AT_ID_SHIFT 3
740
741
742#define GSIO_START 0x80000000
743#define GSIO_BUSY GSIO_START
744
745
746
747#define UART_RX 0
748#define UART_TX 0
749#define UART_DLL 0
750#define UART_IER 1
751#define UART_DLM 1
752#define UART_IIR 2
753#define UART_FCR 2
754#define UART_LCR 3
755#define UART_MCR 4
756#define UART_LSR 5
757#define UART_MSR 6
758#define UART_SCR 7
759#define UART_LCR_DLAB 0x80
760#define UART_LCR_WLEN8 0x03
761#define UART_MCR_OUT2 0x08
762#define UART_MCR_LOOP 0x10
763#define UART_LSR_RX_FIFO 0x80
764#define UART_LSR_TDHR 0x40
765#define UART_LSR_THRE 0x20
766#define UART_LSR_BREAK 0x10
767#define UART_LSR_FRAMING 0x08
768#define UART_LSR_PARITY 0x04
769#define UART_LSR_OVERRUN 0x02
770#define UART_LSR_RXRDY 0x01
771#define UART_FCR_FIFO_ENABLE 1
772
773
774#define UART_IIR_FIFO_MASK 0xc0
775#define UART_IIR_INT_MASK 0xf
776#define UART_IIR_MDM_CHG 0x0
777#define UART_IIR_NOINT 0x1
778#define UART_IIR_THRE 0x2
779#define UART_IIR_RCVD_DATA 0x4
780#define UART_IIR_RCVR_STATUS 0x6
781#define UART_IIR_CHAR_TIME 0xc
782
783
784#define UART_IER_EDSSI 8
785#define UART_IER_ELSI 4
786#define UART_IER_ETBEI 2
787#define UART_IER_ERBFI 1
788
789
790#define PST_EXTLPOAVAIL 0x0100
791#define PST_WDRESET 0x0080
792#define PST_INTPEND 0x0040
793#define PST_SBCLKST 0x0030
794#define PST_SBCLKST_ILP 0x0010
795#define PST_SBCLKST_ALP 0x0020
796#define PST_SBCLKST_HT 0x0030
797#define PST_ALPAVAIL 0x0008
798#define PST_HTAVAIL 0x0004
799#define PST_RESINIT 0x0003
800
801
802#define PCAP_REV_MASK 0x000000ff
803#define PCAP_RC_MASK 0x00001f00
804#define PCAP_RC_SHIFT 8
805#define PCAP_TC_MASK 0x0001e000
806#define PCAP_TC_SHIFT 13
807#define PCAP_PC_MASK 0x001e0000
808#define PCAP_PC_SHIFT 17
809#define PCAP_VC_MASK 0x01e00000
810#define PCAP_VC_SHIFT 21
811#define PCAP_CC_MASK 0x1e000000
812#define PCAP_CC_SHIFT 25
813#define PCAP5_PC_MASK 0x003e0000
814#define PCAP5_PC_SHIFT 17
815#define PCAP5_VC_MASK 0x07c00000
816#define PCAP5_VC_SHIFT 22
817#define PCAP5_CC_MASK 0xf8000000
818#define PCAP5_CC_SHIFT 27
819
820
821
822#define PRRT_TIME_MASK 0x03ff
823#define PRRT_INTEN 0x0400
824#define PRRT_REQ_ACTIVE 0x0800
825#define PRRT_ALP_REQ 0x1000
826#define PRRT_HT_REQ 0x2000
827
828
829#define PMURES_BIT(bit) (1 << (bit))
830
831
832#define PMURES_MAX_RESNUM 30
833
834
835#define PMU_CHIPCTL0 0
836
837
838#define PMU_CC1_CLKREQ_TYPE_SHIFT 19
839#define PMU_CC1_CLKREQ_TYPE_MASK (1 << PMU_CC1_CLKREQ_TYPE_SHIFT)
840
841#define CLKREQ_TYPE_CONFIG_OPENDRAIN 0
842#define CLKREQ_TYPE_CONFIG_PUSHPULL 1
843
844
845#define PMU_CHIPCTL1 1
846#define PMU_CC1_RXC_DLL_BYPASS 0x00010000
847
848#define PMU_CC1_IF_TYPE_MASK 0x00000030
849#define PMU_CC1_IF_TYPE_RMII 0x00000000
850#define PMU_CC1_IF_TYPE_MII 0x00000010
851#define PMU_CC1_IF_TYPE_RGMII 0x00000020
852
853#define PMU_CC1_SW_TYPE_MASK 0x000000c0
854#define PMU_CC1_SW_TYPE_EPHY 0x00000000
855#define PMU_CC1_SW_TYPE_EPHYMII 0x00000040
856#define PMU_CC1_SW_TYPE_EPHYRMII 0x00000080
857#define PMU_CC1_SW_TYPE_RGMII 0x000000c0
858
859
860
861
862
863#define PMU0_PLL0_PLLCTL0 0
864#define PMU0_PLL0_PC0_PDIV_MASK 1
865#define PMU0_PLL0_PC0_PDIV_FREQ 25000
866#define PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038
867#define PMU0_PLL0_PC0_DIV_ARM_SHIFT 3
868#define PMU0_PLL0_PC0_DIV_ARM_BASE 8
869
870
871#define PMU0_PLL0_PC0_DIV_ARM_110MHZ 0
872#define PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1
873#define PMU0_PLL0_PC0_DIV_ARM_88MHZ 2
874#define PMU0_PLL0_PC0_DIV_ARM_80MHZ 3
875#define PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4
876#define PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5
877#define PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6
878#define PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7
879
880
881#define PMU0_PLL0_PLLCTL1 1
882#define PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000
883#define PMU0_PLL0_PC1_WILD_INT_SHIFT 28
884#define PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00
885#define PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8
886#define PMU0_PLL0_PC1_STOP_MOD 0x00000040
887
888
889#define PMU0_PLL0_PLLCTL2 2
890#define PMU0_PLL0_PC2_WILD_INT_MASK 0xf
891#define PMU0_PLL0_PC2_WILD_INT_SHIFT 4
892
893
894
895#define PMU1_PLL0_PLLCTL0 0
896#define PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000
897#define PMU1_PLL0_PC0_P1DIV_SHIFT 20
898#define PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000
899#define PMU1_PLL0_PC0_P2DIV_SHIFT 24
900
901
902#define PMU1_PLL0_PLLCTL1 1
903#define PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff
904#define PMU1_PLL0_PC1_M1DIV_SHIFT 0
905#define PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00
906#define PMU1_PLL0_PC1_M2DIV_SHIFT 8
907#define PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000
908#define PMU1_PLL0_PC1_M3DIV_SHIFT 16
909#define PMU1_PLL0_PC1_M4DIV_MASK 0xff000000
910#define PMU1_PLL0_PC1_M4DIV_SHIFT 24
911#define PMU1_PLL0_PC1_M4DIV_BY_9 9
912#define PMU1_PLL0_PC1_M4DIV_BY_18 0x12
913#define PMU1_PLL0_PC1_M4DIV_BY_36 0x24
914
915#define DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8
916#define DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT)
917#define DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT)
918
919
920#define PMU1_PLL0_PLLCTL2 2
921#define PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff
922#define PMU1_PLL0_PC2_M5DIV_SHIFT 0
923#define PMU1_PLL0_PC2_M5DIV_BY_12 0xc
924#define PMU1_PLL0_PC2_M5DIV_BY_18 0x12
925#define PMU1_PLL0_PC2_M5DIV_BY_36 0x24
926#define PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00
927#define PMU1_PLL0_PC2_M6DIV_SHIFT 8
928#define PMU1_PLL0_PC2_M6DIV_BY_18 0x12
929#define PMU1_PLL0_PC2_M6DIV_BY_36 0x24
930#define PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000
931#define PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17
932#define PMU1_PLL0_PC2_NDIV_MODE_MASH 1
933#define PMU1_PLL0_PC2_NDIV_MODE_MFB 2
934#define PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000
935#define PMU1_PLL0_PC2_NDIV_INT_SHIFT 20
936
937
938#define PMU1_PLL0_PLLCTL3 3
939#define PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff
940#define PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0
941
942
943#define PMU1_PLL0_PLLCTL4 4
944
945
946#define PMU1_PLL0_PLLCTL5 5
947#define PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00
948#define PMU1_PLL0_PC5_CLK_DRV_SHIFT 8
949
950
951#define PMU2_PHY_PLL_PLLCTL 4
952#define PMU2_SI_PLL_PLLCTL 10
953
954
955
956
957#define PMU2_PLL_PLLCTL0 0
958#define PMU2_PLL_PC0_P1DIV_MASK 0x00f00000
959#define PMU2_PLL_PC0_P1DIV_SHIFT 20
960#define PMU2_PLL_PC0_P2DIV_MASK 0x0f000000
961#define PMU2_PLL_PC0_P2DIV_SHIFT 24
962
963
964#define PMU2_PLL_PLLCTL1 1
965#define PMU2_PLL_PC1_M1DIV_MASK 0x000000ff
966#define PMU2_PLL_PC1_M1DIV_SHIFT 0
967#define PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00
968#define PMU2_PLL_PC1_M2DIV_SHIFT 8
969#define PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000
970#define PMU2_PLL_PC1_M3DIV_SHIFT 16
971#define PMU2_PLL_PC1_M4DIV_MASK 0xff000000
972#define PMU2_PLL_PC1_M4DIV_SHIFT 24
973
974
975#define PMU2_PLL_PLLCTL2 2
976#define PMU2_PLL_PC2_M5DIV_MASK 0x000000ff
977#define PMU2_PLL_PC2_M5DIV_SHIFT 0
978#define PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00
979#define PMU2_PLL_PC2_M6DIV_SHIFT 8
980#define PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000
981#define PMU2_PLL_PC2_NDIV_MODE_SHIFT 17
982#define PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000
983#define PMU2_PLL_PC2_NDIV_INT_SHIFT 20
984
985
986#define PMU2_PLL_PLLCTL3 3
987#define PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff
988#define PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0
989
990
991#define PMU2_PLL_PLLCTL4 4
992
993
994#define PMU2_PLL_PLLCTL5 5
995#define PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00
996#define PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8
997#define PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000
998#define PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12
999#define PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000
1000#define PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16
1001#define PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000
1002#define PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20
1003#define PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000
1004#define PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24
1005#define PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000
1006#define PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28
1007
1008
1009#define PMU5_PLL_P1P2_OFF 0
1010#define PMU5_PLL_P1_MASK 0x0f000000
1011#define PMU5_PLL_P1_SHIFT 24
1012#define PMU5_PLL_P2_MASK 0x00f00000
1013#define PMU5_PLL_P2_SHIFT 20
1014#define PMU5_PLL_M14_OFF 1
1015#define PMU5_PLL_MDIV_MASK 0x000000ff
1016#define PMU5_PLL_MDIV_WIDTH 8
1017#define PMU5_PLL_NM5_OFF 2
1018#define PMU5_PLL_NDIV_MASK 0xfff00000
1019#define PMU5_PLL_NDIV_SHIFT 20
1020#define PMU5_PLL_NDIV_MODE_MASK 0x000e0000
1021#define PMU5_PLL_NDIV_MODE_SHIFT 17
1022#define PMU5_PLL_FMAB_OFF 3
1023#define PMU5_PLL_MRAT_MASK 0xf0000000
1024#define PMU5_PLL_MRAT_SHIFT 28
1025#define PMU5_PLL_ABRAT_MASK 0x08000000
1026#define PMU5_PLL_ABRAT_SHIFT 27
1027#define PMU5_PLL_FDIV_MASK 0x07ffffff
1028#define PMU5_PLL_PLLCTL_OFF 4
1029#define PMU5_PLL_PCHI_OFF 5
1030#define PMU5_PLL_PCHI_MASK 0x0000003f
1031
1032
1033#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF
1034#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000
1035#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31
1036
1037
1038#define PMU5_MAINPLL_CPU 1
1039#define PMU5_MAINPLL_MEM 2
1040#define PMU5_MAINPLL_SI 3
1041
1042#define PMU7_PLL_PLLCTL7 7
1043#define PMU7_PLL_CTL7_M4DIV_MASK 0xff000000
1044#define PMU7_PLL_CTL7_M4DIV_SHIFT 24
1045#define PMU7_PLL_CTL7_M4DIV_BY_6 6
1046#define PMU7_PLL_CTL7_M4DIV_BY_12 0xc
1047#define PMU7_PLL_CTL7_M4DIV_BY_24 0x18
1048#define PMU7_PLL_PLLCTL8 8
1049#define PMU7_PLL_CTL8_M5DIV_MASK 0x000000ff
1050#define PMU7_PLL_CTL8_M5DIV_SHIFT 0
1051#define PMU7_PLL_CTL8_M5DIV_BY_8 8
1052#define PMU7_PLL_CTL8_M5DIV_BY_12 0xc
1053#define PMU7_PLL_CTL8_M5DIV_BY_24 0x18
1054#define PMU7_PLL_CTL8_M6DIV_MASK 0x0000ff00
1055#define PMU7_PLL_CTL8_M6DIV_SHIFT 8
1056#define PMU7_PLL_CTL8_M6DIV_BY_12 0xc
1057#define PMU7_PLL_CTL8_M6DIV_BY_24 0x18
1058#define PMU7_PLL_PLLCTL11 11
1059#define PMU7_PLL_PLLCTL11_MASK 0xffffff00
1060#define PMU7_PLL_PLLCTL11_VAL 0x22222200
1061
1062
1063#define PMU4716_MAINPLL_PLL0 12
1064
1065
1066#define PMU5356_MAINPLL_PLL0 0
1067#define PMU5357_MAINPLL_PLL0 0
1068
1069
1070#define RES4716_PROC_PLL_ON 0x00000040
1071#define RES4716_PROC_HT_AVAIL 0x00000080
1072
1073
1074#define CCTRL_471X_I2S_PINS_ENABLE 0x0080
1075
1076
1077
1078#define CCTRL_5357_I2S_PINS_ENABLE 0x00040000
1079#define CCTRL_5357_I2CSPI_PINS_ENABLE 0x00080000
1080
1081
1082#define RES5354_EXT_SWITCHER_PWM 0
1083#define RES5354_BB_SWITCHER_PWM 1
1084#define RES5354_BB_SWITCHER_BURST 2
1085#define RES5354_BB_EXT_SWITCHER_BURST 3
1086#define RES5354_ILP_REQUEST 4
1087#define RES5354_RADIO_SWITCHER_PWM 5
1088#define RES5354_RADIO_SWITCHER_BURST 6
1089#define RES5354_ROM_SWITCH 7
1090#define RES5354_PA_REF_LDO 8
1091#define RES5354_RADIO_LDO 9
1092#define RES5354_AFE_LDO 10
1093#define RES5354_PLL_LDO 11
1094#define RES5354_BG_FILTBYP 12
1095#define RES5354_TX_FILTBYP 13
1096#define RES5354_RX_FILTBYP 14
1097#define RES5354_XTAL_PU 15
1098#define RES5354_XTAL_EN 16
1099#define RES5354_BB_PLL_FILTBYP 17
1100#define RES5354_RF_PLL_FILTBYP 18
1101#define RES5354_BB_PLL_PU 19
1102
1103
1104#define CCTRL5357_EXTPA (1<<14)
1105#define CCTRL5357_ANT_MUX_2o3 (1<<15)
1106
1107
1108#define RES4328_EXT_SWITCHER_PWM 0
1109#define RES4328_BB_SWITCHER_PWM 1
1110#define RES4328_BB_SWITCHER_BURST 2
1111#define RES4328_BB_EXT_SWITCHER_BURST 3
1112#define RES4328_ILP_REQUEST 4
1113#define RES4328_RADIO_SWITCHER_PWM 5
1114#define RES4328_RADIO_SWITCHER_BURST 6
1115#define RES4328_ROM_SWITCH 7
1116#define RES4328_PA_REF_LDO 8
1117#define RES4328_RADIO_LDO 9
1118#define RES4328_AFE_LDO 10
1119#define RES4328_PLL_LDO 11
1120#define RES4328_BG_FILTBYP 12
1121#define RES4328_TX_FILTBYP 13
1122#define RES4328_RX_FILTBYP 14
1123#define RES4328_XTAL_PU 15
1124#define RES4328_XTAL_EN 16
1125#define RES4328_BB_PLL_FILTBYP 17
1126#define RES4328_RF_PLL_FILTBYP 18
1127#define RES4328_BB_PLL_PU 19
1128
1129
1130#define RES4325_BUCK_BOOST_BURST 0
1131#define RES4325_CBUCK_BURST 1
1132#define RES4325_CBUCK_PWM 2
1133#define RES4325_CLDO_CBUCK_BURST 3
1134#define RES4325_CLDO_CBUCK_PWM 4
1135#define RES4325_BUCK_BOOST_PWM 5
1136#define RES4325_ILP_REQUEST 6
1137#define RES4325_ABUCK_BURST 7
1138#define RES4325_ABUCK_PWM 8
1139#define RES4325_LNLDO1_PU 9
1140#define RES4325_OTP_PU 10
1141#define RES4325_LNLDO3_PU 11
1142#define RES4325_LNLDO4_PU 12
1143#define RES4325_XTAL_PU 13
1144#define RES4325_ALP_AVAIL 14
1145#define RES4325_RX_PWRSW_PU 15
1146#define RES4325_TX_PWRSW_PU 16
1147#define RES4325_RFPLL_PWRSW_PU 17
1148#define RES4325_LOGEN_PWRSW_PU 18
1149#define RES4325_AFE_PWRSW_PU 19
1150#define RES4325_BBPLL_PWRSW_PU 20
1151#define RES4325_HT_AVAIL 21
1152
1153
1154#define RES4325B0_CBUCK_LPOM 1
1155#define RES4325B0_CBUCK_BURST 2
1156#define RES4325B0_CBUCK_PWM 3
1157#define RES4325B0_CLDO_PU 4
1158
1159
1160#define RES4325C1_LNLDO2_PU 12
1161
1162
1163#define CST4325_SPROM_OTP_SEL_MASK 0x00000003
1164#define CST4325_DEFCIS_SEL 0
1165#define CST4325_SPROM_SEL 1
1166#define CST4325_OTP_SEL 2
1167#define CST4325_OTP_PWRDN 3
1168#define CST4325_SDIO_USB_MODE_MASK 0x00000004
1169#define CST4325_SDIO_USB_MODE_SHIFT 2
1170#define CST4325_RCAL_VALID_MASK 0x00000008
1171#define CST4325_RCAL_VALID_SHIFT 3
1172#define CST4325_RCAL_VALUE_MASK 0x000001f0
1173#define CST4325_RCAL_VALUE_SHIFT 4
1174#define CST4325_PMUTOP_2B_MASK 0x00000200
1175#define CST4325_PMUTOP_2B_SHIFT 9
1176
1177#define RES4329_RESERVED0 0
1178#define RES4329_CBUCK_LPOM 1
1179#define RES4329_CBUCK_BURST 2
1180#define RES4329_CBUCK_PWM 3
1181#define RES4329_CLDO_PU 4
1182#define RES4329_PALDO_PU 5
1183#define RES4329_ILP_REQUEST 6
1184#define RES4329_RESERVED7 7
1185#define RES4329_RESERVED8 8
1186#define RES4329_LNLDO1_PU 9
1187#define RES4329_OTP_PU 10
1188#define RES4329_RESERVED11 11
1189#define RES4329_LNLDO2_PU 12
1190#define RES4329_XTAL_PU 13
1191#define RES4329_ALP_AVAIL 14
1192#define RES4329_RX_PWRSW_PU 15
1193#define RES4329_TX_PWRSW_PU 16
1194#define RES4329_RFPLL_PWRSW_PU 17
1195#define RES4329_LOGEN_PWRSW_PU 18
1196#define RES4329_AFE_PWRSW_PU 19
1197#define RES4329_BBPLL_PWRSW_PU 20
1198#define RES4329_HT_AVAIL 21
1199
1200#define CST4329_SPROM_OTP_SEL_MASK 0x00000003
1201#define CST4329_DEFCIS_SEL 0
1202#define CST4329_SPROM_SEL 1
1203#define CST4329_OTP_SEL 2
1204#define CST4329_OTP_PWRDN 3
1205#define CST4329_SPI_SDIO_MODE_MASK 0x00000004
1206#define CST4329_SPI_SDIO_MODE_SHIFT 2
1207
1208
1209#define CST4312_SPROM_OTP_SEL_MASK 0x00000003
1210#define CST4312_DEFCIS_SEL 0
1211#define CST4312_SPROM_SEL 1
1212#define CST4312_OTP_SEL 2
1213#define CST4312_OTP_BAD 3
1214
1215
1216#define RES4312_SWITCHER_BURST 0
1217#define RES4312_SWITCHER_PWM 1
1218#define RES4312_PA_REF_LDO 2
1219#define RES4312_CORE_LDO_BURST 3
1220#define RES4312_CORE_LDO_PWM 4
1221#define RES4312_RADIO_LDO 5
1222#define RES4312_ILP_REQUEST 6
1223#define RES4312_BG_FILTBYP 7
1224#define RES4312_TX_FILTBYP 8
1225#define RES4312_RX_FILTBYP 9
1226#define RES4312_XTAL_PU 10
1227#define RES4312_ALP_AVAIL 11
1228#define RES4312_BB_PLL_FILTBYP 12
1229#define RES4312_RF_PLL_FILTBYP 13
1230#define RES4312_HT_AVAIL 14
1231
1232
1233#define RES4322_RF_LDO 0
1234#define RES4322_ILP_REQUEST 1
1235#define RES4322_XTAL_PU 2
1236#define RES4322_ALP_AVAIL 3
1237#define RES4322_SI_PLL_ON 4
1238#define RES4322_HT_SI_AVAIL 5
1239#define RES4322_PHY_PLL_ON 6
1240#define RES4322_HT_PHY_AVAIL 7
1241#define RES4322_OTP_PU 8
1242
1243
1244#define CST4322_XTAL_FREQ_20_40MHZ 0x00000020
1245#define CST4322_SPROM_OTP_SEL_MASK 0x000000c0
1246#define CST4322_SPROM_OTP_SEL_SHIFT 6
1247#define CST4322_NO_SPROM_OTP 0
1248#define CST4322_SPROM_PRESENT 1
1249#define CST4322_OTP_PRESENT 2
1250#define CST4322_PCI_OR_USB 0x00000100
1251#define CST4322_BOOT_MASK 0x00000600
1252#define CST4322_BOOT_SHIFT 9
1253#define CST4322_BOOT_FROM_SRAM 0
1254#define CST4322_BOOT_FROM_ROM 1
1255#define CST4322_BOOT_FROM_FLASH 2
1256#define CST4322_BOOT_FROM_INVALID 3
1257#define CST4322_ILP_DIV_EN 0x00000800
1258#define CST4322_FLASH_TYPE_MASK 0x00001000
1259#define CST4322_FLASH_TYPE_SHIFT 12
1260#define CST4322_FLASH_TYPE_SHIFT_ST 0
1261#define CST4322_FLASH_TYPE_SHIFT_ATMEL 1
1262#define CST4322_ARM_TAP_SEL 0x00002000
1263#define CST4322_RES_INIT_MODE_MASK 0x0000c000
1264#define CST4322_RES_INIT_MODE_SHIFT 14
1265#define CST4322_RES_INIT_MODE_ILPAVAIL 0
1266#define CST4322_RES_INIT_MODE_ILPREQ 1
1267#define CST4322_RES_INIT_MODE_ALPAVAIL 2
1268#define CST4322_RES_INIT_MODE_HTAVAIL 3
1269#define CST4322_PCIPLLCLK_GATING 0x00010000
1270#define CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000
1271#define CST4322_PCI_CARDBUS_MODE 0x00040000
1272
1273
1274#define CCTRL43224_GPIO_TOGGLE 0x8000
1275#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0
1276#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0
1277
1278
1279#define RES43236_REGULATOR 0
1280#define RES43236_ILP_REQUEST 1
1281#define RES43236_XTAL_PU 2
1282#define RES43236_ALP_AVAIL 3
1283#define RES43236_SI_PLL_ON 4
1284#define RES43236_HT_SI_AVAIL 5
1285
1286
1287#define CCTRL43236_BT_COEXIST (1<<0)
1288#define CCTRL43236_SECI (1<<1)
1289#define CCTRL43236_EXT_LNA (1<<2)
1290#define CCTRL43236_ANT_MUX_2o3 (1<<3)
1291#define CCTRL43236_GSIO (1<<4)
1292
1293
1294#define CST43236_SFLASH_MASK 0x00000040
1295#define CST43236_OTP_SEL_MASK 0x00000080
1296#define CST43236_OTP_SEL_SHIFT 7
1297#define CST43236_HSIC_MASK 0x00000100
1298#define CST43236_BP_CLK 0x00000200
1299#define CST43236_BOOT_MASK 0x00001800
1300#define CST43236_BOOT_SHIFT 11
1301#define CST43236_BOOT_FROM_SRAM 0
1302#define CST43236_BOOT_FROM_ROM 1
1303#define CST43236_BOOT_FROM_FLASH 2
1304#define CST43236_BOOT_FROM_INVALID 3
1305
1306
1307#define RES43237_REGULATOR 0
1308#define RES43237_ILP_REQUEST 1
1309#define RES43237_XTAL_PU 2
1310#define RES43237_ALP_AVAIL 3
1311#define RES43237_SI_PLL_ON 4
1312#define RES43237_HT_SI_AVAIL 5
1313
1314
1315#define CCTRL43237_BT_COEXIST (1<<0)
1316#define CCTRL43237_SECI (1<<1)
1317#define CCTRL43237_EXT_LNA (1<<2)
1318#define CCTRL43237_ANT_MUX_2o3 (1<<3)
1319#define CCTRL43237_GSIO (1<<4)
1320
1321
1322#define CST43237_SFLASH_MASK 0x00000040
1323#define CST43237_OTP_SEL_MASK 0x00000080
1324#define CST43237_OTP_SEL_SHIFT 7
1325#define CST43237_HSIC_MASK 0x00000100
1326#define CST43237_BP_CLK 0x00000200
1327#define CST43237_BOOT_MASK 0x00001800
1328#define CST43237_BOOT_SHIFT 11
1329#define CST43237_BOOT_FROM_SRAM 0
1330#define CST43237_BOOT_FROM_ROM 1
1331#define CST43237_BOOT_FROM_FLASH 2
1332#define CST43237_BOOT_FROM_INVALID 3
1333
1334
1335#define RES43239_OTP_PU 9
1336#define RES43239_MACPHY_CLKAVAIL 23
1337#define RES43239_HT_AVAIL 24
1338
1339
1340#define CST43239_SPROM_MASK 0x00000002
1341#define CST43239_SFLASH_MASK 0x00000004
1342#define CST43239_RES_INIT_MODE_SHIFT 7
1343#define CST43239_RES_INIT_MODE_MASK 0x000001f0
1344#define CST43239_CHIPMODE_SDIOD(cs) ((cs) & (1 << 15))
1345#define CST43239_CHIPMODE_USB20D(cs) ((cs) & !(1 << 15))
1346#define CST43239_CHIPMODE_SDIO(cs) (((cs) & (1 << 0)) == 0)
1347#define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0))
1348
1349
1350#define CCTRL43239_XTAL_STRENGTH(ctl) ((ctl & 0x3F) << 12)
1351
1352
1353
1354
1355#define RES4315_CBUCK_LPOM 1
1356#define RES4315_CBUCK_BURST 2
1357#define RES4315_CBUCK_PWM 3
1358#define RES4315_CLDO_PU 4
1359#define RES4315_PALDO_PU 5
1360#define RES4315_ILP_REQUEST 6
1361#define RES4315_LNLDO1_PU 9
1362#define RES4315_OTP_PU 10
1363#define RES4315_LNLDO2_PU 12
1364#define RES4315_XTAL_PU 13
1365#define RES4315_ALP_AVAIL 14
1366#define RES4315_RX_PWRSW_PU 15
1367#define RES4315_TX_PWRSW_PU 16
1368#define RES4315_RFPLL_PWRSW_PU 17
1369#define RES4315_LOGEN_PWRSW_PU 18
1370#define RES4315_AFE_PWRSW_PU 19
1371#define RES4315_BBPLL_PWRSW_PU 20
1372#define RES4315_HT_AVAIL 21
1373
1374
1375#define CST4315_SPROM_OTP_SEL_MASK 0x00000003
1376#define CST4315_DEFCIS_SEL 0x00000000
1377#define CST4315_SPROM_SEL 0x00000001
1378#define CST4315_OTP_SEL 0x00000002
1379#define CST4315_OTP_PWRDN 0x00000003
1380#define CST4315_SDIO_MODE 0x00000004
1381#define CST4315_RCAL_VALID 0x00000008
1382#define CST4315_RCAL_VALUE_MASK 0x000001f0
1383#define CST4315_RCAL_VALUE_SHIFT 4
1384#define CST4315_PALDO_EXTPNP 0x00000200
1385#define CST4315_CBUCK_MODE_MASK 0x00000c00
1386#define CST4315_CBUCK_MODE_BURST 0x00000400
1387#define CST4315_CBUCK_MODE_LPBURST 0x00000c00
1388
1389
1390#define RES4319_CBUCK_LPOM 1
1391#define RES4319_CBUCK_BURST 2
1392#define RES4319_CBUCK_PWM 3
1393#define RES4319_CLDO_PU 4
1394#define RES4319_PALDO_PU 5
1395#define RES4319_ILP_REQUEST 6
1396#define RES4319_LNLDO1_PU 9
1397#define RES4319_OTP_PU 10
1398#define RES4319_LNLDO2_PU 12
1399#define RES4319_XTAL_PU 13
1400#define RES4319_ALP_AVAIL 14
1401#define RES4319_RX_PWRSW_PU 15
1402#define RES4319_TX_PWRSW_PU 16
1403#define RES4319_RFPLL_PWRSW_PU 17
1404#define RES4319_LOGEN_PWRSW_PU 18
1405#define RES4319_AFE_PWRSW_PU 19
1406#define RES4319_BBPLL_PWRSW_PU 20
1407#define RES4319_HT_AVAIL 21
1408
1409
1410#define CST4319_SPI_CPULESSUSB 0x00000001
1411#define CST4319_SPI_CLK_POL 0x00000002
1412#define CST4319_SPI_CLK_PH 0x00000008
1413#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0
1414#define CST4319_SPROM_OTP_SEL_SHIFT 6
1415#define CST4319_DEFCIS_SEL 0x00000000
1416#define CST4319_SPROM_SEL 0x00000040
1417#define CST4319_OTP_SEL 0x00000080
1418#define CST4319_OTP_PWRDN 0x000000c0
1419#define CST4319_SDIO_USB_MODE 0x00000100
1420#define CST4319_REMAP_SEL_MASK 0x00000600
1421#define CST4319_ILPDIV_EN 0x00000800
1422#define CST4319_XTAL_PD_POL 0x00001000
1423#define CST4319_LPO_SEL 0x00002000
1424#define CST4319_RES_INIT_MODE 0x0000c000
1425#define CST4319_PALDO_EXTPNP 0x00010000
1426#define CST4319_CBUCK_MODE_MASK 0x00060000
1427#define CST4319_CBUCK_MODE_BURST 0x00020000
1428#define CST4319_CBUCK_MODE_LPBURST 0x00060000
1429#define CST4319_RCAL_VALID 0x01000000
1430#define CST4319_RCAL_VALUE_MASK 0x3e000000
1431#define CST4319_RCAL_VALUE_SHIFT 25
1432
1433#define PMU1_PLL0_CHIPCTL0 0
1434#define PMU1_PLL0_CHIPCTL1 1
1435#define PMU1_PLL0_CHIPCTL2 2
1436#define CCTL_4319USB_XTAL_SEL_MASK 0x00180000
1437#define CCTL_4319USB_XTAL_SEL_SHIFT 19
1438#define CCTL_4319USB_48MHZ_PLL_SEL 1
1439#define CCTL_4319USB_24MHZ_PLL_SEL 2
1440
1441
1442#define RES4336_CBUCK_LPOM 0
1443#define RES4336_CBUCK_BURST 1
1444#define RES4336_CBUCK_LP_PWM 2
1445#define RES4336_CBUCK_PWM 3
1446#define RES4336_CLDO_PU 4
1447#define RES4336_DIS_INT_RESET_PD 5
1448#define RES4336_ILP_REQUEST 6
1449#define RES4336_LNLDO_PU 7
1450#define RES4336_LDO3P3_PU 8
1451#define RES4336_OTP_PU 9
1452#define RES4336_XTAL_PU 10
1453#define RES4336_ALP_AVAIL 11
1454#define RES4336_RADIO_PU 12
1455#define RES4336_BG_PU 13
1456#define RES4336_VREG1p4_PU_PU 14
1457#define RES4336_AFE_PWRSW_PU 15
1458#define RES4336_RX_PWRSW_PU 16
1459#define RES4336_TX_PWRSW_PU 17
1460#define RES4336_BB_PWRSW_PU 18
1461#define RES4336_SYNTH_PWRSW_PU 19
1462#define RES4336_MISC_PWRSW_PU 20
1463#define RES4336_LOGEN_PWRSW_PU 21
1464#define RES4336_BBPLL_PWRSW_PU 22
1465#define RES4336_MACPHY_CLKAVAIL 23
1466#define RES4336_HT_AVAIL 24
1467#define RES4336_RSVD 25
1468
1469
1470#define CST4336_SPI_MODE_MASK 0x00000001
1471#define CST4336_SPROM_PRESENT 0x00000002
1472#define CST4336_OTP_PRESENT 0x00000004
1473#define CST4336_ARMREMAP_0 0x00000008
1474#define CST4336_ILPDIV_EN_MASK 0x00000010
1475#define CST4336_ILPDIV_EN_SHIFT 4
1476#define CST4336_XTAL_PD_POL_MASK 0x00000020
1477#define CST4336_XTAL_PD_POL_SHIFT 5
1478#define CST4336_LPO_SEL_MASK 0x00000040
1479#define CST4336_LPO_SEL_SHIFT 6
1480#define CST4336_RES_INIT_MODE_MASK 0x00000180
1481#define CST4336_RES_INIT_MODE_SHIFT 7
1482#define CST4336_CBUCK_MODE_MASK 0x00000600
1483#define CST4336_CBUCK_MODE_SHIFT 9
1484
1485
1486#define PCTL_4336_SERIAL_ENAB (1 << 24)
1487
1488
1489#define RES4330_CBUCK_LPOM 0
1490#define RES4330_CBUCK_BURST 1
1491#define RES4330_CBUCK_LP_PWM 2
1492#define RES4330_CBUCK_PWM 3
1493#define RES4330_CLDO_PU 4
1494#define RES4330_DIS_INT_RESET_PD 5
1495#define RES4330_ILP_REQUEST 6
1496#define RES4330_LNLDO_PU 7
1497#define RES4330_LDO3P3_PU 8
1498#define RES4330_OTP_PU 9
1499#define RES4330_XTAL_PU 10
1500#define RES4330_ALP_AVAIL 11
1501#define RES4330_RADIO_PU 12
1502#define RES4330_BG_PU 13
1503#define RES4330_VREG1p4_PU_PU 14
1504#define RES4330_AFE_PWRSW_PU 15
1505#define RES4330_RX_PWRSW_PU 16
1506#define RES4330_TX_PWRSW_PU 17
1507#define RES4330_BB_PWRSW_PU 18
1508#define RES4330_SYNTH_PWRSW_PU 19
1509#define RES4330_MISC_PWRSW_PU 20
1510#define RES4330_LOGEN_PWRSW_PU 21
1511#define RES4330_BBPLL_PWRSW_PU 22
1512#define RES4330_MACPHY_CLKAVAIL 23
1513#define RES4330_HT_AVAIL 24
1514#define RES4330_5gRX_PWRSW_PU 25
1515#define RES4330_5gTX_PWRSW_PU 26
1516#define RES4330_5g_LOGEN_PWRSW_PU 27
1517
1518
1519#define CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6)
1520#define CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6)
1521#define CST4330_CHIPMODE_SDIO(cs) (((cs) & 0x4) == 0)
1522#define CST4330_CHIPMODE_GSPI(cs) (((cs) & 0x6) == 4)
1523#define CST4330_CHIPMODE_USB(cs) (((cs) & 0x7) == 6)
1524#define CST4330_CHIPMODE_USBDA(cs) (((cs) & 0x7) == 7)
1525#define CST4330_OTP_PRESENT 0x00000010
1526#define CST4330_LPO_AUTODET_EN 0x00000020
1527#define CST4330_ARMREMAP_0 0x00000040
1528#define CST4330_SPROM_PRESENT 0x00000080
1529#define CST4330_ILPDIV_EN 0x00000100
1530#define CST4330_LPO_SEL 0x00000200
1531#define CST4330_RES_INIT_MODE_SHIFT 10
1532#define CST4330_RES_INIT_MODE_MASK 0x00000c00
1533#define CST4330_CBUCK_MODE_SHIFT 12
1534#define CST4330_CBUCK_MODE_MASK 0x00003000
1535#define CST4330_CBUCK_POWER_OK 0x00004000
1536#define CST4330_BB_PLL_LOCKED 0x00008000
1537#define SOCDEVRAM_4330_BP_ADDR 0x1E000000
1538#define SOCDEVRAM_4330_ARM_ADDR 0x00800000
1539
1540
1541#define PCTL_4330_SERIAL_ENAB (1 << 24)
1542
1543
1544#define CCTRL_4330_GPIO_SEL 0x00000001
1545#define CCTRL_4330_ERCX_SEL 0x00000002
1546#define CCTRL_4330_SDIO_HOST_WAKE 0x00000004
1547#define CCTRL_4330_JTAG_DISABLE 0x00000008
1548
1549
1550#define RES4313_BB_PU_RSRC 0
1551#define RES4313_ILP_REQ_RSRC 1
1552#define RES4313_XTAL_PU_RSRC 2
1553#define RES4313_ALP_AVAIL_RSRC 3
1554#define RES4313_RADIO_PU_RSRC 4
1555#define RES4313_BG_PU_RSRC 5
1556#define RES4313_VREG1P4_PU_RSRC 6
1557#define RES4313_AFE_PWRSW_RSRC 7
1558#define RES4313_RX_PWRSW_RSRC 8
1559#define RES4313_TX_PWRSW_RSRC 9
1560#define RES4313_BB_PWRSW_RSRC 10
1561#define RES4313_SYNTH_PWRSW_RSRC 11
1562#define RES4313_MISC_PWRSW_RSRC 12
1563#define RES4313_BB_PLL_PWRSW_RSRC 13
1564#define RES4313_HT_AVAIL_RSRC 14
1565#define RES4313_MACPHY_CLK_AVAIL_RSRC 15
1566
1567
1568#define CST4313_SPROM_PRESENT 1
1569#define CST4313_OTP_PRESENT 2
1570#define CST4313_SPROM_OTP_SEL_MASK 0x00000002
1571#define CST4313_SPROM_OTP_SEL_SHIFT 0
1572
1573
1574#define CCTRL_4313_12MA_LED_DRIVE 0x00000007
1575
1576
1577#define RES43228_NOT_USED 0
1578#define RES43228_ILP_REQUEST 1
1579#define RES43228_XTAL_PU 2
1580#define RES43228_ALP_AVAIL 3
1581#define RES43228_PLL_EN 4
1582#define RES43228_HT_PHY_AVAIL 5
1583
1584
1585#define CST43228_ILP_DIV_EN 0x1
1586#define CST43228_OTP_PRESENT 0x2
1587#define CST43228_SERDES_REFCLK_PADSEL 0x4
1588#define CST43228_SDIO_MODE 0x8
1589#define CST43228_SDIO_OTP_PRESENT 0x10
1590#define CST43228_SDIO_RESET 0x20
1591
1592
1593#define PMU_MAX_TRANSITION_DLY 15000
1594
1595
1596#define PMURES_UP_TRANSITION 2
1597
1598
1599
1600
1601
1602#define ECI_BW_20 0x0
1603#define ECI_BW_25 0x1
1604#define ECI_BW_30 0x2
1605#define ECI_BW_35 0x3
1606#define ECI_BW_40 0x4
1607#define ECI_BW_45 0x5
1608#define ECI_BW_50 0x6
1609#define ECI_BW_ALL 0x7
1610
1611
1612#define WLAN_NUM_ANT1 TXANT_0
1613#define WLAN_NUM_ANT2 TXANT_1
1614
1615#endif
diff --git a/drivers/net/wireless/bcmdhd/include/sbconfig.h b/drivers/net/wireless/bcmdhd/include/sbconfig.h
new file mode 100644
index 00000000000..76f05ae34bd
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbconfig.h
@@ -0,0 +1,276 @@
1/*
2 * Broadcom SiliconBackplane hardware register definitions.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: sbconfig.h,v 13.70 2008-03-28 19:17:04 Exp $
25 */
26
27
28#ifndef _SBCONFIG_H
29#define _SBCONFIG_H
30
31
32#ifndef PAD
33#define _PADLINE(line) pad ## line
34#define _XSTR(line) _PADLINE(line)
35#define PAD _XSTR(__LINE__)
36#endif
37
38
39#define SB_BUS_SIZE 0x10000
40#define SB_BUS_BASE(b) (SI_ENUM_BASE + (b) * SB_BUS_SIZE)
41#define SB_BUS_MAXCORES (SB_BUS_SIZE / SI_CORE_SIZE)
42
43
44#define SBCONFIGOFF 0xf00
45#define SBCONFIGSIZE 256
46
47#define SBIPSFLAG 0x08
48#define SBTPSFLAG 0x18
49#define SBTMERRLOGA 0x48
50#define SBTMERRLOG 0x50
51#define SBADMATCH3 0x60
52#define SBADMATCH2 0x68
53#define SBADMATCH1 0x70
54#define SBIMSTATE 0x90
55#define SBINTVEC 0x94
56#define SBTMSTATELOW 0x98
57#define SBTMSTATEHIGH 0x9c
58#define SBBWA0 0xa0
59#define SBIMCONFIGLOW 0xa8
60#define SBIMCONFIGHIGH 0xac
61#define SBADMATCH0 0xb0
62#define SBTMCONFIGLOW 0xb8
63#define SBTMCONFIGHIGH 0xbc
64#define SBBCONFIG 0xc0
65#define SBBSTATE 0xc8
66#define SBACTCNFG 0xd8
67#define SBFLAGST 0xe8
68#define SBIDLOW 0xf8
69#define SBIDHIGH 0xfc
70
71
72
73#define SBIMERRLOGA 0xea8
74#define SBIMERRLOG 0xeb0
75#define SBTMPORTCONNID0 0xed8
76#define SBTMPORTLOCK0 0xef8
77
78#ifndef _LANGUAGE_ASSEMBLY
79
80typedef volatile struct _sbconfig {
81 uint32 PAD[2];
82 uint32 sbipsflag;
83 uint32 PAD[3];
84 uint32 sbtpsflag;
85 uint32 PAD[11];
86 uint32 sbtmerrloga;
87 uint32 PAD;
88 uint32 sbtmerrlog;
89 uint32 PAD[3];
90 uint32 sbadmatch3;
91 uint32 PAD;
92 uint32 sbadmatch2;
93 uint32 PAD;
94 uint32 sbadmatch1;
95 uint32 PAD[7];
96 uint32 sbimstate;
97 uint32 sbintvec;
98 uint32 sbtmstatelow;
99 uint32 sbtmstatehigh;
100 uint32 sbbwa0;
101 uint32 PAD;
102 uint32 sbimconfiglow;
103 uint32 sbimconfighigh;
104 uint32 sbadmatch0;
105 uint32 PAD;
106 uint32 sbtmconfiglow;
107 uint32 sbtmconfighigh;
108 uint32 sbbconfig;
109 uint32 PAD;
110 uint32 sbbstate;
111 uint32 PAD[3];
112 uint32 sbactcnfg;
113 uint32 PAD[3];
114 uint32 sbflagst;
115 uint32 PAD[3];
116 uint32 sbidlow;
117 uint32 sbidhigh;
118} sbconfig_t;
119
120#endif
121
122
123#define SBIPS_INT1_MASK 0x3f
124#define SBIPS_INT1_SHIFT 0
125#define SBIPS_INT2_MASK 0x3f00
126#define SBIPS_INT2_SHIFT 8
127#define SBIPS_INT3_MASK 0x3f0000
128#define SBIPS_INT3_SHIFT 16
129#define SBIPS_INT4_MASK 0x3f000000
130#define SBIPS_INT4_SHIFT 24
131
132
133#define SBTPS_NUM0_MASK 0x3f
134#define SBTPS_F0EN0 0x40
135
136
137#define SBTMEL_CM 0x00000007
138#define SBTMEL_CI 0x0000ff00
139#define SBTMEL_EC 0x0f000000
140#define SBTMEL_ME 0x80000000
141
142
143#define SBIM_PC 0xf
144#define SBIM_AP_MASK 0x30
145#define SBIM_AP_BOTH 0x00
146#define SBIM_AP_TS 0x10
147#define SBIM_AP_TK 0x20
148#define SBIM_AP_RSV 0x30
149#define SBIM_IBE 0x20000
150#define SBIM_TO 0x40000
151#define SBIM_BY 0x01800000
152#define SBIM_RJ 0x02000000
153
154
155#define SBTML_RESET 0x0001
156#define SBTML_REJ_MASK 0x0006
157#define SBTML_REJ 0x0002
158#define SBTML_TMPREJ 0x0004
159
160#define SBTML_SICF_SHIFT 16
161
162
163#define SBTMH_SERR 0x0001
164#define SBTMH_INT 0x0002
165#define SBTMH_BUSY 0x0004
166#define SBTMH_TO 0x0020
167
168#define SBTMH_SISF_SHIFT 16
169
170
171#define SBBWA_TAB0_MASK 0xffff
172#define SBBWA_TAB1_MASK 0xffff
173#define SBBWA_TAB1_SHIFT 16
174
175
176#define SBIMCL_STO_MASK 0x7
177#define SBIMCL_RTO_MASK 0x70
178#define SBIMCL_RTO_SHIFT 4
179#define SBIMCL_CID_MASK 0xff0000
180#define SBIMCL_CID_SHIFT 16
181
182
183#define SBIMCH_IEM_MASK 0xc
184#define SBIMCH_TEM_MASK 0x30
185#define SBIMCH_TEM_SHIFT 4
186#define SBIMCH_BEM_MASK 0xc0
187#define SBIMCH_BEM_SHIFT 6
188
189
190#define SBAM_TYPE_MASK 0x3
191#define SBAM_AD64 0x4
192#define SBAM_ADINT0_MASK 0xf8
193#define SBAM_ADINT0_SHIFT 3
194#define SBAM_ADINT1_MASK 0x1f8
195#define SBAM_ADINT1_SHIFT 3
196#define SBAM_ADINT2_MASK 0x1f8
197#define SBAM_ADINT2_SHIFT 3
198#define SBAM_ADEN 0x400
199#define SBAM_ADNEG 0x800
200#define SBAM_BASE0_MASK 0xffffff00
201#define SBAM_BASE0_SHIFT 8
202#define SBAM_BASE1_MASK 0xfffff000
203#define SBAM_BASE1_SHIFT 12
204#define SBAM_BASE2_MASK 0xffff0000
205#define SBAM_BASE2_SHIFT 16
206
207
208#define SBTMCL_CD_MASK 0xff
209#define SBTMCL_CO_MASK 0xf800
210#define SBTMCL_CO_SHIFT 11
211#define SBTMCL_IF_MASK 0xfc0000
212#define SBTMCL_IF_SHIFT 18
213#define SBTMCL_IM_MASK 0x3000000
214#define SBTMCL_IM_SHIFT 24
215
216
217#define SBTMCH_BM_MASK 0x3
218#define SBTMCH_RM_MASK 0x3
219#define SBTMCH_RM_SHIFT 2
220#define SBTMCH_SM_MASK 0x30
221#define SBTMCH_SM_SHIFT 4
222#define SBTMCH_EM_MASK 0x300
223#define SBTMCH_EM_SHIFT 8
224#define SBTMCH_IM_MASK 0xc00
225#define SBTMCH_IM_SHIFT 10
226
227
228#define SBBC_LAT_MASK 0x3
229#define SBBC_MAX0_MASK 0xf0000
230#define SBBC_MAX0_SHIFT 16
231#define SBBC_MAX1_MASK 0xf00000
232#define SBBC_MAX1_SHIFT 20
233
234
235#define SBBS_SRD 0x1
236#define SBBS_HRD 0x2
237
238
239#define SBIDL_CS_MASK 0x3
240#define SBIDL_AR_MASK 0x38
241#define SBIDL_AR_SHIFT 3
242#define SBIDL_SYNCH 0x40
243#define SBIDL_INIT 0x80
244#define SBIDL_MINLAT_MASK 0xf00
245#define SBIDL_MINLAT_SHIFT 8
246#define SBIDL_MAXLAT 0xf000
247#define SBIDL_MAXLAT_SHIFT 12
248#define SBIDL_FIRST 0x10000
249#define SBIDL_CW_MASK 0xc0000
250#define SBIDL_CW_SHIFT 18
251#define SBIDL_TP_MASK 0xf00000
252#define SBIDL_TP_SHIFT 20
253#define SBIDL_IP_MASK 0xf000000
254#define SBIDL_IP_SHIFT 24
255#define SBIDL_RV_MASK 0xf0000000
256#define SBIDL_RV_SHIFT 28
257#define SBIDL_RV_2_2 0x00000000
258#define SBIDL_RV_2_3 0x10000000
259
260
261#define SBIDH_RC_MASK 0x000f
262#define SBIDH_RCE_MASK 0x7000
263#define SBIDH_RCE_SHIFT 8
264#define SBCOREREV(sbidh) \
265 ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | ((sbidh) & SBIDH_RC_MASK))
266#define SBIDH_CC_MASK 0x8ff0
267#define SBIDH_CC_SHIFT 4
268#define SBIDH_VC_MASK 0xffff0000
269#define SBIDH_VC_SHIFT 16
270
271#define SB_COMMIT 0xfd8
272
273
274#define SB_VEND_BCM 0x4243
275
276#endif
diff --git a/drivers/net/wireless/bcmdhd/include/sbhnddma.h b/drivers/net/wireless/bcmdhd/include/sbhnddma.h
new file mode 100644
index 00000000000..05d0587bc20
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbhnddma.h
@@ -0,0 +1,327 @@
1/*
2 * Generic Broadcom Home Networking Division (HND) DMA engine HW interface
3 * This supports the following chips: BCM42xx, 44xx, 47xx .
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: sbhnddma.h,v 13.20.2.3 2010-10-14 22:21:29 Exp $
26 */
27
28
29#ifndef _sbhnddma_h_
30#define _sbhnddma_h_
31
32
33
34
35
36
37
38typedef volatile struct {
39 uint32 control;
40 uint32 addr;
41 uint32 ptr;
42 uint32 status;
43} dma32regs_t;
44
45typedef volatile struct {
46 dma32regs_t xmt;
47 dma32regs_t rcv;
48} dma32regp_t;
49
50typedef volatile struct {
51 uint32 fifoaddr;
52 uint32 fifodatalow;
53 uint32 fifodatahigh;
54 uint32 pad;
55} dma32diag_t;
56
57
58typedef volatile struct {
59 uint32 ctrl;
60 uint32 addr;
61} dma32dd_t;
62
63
64#define D32RINGALIGN_BITS 12
65#define D32MAXRINGSZ (1 << D32RINGALIGN_BITS)
66#define D32RINGALIGN (1 << D32RINGALIGN_BITS)
67
68#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t))
69
70
71#define XC_XE ((uint32)1 << 0)
72#define XC_SE ((uint32)1 << 1)
73#define XC_LE ((uint32)1 << 2)
74#define XC_FL ((uint32)1 << 4)
75#define XC_PD ((uint32)1 << 11)
76#define XC_AE ((uint32)3 << 16)
77#define XC_AE_SHIFT 16
78#define XC_BL_MASK 0x001C0000
79#define XC_BL_SHIFT 18
80
81
82#define XP_LD_MASK 0xfff
83
84
85#define XS_CD_MASK 0x0fff
86#define XS_XS_MASK 0xf000
87#define XS_XS_SHIFT 12
88#define XS_XS_DISABLED 0x0000
89#define XS_XS_ACTIVE 0x1000
90#define XS_XS_IDLE 0x2000
91#define XS_XS_STOPPED 0x3000
92#define XS_XS_SUSP 0x4000
93#define XS_XE_MASK 0xf0000
94#define XS_XE_SHIFT 16
95#define XS_XE_NOERR 0x00000
96#define XS_XE_DPE 0x10000
97#define XS_XE_DFU 0x20000
98#define XS_XE_BEBR 0x30000
99#define XS_XE_BEDA 0x40000
100#define XS_AD_MASK 0xfff00000
101#define XS_AD_SHIFT 20
102
103
104#define RC_RE ((uint32)1 << 0)
105#define RC_RO_MASK 0xfe
106#define RC_RO_SHIFT 1
107#define RC_FM ((uint32)1 << 8)
108#define RC_SH ((uint32)1 << 9)
109#define RC_OC ((uint32)1 << 10)
110#define RC_PD ((uint32)1 << 11)
111#define RC_AE ((uint32)3 << 16)
112#define RC_AE_SHIFT 16
113#define RC_BL_MASK 0x001C0000
114#define RC_BL_SHIFT 18
115
116
117#define RP_LD_MASK 0xfff
118
119
120#define RS_CD_MASK 0x0fff
121#define RS_RS_MASK 0xf000
122#define RS_RS_SHIFT 12
123#define RS_RS_DISABLED 0x0000
124#define RS_RS_ACTIVE 0x1000
125#define RS_RS_IDLE 0x2000
126#define RS_RS_STOPPED 0x3000
127#define RS_RE_MASK 0xf0000
128#define RS_RE_SHIFT 16
129#define RS_RE_NOERR 0x00000
130#define RS_RE_DPE 0x10000
131#define RS_RE_DFO 0x20000
132#define RS_RE_BEBW 0x30000
133#define RS_RE_BEDA 0x40000
134#define RS_AD_MASK 0xfff00000
135#define RS_AD_SHIFT 20
136
137
138#define FA_OFF_MASK 0xffff
139#define FA_SEL_MASK 0xf0000
140#define FA_SEL_SHIFT 16
141#define FA_SEL_XDD 0x00000
142#define FA_SEL_XDP 0x10000
143#define FA_SEL_RDD 0x40000
144#define FA_SEL_RDP 0x50000
145#define FA_SEL_XFD 0x80000
146#define FA_SEL_XFP 0x90000
147#define FA_SEL_RFD 0xc0000
148#define FA_SEL_RFP 0xd0000
149#define FA_SEL_RSD 0xe0000
150#define FA_SEL_RSP 0xf0000
151
152
153#define CTRL_BC_MASK 0x00001fff
154#define CTRL_AE ((uint32)3 << 16)
155#define CTRL_AE_SHIFT 16
156#define CTRL_PARITY ((uint32)3 << 18)
157#define CTRL_EOT ((uint32)1 << 28)
158#define CTRL_IOC ((uint32)1 << 29)
159#define CTRL_EOF ((uint32)1 << 30)
160#define CTRL_SOF ((uint32)1 << 31)
161
162
163#define CTRL_CORE_MASK 0x0ff00000
164
165
166
167
168typedef volatile struct {
169 uint32 control;
170 uint32 ptr;
171 uint32 addrlow;
172 uint32 addrhigh;
173 uint32 status0;
174 uint32 status1;
175} dma64regs_t;
176
177typedef volatile struct {
178 dma64regs_t tx;
179 dma64regs_t rx;
180} dma64regp_t;
181
182typedef volatile struct {
183 uint32 fifoaddr;
184 uint32 fifodatalow;
185 uint32 fifodatahigh;
186 uint32 pad;
187} dma64diag_t;
188
189
190typedef volatile struct {
191 uint32 ctrl1;
192 uint32 ctrl2;
193 uint32 addrlow;
194 uint32 addrhigh;
195} dma64dd_t;
196
197
198#define D64RINGALIGN_BITS 13
199#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS)
200#define D64RINGALIGN (1 << D64RINGALIGN_BITS)
201
202#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t))
203
204
205#define D64_DEF_USBBURSTLEN 2
206#define D64_DEF_SDIOBURSTLEN 1
207
208
209#define D64_XC_XE 0x00000001
210#define D64_XC_SE 0x00000002
211#define D64_XC_LE 0x00000004
212#define D64_XC_FL 0x00000010
213#define D64_XC_PD 0x00000800
214#define D64_XC_AE 0x00030000
215#define D64_XC_AE_SHIFT 16
216#define D64_XC_BL_MASK 0x001C0000
217#define D64_XC_BL_SHIFT 18
218
219
220#define D64_XP_LD_MASK 0x00000fff
221
222
223#define D64_XS0_CD_MASK 0x00001fff
224#define D64_XS0_XS_MASK 0xf0000000
225#define D64_XS0_XS_SHIFT 28
226#define D64_XS0_XS_DISABLED 0x00000000
227#define D64_XS0_XS_ACTIVE 0x10000000
228#define D64_XS0_XS_IDLE 0x20000000
229#define D64_XS0_XS_STOPPED 0x30000000
230#define D64_XS0_XS_SUSP 0x40000000
231
232#define D64_XS1_AD_MASK 0x00001fff
233#define D64_XS1_XE_MASK 0xf0000000
234#define D64_XS1_XE_SHIFT 28
235#define D64_XS1_XE_NOERR 0x00000000
236#define D64_XS1_XE_DPE 0x10000000
237#define D64_XS1_XE_DFU 0x20000000
238#define D64_XS1_XE_DTE 0x30000000
239#define D64_XS1_XE_DESRE 0x40000000
240#define D64_XS1_XE_COREE 0x50000000
241
242
243#define D64_RC_RE 0x00000001
244#define D64_RC_RO_MASK 0x000000fe
245#define D64_RC_RO_SHIFT 1
246#define D64_RC_FM 0x00000100
247#define D64_RC_SH 0x00000200
248#define D64_RC_OC 0x00000400
249#define D64_RC_PD 0x00000800
250#define D64_RC_AE 0x00030000
251#define D64_RC_AE_SHIFT 16
252#define D64_RC_BL_MASK 0x001C0000
253#define D64_RC_BL_SHIFT 18
254
255
256#define DMA_CTRL_PEN (1 << 0)
257#define DMA_CTRL_ROC (1 << 1)
258#define DMA_CTRL_RXMULTI (1 << 2)
259#define DMA_CTRL_UNFRAMED (1 << 3)
260#define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4)
261
262
263#define D64_RP_LD_MASK 0x00000fff
264
265
266#define D64_RS0_CD_MASK 0x00001fff
267#define D64_RS0_RS_MASK 0xf0000000
268#define D64_RS0_RS_SHIFT 28
269#define D64_RS0_RS_DISABLED 0x00000000
270#define D64_RS0_RS_ACTIVE 0x10000000
271#define D64_RS0_RS_IDLE 0x20000000
272#define D64_RS0_RS_STOPPED 0x30000000
273#define D64_RS0_RS_SUSP 0x40000000
274
275#define D64_RS1_AD_MASK 0x0001ffff
276#define D64_RS1_RE_MASK 0xf0000000
277#define D64_RS1_RE_SHIFT 28
278#define D64_RS1_RE_NOERR 0x00000000
279#define D64_RS1_RE_DPO 0x10000000
280#define D64_RS1_RE_DFU 0x20000000
281#define D64_RS1_RE_DTE 0x30000000
282#define D64_RS1_RE_DESRE 0x40000000
283#define D64_RS1_RE_COREE 0x50000000
284
285
286#define D64_FA_OFF_MASK 0xffff
287#define D64_FA_SEL_MASK 0xf0000
288#define D64_FA_SEL_SHIFT 16
289#define D64_FA_SEL_XDD 0x00000
290#define D64_FA_SEL_XDP 0x10000
291#define D64_FA_SEL_RDD 0x40000
292#define D64_FA_SEL_RDP 0x50000
293#define D64_FA_SEL_XFD 0x80000
294#define D64_FA_SEL_XFP 0x90000
295#define D64_FA_SEL_RFD 0xc0000
296#define D64_FA_SEL_RFP 0xd0000
297#define D64_FA_SEL_RSD 0xe0000
298#define D64_FA_SEL_RSP 0xf0000
299
300
301#define D64_CTRL_COREFLAGS 0x0ff00000
302#define D64_CTRL1_EOT ((uint32)1 << 28)
303#define D64_CTRL1_IOC ((uint32)1 << 29)
304#define D64_CTRL1_EOF ((uint32)1 << 30)
305#define D64_CTRL1_SOF ((uint32)1 << 31)
306
307
308#define D64_CTRL2_BC_MASK 0x00007fff
309#define D64_CTRL2_AE 0x00030000
310#define D64_CTRL2_AE_SHIFT 16
311#define D64_CTRL2_PARITY 0x00040000
312
313
314#define D64_CTRL_CORE_MASK 0x0ff00000
315
316#define D64_RX_FRM_STS_LEN 0x0000ffff
317#define D64_RX_FRM_STS_OVFL 0x00800000
318#define D64_RX_FRM_STS_DSCRCNT 0x0f000000
319#define D64_RX_FRM_STS_DATATYPE 0xf0000000
320
321
322typedef volatile struct {
323 uint16 len;
324 uint16 flags;
325} dma_rxh_t;
326
327#endif
diff --git a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h
new file mode 100644
index 00000000000..aba914bd014
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h
@@ -0,0 +1,109 @@
1/*
2 * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: sbpcmcia.h,v 13.48.12.6 2010-11-04 09:39:42 Exp $
25 */
26
27
28#ifndef _SBPCMCIA_H
29#define _SBPCMCIA_H
30
31
32
33
34#define PCMCIA_FCR (0x700 / 2)
35
36#define FCR0_OFF 0
37#define FCR1_OFF (0x40 / 2)
38#define FCR2_OFF (0x80 / 2)
39#define FCR3_OFF (0xc0 / 2)
40
41#define PCMCIA_FCR0 (0x700 / 2)
42#define PCMCIA_FCR1 (0x740 / 2)
43#define PCMCIA_FCR2 (0x780 / 2)
44#define PCMCIA_FCR3 (0x7c0 / 2)
45
46
47
48#define PCMCIA_COR 0
49
50#define COR_RST 0x80
51#define COR_LEV 0x40
52#define COR_IRQEN 0x04
53#define COR_BLREN 0x01
54#define COR_FUNEN 0x01
55
56
57#define PCICIA_FCSR (2 / 2)
58#define PCICIA_PRR (4 / 2)
59#define PCICIA_SCR (6 / 2)
60#define PCICIA_ESR (8 / 2)
61
62
63#define PCM_MEMOFF 0x0000
64#define F0_MEMOFF 0x1000
65#define F1_MEMOFF 0x2000
66#define F2_MEMOFF 0x3000
67#define F3_MEMOFF 0x4000
68
69
70#define MEM_ADDR0 (0x728 / 2)
71#define MEM_ADDR1 (0x72a / 2)
72#define MEM_ADDR2 (0x72c / 2)
73
74
75#define PCMCIA_ADDR0 (0x072e / 2)
76#define PCMCIA_ADDR1 (0x0730 / 2)
77#define PCMCIA_ADDR2 (0x0732 / 2)
78
79#define MEM_SEG (0x0734 / 2)
80#define SROM_CS (0x0736 / 2)
81#define SROM_DATAL (0x0738 / 2)
82#define SROM_DATAH (0x073a / 2)
83#define SROM_ADDRL (0x073c / 2)
84#define SROM_ADDRH (0x073e / 2)
85#define SROM_INFO2 (0x0772 / 2)
86#define SROM_INFO (0x07be / 2)
87
88
89#define SROM_IDLE 0
90#define SROM_WRITE 1
91#define SROM_READ 2
92#define SROM_WEN 4
93#define SROM_WDS 7
94#define SROM_DONE 8
95
96
97#define SRI_SZ_MASK 0x03
98#define SRI_BLANK 0x04
99#define SRI_OTP 0x80
100
101
102
103#define SBTML_INT_ACK 0x40000
104#define SBTML_INT_EN 0x20000
105
106
107#define SBTMH_INT_STATUS 0x40000
108
109#endif
diff --git a/drivers/net/wireless/bcmdhd/include/sbsdio.h b/drivers/net/wireless/bcmdhd/include/sbsdio.h
new file mode 100644
index 00000000000..4280d5bf9c1
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbsdio.h
@@ -0,0 +1,166 @@
1/*
2 * SDIO device core hardware definitions.
3 * sdio is a portion of the pcmcia core in core rev 3 - rev 8
4 *
5 * SDIO core support 1bit, 4 bit SDIO mode as well as SPI mode.
6 *
7 * Copyright (C) 1999-2011, Broadcom Corporation
8 *
9 * Unless you and Broadcom execute a separate written software license
10 * agreement governing use of this software, this software is licensed to you
11 * under the terms of the GNU General Public License version 2 (the "GPL"),
12 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
13 * following added to such license:
14 *
15 * As a special exception, the copyright holders of this software give you
16 * permission to link this software with independent modules, and to copy and
17 * distribute the resulting executable under terms of your choice, provided that
18 * you also meet, for each linked independent module, the terms and conditions of
19 * the license of that module. An independent module is a module which is not
20 * derived from this software. The special exception does not apply to any
21 * modifications of the software.
22 *
23 * Notwithstanding the above, under no circumstances may you combine this
24 * software in any way with any other Broadcom software provided under a license
25 * other than the GPL, without Broadcom's express prior written consent.
26 *
27 * $Id: sbsdio.h,v 13.34 2009-03-11 20:27:16 Exp $
28 */
29
30#ifndef _SBSDIO_H
31#define _SBSDIO_H
32
33#define SBSDIO_NUM_FUNCTION 3 /* as of sdiod rev 0, supports 3 functions */
34
35/* function 1 miscellaneous registers */
36#define SBSDIO_SPROM_CS 0x10000 /* sprom command and status */
37#define SBSDIO_SPROM_INFO 0x10001 /* sprom info register */
38#define SBSDIO_SPROM_DATA_LOW 0x10002 /* sprom indirect access data byte 0 */
39#define SBSDIO_SPROM_DATA_HIGH 0x10003 /* sprom indirect access data byte 1 */
40#define SBSDIO_SPROM_ADDR_LOW 0x10004 /* sprom indirect access addr byte 0 */
41#define SBSDIO_SPROM_ADDR_HIGH 0x10005 /* sprom indirect access addr byte 0 */
42#define SBSDIO_CHIP_CTRL_DATA 0x10006 /* xtal_pu (gpio) output */
43#define SBSDIO_CHIP_CTRL_EN 0x10007 /* xtal_pu (gpio) enable */
44#define SBSDIO_WATERMARK 0x10008 /* rev < 7, watermark for sdio device */
45#define SBSDIO_DEVICE_CTL 0x10009 /* control busy signal generation */
46
47/* registers introduced in rev 8, some content (mask/bits) defs in sbsdpcmdev.h */
48#define SBSDIO_FUNC1_SBADDRLOW 0x1000A /* SB Address Window Low (b15) */
49#define SBSDIO_FUNC1_SBADDRMID 0x1000B /* SB Address Window Mid (b23:b16) */
50#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C /* SB Address Window High (b31:b24) */
51#define SBSDIO_FUNC1_FRAMECTRL 0x1000D /* Frame Control (frame term/abort) */
52#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E /* ChipClockCSR (ALP/HT ctl/status) */
53#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F /* SdioPullUp (on cmd, d0-d2) */
54#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 /* Write Frame Byte Count Low */
55#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A /* Write Frame Byte Count High */
56#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B /* Read Frame Byte Count Low */
57#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C /* Read Frame Byte Count High */
58
59#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */
60#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */
61
62/* SBSDIO_SPROM_CS */
63#define SBSDIO_SPROM_IDLE 0
64#define SBSDIO_SPROM_WRITE 1
65#define SBSDIO_SPROM_READ 2
66#define SBSDIO_SPROM_WEN 4
67#define SBSDIO_SPROM_WDS 7
68#define SBSDIO_SPROM_DONE 8
69
70/* SBSDIO_SPROM_INFO */
71#define SROM_SZ_MASK 0x03 /* SROM size, 1: 4k, 2: 16k */
72#define SROM_BLANK 0x04 /* depreciated in corerev 6 */
73#define SROM_OTP 0x80 /* OTP present */
74
75/* SBSDIO_CHIP_CTRL */
76#define SBSDIO_CHIP_CTRL_XTAL 0x01 /* or'd with onchip xtal_pu,
77 * 1: power on oscillator
78 * (for 4318 only)
79 */
80/* SBSDIO_WATERMARK */
81#define SBSDIO_WATERMARK_MASK 0x7f /* number of words - 1 for sd device
82 * to wait before sending data to host
83 */
84
85/* SBSDIO_DEVICE_CTL */
86#define SBSDIO_DEVCTL_SETBUSY 0x01 /* 1: device will assert busy signal when
87 * receiving CMD53
88 */
89#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 /* 1: assertion of sdio interrupt is
90 * synchronous to the sdio clock
91 */
92#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 /* 1: mask all interrupts to host
93 * except the chipActive (rev 8)
94 */
95#define SBSDIO_DEVCTL_PADS_ISO 0x08 /* 1: isolate internal sdio signals, put
96 * external pads in tri-state; requires
97 * sdio bus power cycle to clear (rev 9)
98 */
99#define SBSDIO_DEVCTL_SB_RST_CTL 0x30 /* Force SD->SB reset mapping (rev 11) */
100#define SBSDIO_DEVCTL_RST_CORECTL 0x00 /* Determined by CoreControl bit */
101#define SBSDIO_DEVCTL_RST_BPRESET 0x10 /* Force backplane reset */
102#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 /* Force no backplane reset */
103
104
105/* SBSDIO_FUNC1_CHIPCLKCSR */
106#define SBSDIO_FORCE_ALP 0x01 /* Force ALP request to backplane */
107#define SBSDIO_FORCE_HT 0x02 /* Force HT request to backplane */
108#define SBSDIO_FORCE_ILP 0x04 /* Force ILP request to backplane */
109#define SBSDIO_ALP_AVAIL_REQ 0x08 /* Make ALP ready (power up xtal) */
110#define SBSDIO_HT_AVAIL_REQ 0x10 /* Make HT ready (power up PLL) */
111#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 /* Squelch clock requests from HW */
112#define SBSDIO_ALP_AVAIL 0x40 /* Status: ALP is ready */
113#define SBSDIO_HT_AVAIL 0x80 /* Status: HT is ready */
114/* In rev8, actual avail bits followed original docs */
115#define SBSDIO_Rev8_HT_AVAIL 0x40
116#define SBSDIO_Rev8_ALP_AVAIL 0x80
117
118#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
119#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS)
120#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
121#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
122#define SBSDIO_CLKAV(regval, alponly) (SBSDIO_ALPAV(regval) && \
123 (alponly ? 1 : SBSDIO_HTAV(regval)))
124
125/* SBSDIO_FUNC1_SDIOPULLUP */
126#define SBSDIO_PULLUP_D0 0x01 /* Enable D0/MISO pullup */
127#define SBSDIO_PULLUP_D1 0x02 /* Enable D1/INT# pullup */
128#define SBSDIO_PULLUP_D2 0x04 /* Enable D2 pullup */
129#define SBSDIO_PULLUP_CMD 0x08 /* Enable CMD/MOSI pullup */
130#define SBSDIO_PULLUP_ALL 0x0f /* All valid bits */
131
132/* function 1 OCP space */
133#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF /* sb offset addr is <= 15 bits, 32k */
134#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000
135#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 /* with b15, maps to 32-bit SB access */
136
137/* some duplication with sbsdpcmdev.h here */
138/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */
139#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */
140#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */
141#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */
142#define SBSDIO_SBWINDOW_MASK 0xffff8000 /* Address bits from SBADDR regs */
143
144/* direct(mapped) cis space */
145#define SBSDIO_CIS_BASE_COMMON 0x1000 /* MAPPED common CIS address */
146#define SBSDIO_CIS_SIZE_LIMIT 0x200 /* maximum bytes in one CIS */
147#define SBSDIO_OTP_CIS_SIZE_LIMIT 0x078 /* maximum bytes OTP CIS */
148
149#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF /* cis offset addr is < 17 bits */
150
151#define SBSDIO_CIS_MANFID_TUPLE_LEN 6 /* manfid tuple length, include tuple,
152 * link bytes
153 */
154
155/* indirect cis access (in sprom) */
156#define SBSDIO_SPROM_CIS_OFFSET 0x8 /* 8 control bytes first, CIS starts from
157 * 8th byte
158 */
159
160#define SBSDIO_BYTEMODE_DATALEN_MAX 64 /* sdio byte mode: maximum length of one
161 * data comamnd
162 */
163
164#define SBSDIO_CORE_ADDR_MASK 0x1FFFF /* sdio core function one address mask */
165
166#endif /* _SBSDIO_H */
diff --git a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h
new file mode 100644
index 00000000000..107a8b07c9e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h
@@ -0,0 +1,293 @@
1/*
2 * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific
3 * device core support
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: sbsdpcmdev.h,v 13.38 2009-09-22 22:56:45 Exp $
26 */
27
28#ifndef _sbsdpcmdev_h_
29#define _sbsdpcmdev_h_
30
31/* cpp contortions to concatenate w/arg prescan */
32#ifndef PAD
33#define _PADLINE(line) pad ## line
34#define _XSTR(line) _PADLINE(line)
35#define PAD _XSTR(__LINE__)
36#endif /* PAD */
37
38
39typedef volatile struct {
40 dma64regs_t xmt; /* dma tx */
41 uint32 PAD[2];
42 dma64regs_t rcv; /* dma rx */
43 uint32 PAD[2];
44} dma64p_t;
45
46/* dma64 sdiod corerev >= 1 */
47typedef volatile struct {
48 dma64p_t dma64regs[2];
49 dma64diag_t dmafifo; /* DMA Diagnostic Regs, 0x280-0x28c */
50 uint32 PAD[92];
51} sdiodma64_t;
52
53/* dma32 sdiod corerev == 0 */
54typedef volatile struct {
55 dma32regp_t dma32regs[2]; /* dma tx & rx, 0x200-0x23c */
56 dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x240-0x24c */
57 uint32 PAD[108];
58} sdiodma32_t;
59
60/* dma32 regs for pcmcia core */
61typedef volatile struct {
62 dma32regp_t dmaregs; /* DMA Regs, 0x200-0x21c, rev8 */
63 dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x220-0x22c */
64 uint32 PAD[116];
65} pcmdma32_t;
66
67/* core registers */
68typedef volatile struct {
69 uint32 corecontrol; /* CoreControl, 0x000, rev8 */
70 uint32 corestatus; /* CoreStatus, 0x004, rev8 */
71 uint32 PAD[1];
72 uint32 biststatus; /* BistStatus, 0x00c, rev8 */
73
74 /* PCMCIA access */
75 uint16 pcmciamesportaladdr; /* PcmciaMesPortalAddr, 0x010, rev8 */
76 uint16 PAD[1];
77 uint16 pcmciamesportalmask; /* PcmciaMesPortalMask, 0x014, rev8 */
78 uint16 PAD[1];
79 uint16 pcmciawrframebc; /* PcmciaWrFrameBC, 0x018, rev8 */
80 uint16 PAD[1];
81 uint16 pcmciaunderflowtimer; /* PcmciaUnderflowTimer, 0x01c, rev8 */
82 uint16 PAD[1];
83
84 /* interrupt */
85 uint32 intstatus; /* IntStatus, 0x020, rev8 */
86 uint32 hostintmask; /* IntHostMask, 0x024, rev8 */
87 uint32 intmask; /* IntSbMask, 0x028, rev8 */
88 uint32 sbintstatus; /* SBIntStatus, 0x02c, rev8 */
89 uint32 sbintmask; /* SBIntMask, 0x030, rev8 */
90 uint32 funcintmask; /* SDIO Function Interrupt Mask, SDIO rev4 */
91 uint32 PAD[2];
92 uint32 tosbmailbox; /* ToSBMailbox, 0x040, rev8 */
93 uint32 tohostmailbox; /* ToHostMailbox, 0x044, rev8 */
94 uint32 tosbmailboxdata; /* ToSbMailboxData, 0x048, rev8 */
95 uint32 tohostmailboxdata; /* ToHostMailboxData, 0x04c, rev8 */
96
97 /* synchronized access to registers in SDIO clock domain */
98 uint32 sdioaccess; /* SdioAccess, 0x050, rev8 */
99 uint32 PAD[3];
100
101 /* PCMCIA frame control */
102 uint8 pcmciaframectrl; /* pcmciaFrameCtrl, 0x060, rev8 */
103 uint8 PAD[3];
104 uint8 pcmciawatermark; /* pcmciaWaterMark, 0x064, rev8 */
105 uint8 PAD[155];
106
107 /* interrupt batching control */
108 uint32 intrcvlazy; /* IntRcvLazy, 0x100, rev8 */
109 uint32 PAD[3];
110
111 /* counters */
112 uint32 cmd52rd; /* Cmd52RdCount, 0x110, rev8, SDIO: cmd52 reads */
113 uint32 cmd52wr; /* Cmd52WrCount, 0x114, rev8, SDIO: cmd52 writes */
114 uint32 cmd53rd; /* Cmd53RdCount, 0x118, rev8, SDIO: cmd53 reads */
115 uint32 cmd53wr; /* Cmd53WrCount, 0x11c, rev8, SDIO: cmd53 writes */
116 uint32 abort; /* AbortCount, 0x120, rev8, SDIO: aborts */
117 uint32 datacrcerror; /* DataCrcErrorCount, 0x124, rev8, SDIO: frames w/bad CRC */
118 uint32 rdoutofsync; /* RdOutOfSyncCount, 0x128, rev8, SDIO/PCMCIA: Rd Frm OOS */
119 uint32 wroutofsync; /* RdOutOfSyncCount, 0x12c, rev8, SDIO/PCMCIA: Wr Frm OOS */
120 uint32 writebusy; /* WriteBusyCount, 0x130, rev8, SDIO: dev asserted "busy" */
121 uint32 readwait; /* ReadWaitCount, 0x134, rev8, SDIO: read: no data avail */
122 uint32 readterm; /* ReadTermCount, 0x138, rev8, SDIO: rd frm terminates */
123 uint32 writeterm; /* WriteTermCount, 0x13c, rev8, SDIO: wr frm terminates */
124 uint32 PAD[40];
125 uint32 clockctlstatus; /* ClockCtlStatus, 0x1e0, rev8 */
126 uint32 PAD[7];
127
128 /* DMA engines */
129 volatile union {
130 pcmdma32_t pcm32;
131 sdiodma32_t sdiod32;
132 sdiodma64_t sdiod64;
133 } dma;
134
135 /* SDIO/PCMCIA CIS region */
136 char cis[512]; /* 512 byte CIS, 0x400-0x5ff, rev6 */
137
138 /* PCMCIA function control registers */
139 char pcmciafcr[256]; /* PCMCIA FCR, 0x600-6ff, rev6 */
140 uint16 PAD[55];
141
142 /* PCMCIA backplane access */
143 uint16 backplanecsr; /* BackplaneCSR, 0x76E, rev6 */
144 uint16 backplaneaddr0; /* BackplaneAddr0, 0x770, rev6 */
145 uint16 backplaneaddr1; /* BackplaneAddr1, 0x772, rev6 */
146 uint16 backplaneaddr2; /* BackplaneAddr2, 0x774, rev6 */
147 uint16 backplaneaddr3; /* BackplaneAddr3, 0x776, rev6 */
148 uint16 backplanedata0; /* BackplaneData0, 0x778, rev6 */
149 uint16 backplanedata1; /* BackplaneData1, 0x77a, rev6 */
150 uint16 backplanedata2; /* BackplaneData2, 0x77c, rev6 */
151 uint16 backplanedata3; /* BackplaneData3, 0x77e, rev6 */
152 uint16 PAD[31];
153
154 /* sprom "size" & "blank" info */
155 uint16 spromstatus; /* SPROMStatus, 0x7BE, rev2 */
156 uint32 PAD[464];
157
158 /* Sonics SiliconBackplane registers */
159 sbconfig_t sbconfig; /* SbConfig Regs, 0xf00-0xfff, rev8 */
160} sdpcmd_regs_t;
161
162/* corecontrol */
163#define CC_CISRDY (1 << 0) /* CIS Ready */
164#define CC_BPRESEN (1 << 1) /* CCCR RES signal causes backplane reset */
165#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */
166#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation bit (rev 11) */
167#define CC_XMTDATAAVAIL_MODE (1 << 4) /* data avail generates an interrupt */
168#define CC_XMTDATAAVAIL_CTRL (1 << 5) /* data avail interrupt ctrl */
169
170/* corestatus */
171#define CS_PCMCIAMODE (1 << 0) /* Device Mode; 0=SDIO, 1=PCMCIA */
172#define CS_SMARTDEV (1 << 1) /* 1=smartDev enabled */
173#define CS_F2ENABLED (1 << 2) /* 1=host has enabled the device */
174
175#define PCMCIA_MES_PA_MASK 0x7fff /* PCMCIA Message Portal Address Mask */
176#define PCMCIA_MES_PM_MASK 0x7fff /* PCMCIA Message Portal Mask Mask */
177#define PCMCIA_WFBC_MASK 0xffff /* PCMCIA Write Frame Byte Count Mask */
178#define PCMCIA_UT_MASK 0x07ff /* PCMCIA Underflow Timer Mask */
179
180/* intstatus */
181#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */
182#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */
183#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */
184#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */
185#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */
186#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */
187#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */
188#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */
189#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */
190#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */
191#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */
192#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */
193#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */
194#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */
195#define I_PC (1 << 10) /* descriptor error */
196#define I_PD (1 << 11) /* data error */
197#define I_DE (1 << 12) /* Descriptor protocol Error */
198#define I_RU (1 << 13) /* Receive descriptor Underflow */
199#define I_RO (1 << 14) /* Receive fifo Overflow */
200#define I_XU (1 << 15) /* Transmit fifo Underflow */
201#define I_RI (1 << 16) /* Receive Interrupt */
202#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */
203#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */
204#define I_XI (1 << 24) /* Transmit Interrupt */
205#define I_RF_TERM (1 << 25) /* Read Frame Terminate */
206#define I_WF_TERM (1 << 26) /* Write Frame Terminate */
207#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */
208#define I_SBINT (1 << 28) /* sbintstatus Interrupt */
209#define I_CHIPACTIVE (1 << 29) /* chip transitioned from doze to active state */
210#define I_SRESET (1 << 30) /* CCCR RES interrupt */
211#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */
212#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU) /* DMA Errors */
213#define I_DMA (I_RI | I_XI | I_ERRORS)
214
215/* sbintstatus */
216#define I_SB_SERR (1 << 8) /* Backplane SError (write) */
217#define I_SB_RESPERR (1 << 9) /* Backplane Response Error (read) */
218#define I_SB_SPROMERR (1 << 10) /* Error accessing the sprom */
219
220/* sdioaccess */
221#define SDA_DATA_MASK 0x000000ff /* Read/Write Data Mask */
222#define SDA_ADDR_MASK 0x000fff00 /* Read/Write Address Mask */
223#define SDA_ADDR_SHIFT 8 /* Read/Write Address Shift */
224#define SDA_WRITE 0x01000000 /* Write bit */
225#define SDA_READ 0x00000000 /* Write bit cleared for Read */
226#define SDA_BUSY 0x80000000 /* Busy bit */
227
228/* sdioaccess-accessible register address spaces */
229#define SDA_CCCR_SPACE 0x000 /* sdioAccess CCCR register space */
230#define SDA_F1_FBR_SPACE 0x100 /* sdioAccess F1 FBR register space */
231#define SDA_F2_FBR_SPACE 0x200 /* sdioAccess F2 FBR register space */
232#define SDA_F1_REG_SPACE 0x300 /* sdioAccess F1 core-specific register space */
233
234/* SDA_F1_REG_SPACE sdioaccess-accessible F1 reg space register offsets */
235#define SDA_CHIPCONTROLDATA 0x006 /* ChipControlData */
236#define SDA_CHIPCONTROLENAB 0x007 /* ChipControlEnable */
237#define SDA_F2WATERMARK 0x008 /* Function 2 Watermark */
238#define SDA_DEVICECONTROL 0x009 /* DeviceControl */
239#define SDA_SBADDRLOW 0x00a /* SbAddrLow */
240#define SDA_SBADDRMID 0x00b /* SbAddrMid */
241#define SDA_SBADDRHIGH 0x00c /* SbAddrHigh */
242#define SDA_FRAMECTRL 0x00d /* FrameCtrl */
243#define SDA_CHIPCLOCKCSR 0x00e /* ChipClockCSR */
244#define SDA_SDIOPULLUP 0x00f /* SdioPullUp */
245#define SDA_SDIOWRFRAMEBCLOW 0x019 /* SdioWrFrameBCLow */
246#define SDA_SDIOWRFRAMEBCHIGH 0x01a /* SdioWrFrameBCHigh */
247#define SDA_SDIORDFRAMEBCLOW 0x01b /* SdioRdFrameBCLow */
248#define SDA_SDIORDFRAMEBCHIGH 0x01c /* SdioRdFrameBCHigh */
249
250/* SDA_F2WATERMARK */
251#define SDA_F2WATERMARK_MASK 0x7f /* F2Watermark Mask */
252
253/* SDA_SBADDRLOW */
254#define SDA_SBADDRLOW_MASK 0x80 /* SbAddrLow Mask */
255
256/* SDA_SBADDRMID */
257#define SDA_SBADDRMID_MASK 0xff /* SbAddrMid Mask */
258
259/* SDA_SBADDRHIGH */
260#define SDA_SBADDRHIGH_MASK 0xff /* SbAddrHigh Mask */
261
262/* SDA_FRAMECTRL */
263#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */
264#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */
265#define SFC_CRC4WOOS (1 << 2) /* HW reports CRC error for write out of sync */
266#define SFC_ABORTALL (1 << 3) /* Abort cancels all in-progress frames */
267
268/* pcmciaframectrl */
269#define PFC_RF_TERM (1 << 0) /* Read Frame Terminate */
270#define PFC_WF_TERM (1 << 1) /* Write Frame Terminate */
271
272/* intrcvlazy */
273#define IRL_TO_MASK 0x00ffffff /* timeout */
274#define IRL_FC_MASK 0xff000000 /* frame count */
275#define IRL_FC_SHIFT 24 /* frame count */
276
277/* rx header */
278typedef volatile struct {
279 uint16 len;
280 uint16 flags;
281} sdpcmd_rxh_t;
282
283/* rx header flags */
284#define RXF_CRC 0x0001 /* CRC error detected */
285#define RXF_WOOS 0x0002 /* write frame out of sync */
286#define RXF_WF_TERM 0x0004 /* write frame terminated */
287#define RXF_ABORT 0x0008 /* write frame aborted */
288#define RXF_DISCARD (RXF_CRC | RXF_WOOS | RXF_WF_TERM | RXF_ABORT) /* bad frame */
289
290/* HW frame tag */
291#define SDPCM_FRAMETAG_LEN 4 /* HW frametag: 2 bytes len, 2 bytes check val */
292
293#endif /* _sbsdpcmdev_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/sbsocram.h b/drivers/net/wireless/bcmdhd/include/sbsocram.h
new file mode 100644
index 00000000000..1cba4223890
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sbsocram.h
@@ -0,0 +1,186 @@
1/*
2 * BCM47XX Sonics SiliconBackplane embedded ram core
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: sbsocram.h,v 13.15 2009-10-02 16:55:44 Exp $
25 */
26
27
28#ifndef _SBSOCRAM_H
29#define _SBSOCRAM_H
30
31#ifndef _LANGUAGE_ASSEMBLY
32
33
34#ifndef PAD
35#define _PADLINE(line) pad ## line
36#define _XSTR(line) _PADLINE(line)
37#define PAD _XSTR(__LINE__)
38#endif
39
40
41typedef volatile struct sbsocramregs {
42 uint32 coreinfo;
43 uint32 bwalloc;
44 uint32 extracoreinfo;
45 uint32 biststat;
46 uint32 bankidx;
47 uint32 standbyctrl;
48
49 uint32 errlogstatus;
50 uint32 errlogaddr;
51
52 uint32 cambankidx;
53 uint32 cambankstandbyctrl;
54 uint32 cambankpatchctrl;
55 uint32 cambankpatchtblbaseaddr;
56 uint32 cambankcmdreg;
57 uint32 cambankdatareg;
58 uint32 cambankmaskreg;
59 uint32 PAD[1];
60 uint32 bankinfo;
61 uint32 PAD[15];
62 uint32 extmemconfig;
63 uint32 extmemparitycsr;
64 uint32 extmemparityerrdata;
65 uint32 extmemparityerrcnt;
66 uint32 extmemwrctrlandsize;
67 uint32 PAD[84];
68 uint32 workaround;
69 uint32 pwrctl;
70 uint32 PAD[133];
71 uint32 sr_control;
72 uint32 sr_status;
73 uint32 sr_address;
74 uint32 sr_data;
75} sbsocramregs_t;
76
77#endif
78
79
80#define SR_COREINFO 0x00
81#define SR_BWALLOC 0x04
82#define SR_BISTSTAT 0x0c
83#define SR_BANKINDEX 0x10
84#define SR_BANKSTBYCTL 0x14
85#define SR_PWRCTL 0x1e8
86
87
88#define SRCI_PT_MASK 0x00070000
89#define SRCI_PT_SHIFT 16
90
91#define SRCI_PT_OCP_OCP 0
92#define SRCI_PT_AXI_OCP 1
93#define SRCI_PT_ARM7AHB_OCP 2
94#define SRCI_PT_CM3AHB_OCP 3
95#define SRCI_PT_AXI_AXI 4
96#define SRCI_PT_AHB_AXI 5
97
98#define SRCI_LSS_MASK 0x00f00000
99#define SRCI_LSS_SHIFT 20
100#define SRCI_LRS_MASK 0x0f000000
101#define SRCI_LRS_SHIFT 24
102
103
104#define SRCI_MS0_MASK 0xf
105#define SR_MS0_BASE 16
106
107
108#define SRCI_ROMNB_MASK 0xf000
109#define SRCI_ROMNB_SHIFT 12
110#define SRCI_ROMBSZ_MASK 0xf00
111#define SRCI_ROMBSZ_SHIFT 8
112#define SRCI_SRNB_MASK 0xf0
113#define SRCI_SRNB_SHIFT 4
114#define SRCI_SRBSZ_MASK 0xf
115#define SRCI_SRBSZ_SHIFT 0
116
117#define SR_BSZ_BASE 14
118
119
120#define SRSC_SBYOVR_MASK 0x80000000
121#define SRSC_SBYOVR_SHIFT 31
122#define SRSC_SBYOVRVAL_MASK 0x60000000
123#define SRSC_SBYOVRVAL_SHIFT 29
124#define SRSC_SBYEN_MASK 0x01000000
125#define SRSC_SBYEN_SHIFT 24
126
127
128#define SRPC_PMU_STBYDIS_MASK 0x00000010
129#define SRPC_PMU_STBYDIS_SHIFT 4
130#define SRPC_STBYOVRVAL_MASK 0x00000008
131#define SRPC_STBYOVRVAL_SHIFT 3
132#define SRPC_STBYOVR_MASK 0x00000007
133#define SRPC_STBYOVR_SHIFT 0
134
135
136#define SRECC_NUM_BANKS_MASK 0x000000F0
137#define SRECC_NUM_BANKS_SHIFT 4
138#define SRECC_BANKSIZE_MASK 0x0000000F
139#define SRECC_BANKSIZE_SHIFT 0
140
141#define SRECC_BANKSIZE(value) (1 << (value))
142
143
144#define SRCBPC_PATCHENABLE 0x80000000
145
146#define SRP_ADDRESS 0x0001FFFC
147#define SRP_VALID 0x8000
148
149
150#define SRCMD_WRITE 0x00020000
151#define SRCMD_READ 0x00010000
152#define SRCMD_DONE 0x80000000
153
154#define SRCMD_DONE_DLY 1000
155
156
157#define SOCRAM_BANKINFO_SZMASK 0x3f
158#define SOCRAM_BANKIDX_ROM_MASK 0x100
159
160#define SOCRAM_BANKIDX_MEMTYPE_SHIFT 8
161
162#define SOCRAM_MEMTYPE_RAM 0
163#define SOCRAM_MEMTYPE_R0M 1
164#define SOCRAM_MEMTYPE_DEVRAM 2
165
166#define SOCRAM_BANKINFO_REG 0x40
167#define SOCRAM_BANKIDX_REG 0x10
168#define SOCRAM_BANKINFO_STDBY_MASK 0x400
169#define SOCRAM_BANKINFO_STDBY_TIMER 0x800
170
171
172#define SOCRAM_BANKINFO_DEVRAMSEL_SHIFT 13
173#define SOCRAM_BANKINFO_DEVRAMSEL_MASK 0x2000
174#define SOCRAM_BANKINFO_DEVRAMPRO_SHIFT 14
175#define SOCRAM_BANKINFO_DEVRAMPRO_MASK 0x4000
176
177
178#define SOCRAM_DEVRAMBANK_MASK 0xF000
179#define SOCRAM_DEVRAMBANK_SHIFT 12
180
181
182#define SOCRAM_BANKINFO_SZBASE 8192
183#define SOCRAM_BANKSIZE_SHIFT 13
184
185
186#endif
diff --git a/drivers/net/wireless/bcmdhd/include/sdio.h b/drivers/net/wireless/bcmdhd/include/sdio.h
new file mode 100644
index 00000000000..ca932266a1b
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sdio.h
@@ -0,0 +1,611 @@
1/*
2 * SDIO spec header file
3 * Protocol and standard (common) device definitions
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: sdio.h,v 13.27.14.1 2010-09-07 13:37:45 Exp $
26 */
27
28#ifndef _SDIO_H
29#define _SDIO_H
30
31
32/* CCCR structure for function 0 */
33typedef volatile struct {
34 uint8 cccr_sdio_rev; /* RO, cccr and sdio revision */
35 uint8 sd_rev; /* RO, sd spec revision */
36 uint8 io_en; /* I/O enable */
37 uint8 io_rdy; /* I/O ready reg */
38 uint8 intr_ctl; /* Master and per function interrupt enable control */
39 uint8 intr_status; /* RO, interrupt pending status */
40 uint8 io_abort; /* read/write abort or reset all functions */
41 uint8 bus_inter; /* bus interface control */
42 uint8 capability; /* RO, card capability */
43
44 uint8 cis_base_low; /* 0x9 RO, common CIS base address, LSB */
45 uint8 cis_base_mid;
46 uint8 cis_base_high; /* 0xB RO, common CIS base address, MSB */
47
48 /* suspend/resume registers */
49 uint8 bus_suspend; /* 0xC */
50 uint8 func_select; /* 0xD */
51 uint8 exec_flag; /* 0xE */
52 uint8 ready_flag; /* 0xF */
53
54 uint8 fn0_blk_size[2]; /* 0x10(LSB), 0x11(MSB) */
55
56 uint8 power_control; /* 0x12 (SDIO version 1.10) */
57
58 uint8 speed_control; /* 0x13 */
59} sdio_regs_t;
60
61/* SDIO Device CCCR offsets */
62#define SDIOD_CCCR_REV 0x00
63#define SDIOD_CCCR_SDREV 0x01
64#define SDIOD_CCCR_IOEN 0x02
65#define SDIOD_CCCR_IORDY 0x03
66#define SDIOD_CCCR_INTEN 0x04
67#define SDIOD_CCCR_INTPEND 0x05
68#define SDIOD_CCCR_IOABORT 0x06
69#define SDIOD_CCCR_BICTRL 0x07
70#define SDIOD_CCCR_CAPABLITIES 0x08
71#define SDIOD_CCCR_CISPTR_0 0x09
72#define SDIOD_CCCR_CISPTR_1 0x0A
73#define SDIOD_CCCR_CISPTR_2 0x0B
74#define SDIOD_CCCR_BUSSUSP 0x0C
75#define SDIOD_CCCR_FUNCSEL 0x0D
76#define SDIOD_CCCR_EXECFLAGS 0x0E
77#define SDIOD_CCCR_RDYFLAGS 0x0F
78#define SDIOD_CCCR_BLKSIZE_0 0x10
79#define SDIOD_CCCR_BLKSIZE_1 0x11
80#define SDIOD_CCCR_POWER_CONTROL 0x12
81#define SDIOD_CCCR_SPEED_CONTROL 0x13
82#define SDIOD_CCCR_UHSI_SUPPORT 0x14
83#define SDIOD_CCCR_DRIVER_STRENGTH 0x15
84#define SDIOD_CCCR_INTR_EXTN 0x16
85
86/* Broadcom extensions (corerev >= 1) */
87#define SDIOD_CCCR_BRCM_SEPINT 0xf2
88
89/* cccr_sdio_rev */
90#define SDIO_REV_SDIOID_MASK 0xf0 /* SDIO spec revision number */
91#define SDIO_REV_CCCRID_MASK 0x0f /* CCCR format version number */
92
93/* sd_rev */
94#define SD_REV_PHY_MASK 0x0f /* SD format version number */
95
96/* io_en */
97#define SDIO_FUNC_ENABLE_1 0x02 /* function 1 I/O enable */
98#define SDIO_FUNC_ENABLE_2 0x04 /* function 2 I/O enable */
99
100/* io_rdys */
101#define SDIO_FUNC_READY_1 0x02 /* function 1 I/O ready */
102#define SDIO_FUNC_READY_2 0x04 /* function 2 I/O ready */
103
104/* intr_ctl */
105#define INTR_CTL_MASTER_EN 0x1 /* interrupt enable master */
106#define INTR_CTL_FUNC1_EN 0x2 /* interrupt enable for function 1 */
107#define INTR_CTL_FUNC2_EN 0x4 /* interrupt enable for function 2 */
108
109/* intr_status */
110#define INTR_STATUS_FUNC1 0x2 /* interrupt pending for function 1 */
111#define INTR_STATUS_FUNC2 0x4 /* interrupt pending for function 2 */
112
113/* io_abort */
114#define IO_ABORT_RESET_ALL 0x08 /* I/O card reset */
115#define IO_ABORT_FUNC_MASK 0x07 /* abort selction: function x */
116
117/* bus_inter */
118#define BUS_CARD_DETECT_DIS 0x80 /* Card Detect disable */
119#define BUS_SPI_CONT_INTR_CAP 0x40 /* support continuous SPI interrupt */
120#define BUS_SPI_CONT_INTR_EN 0x20 /* continuous SPI interrupt enable */
121#define BUS_SD_DATA_WIDTH_MASK 0x03 /* bus width mask */
122#define BUS_SD_DATA_WIDTH_4BIT 0x02 /* bus width 4-bit mode */
123#define BUS_SD_DATA_WIDTH_1BIT 0x00 /* bus width 1-bit mode */
124
125/* capability */
126#define SDIO_CAP_4BLS 0x80 /* 4-bit support for low speed card */
127#define SDIO_CAP_LSC 0x40 /* low speed card */
128#define SDIO_CAP_E4MI 0x20 /* enable interrupt between block of data in 4-bit mode */
129#define SDIO_CAP_S4MI 0x10 /* support interrupt between block of data in 4-bit mode */
130#define SDIO_CAP_SBS 0x08 /* support suspend/resume */
131#define SDIO_CAP_SRW 0x04 /* support read wait */
132#define SDIO_CAP_SMB 0x02 /* support multi-block transfer */
133#define SDIO_CAP_SDC 0x01 /* Support Direct commands during multi-byte transfer */
134
135/* power_control */
136#define SDIO_POWER_SMPC 0x01 /* supports master power control (RO) */
137#define SDIO_POWER_EMPC 0x02 /* enable master power control (allow > 200mA) (RW) */
138
139/* speed_control (control device entry into high-speed clocking mode) */
140#define SDIO_SPEED_SHS 0x01 /* supports high-speed [clocking] mode (RO) */
141#define SDIO_SPEED_EHS 0x02 /* enable high-speed [clocking] mode (RW) */
142
143/* for setting bus speed in card: 0x13h */
144#define SDIO_BUS_SPEED_UHSISEL_M BITFIELD_MASK(3)
145#define SDIO_BUS_SPEED_UHSISEL_S 1
146
147/* for getting bus speed cap in card: 0x14h */
148#define SDIO_BUS_SPEED_UHSICAP_M BITFIELD_MASK(3)
149#define SDIO_BUS_SPEED_UHSICAP_S 0
150
151/* for getting driver type CAP in card: 0x15h */
152#define SDIO_BUS_DRVR_TYPE_CAP_M BITFIELD_MASK(3)
153#define SDIO_BUS_DRVR_TYPE_CAP_S 0
154
155/* for setting driver type selection in card: 0x15h */
156#define SDIO_BUS_DRVR_TYPE_SEL_M BITFIELD_MASK(2)
157#define SDIO_BUS_DRVR_TYPE_SEL_S 4
158
159/* for getting async int support in card: 0x16h */
160#define SDIO_BUS_ASYNCINT_CAP_M BITFIELD_MASK(1)
161#define SDIO_BUS_ASYNCINT_CAP_S 0
162
163/* for setting async int selection in card: 0x16h */
164#define SDIO_BUS_ASYNCINT_SEL_M BITFIELD_MASK(1)
165#define SDIO_BUS_ASYNCINT_SEL_S 1
166
167/* brcm sepint */
168#define SDIO_SEPINT_MASK 0x01 /* route sdpcmdev intr onto separate pad (chip-specific) */
169#define SDIO_SEPINT_OE 0x02 /* 1 asserts output enable for above pad */
170#define SDIO_SEPINT_ACT_HI 0x04 /* use active high interrupt level instead of active low */
171
172/* FBR structure for function 1-7, FBR addresses and register offsets */
173typedef volatile struct {
174 uint8 devctr; /* device interface, CSA control */
175 uint8 ext_dev; /* extended standard I/O device type code */
176 uint8 pwr_sel; /* power selection support */
177 uint8 PAD[6]; /* reserved */
178
179 uint8 cis_low; /* CIS LSB */
180 uint8 cis_mid;
181 uint8 cis_high; /* CIS MSB */
182 uint8 csa_low; /* code storage area, LSB */
183 uint8 csa_mid;
184 uint8 csa_high; /* code storage area, MSB */
185 uint8 csa_dat_win; /* data access window to function */
186
187 uint8 fnx_blk_size[2]; /* block size, little endian */
188} sdio_fbr_t;
189
190/* Maximum number of I/O funcs */
191#define SDIOD_MAX_IOFUNCS 7
192
193/* SDIO Device FBR Start Address */
194#define SDIOD_FBR_STARTADDR 0x100
195
196/* SDIO Device FBR Size */
197#define SDIOD_FBR_SIZE 0x100
198
199/* Macro to calculate FBR register base */
200#define SDIOD_FBR_BASE(n) ((n) * 0x100)
201
202/* Function register offsets */
203#define SDIOD_FBR_DEVCTR 0x00 /* basic info for function */
204#define SDIOD_FBR_EXT_DEV 0x01 /* extended I/O device code */
205#define SDIOD_FBR_PWR_SEL 0x02 /* power selection bits */
206
207/* SDIO Function CIS ptr offset */
208#define SDIOD_FBR_CISPTR_0 0x09
209#define SDIOD_FBR_CISPTR_1 0x0A
210#define SDIOD_FBR_CISPTR_2 0x0B
211
212/* Code Storage Area pointer */
213#define SDIOD_FBR_CSA_ADDR_0 0x0C
214#define SDIOD_FBR_CSA_ADDR_1 0x0D
215#define SDIOD_FBR_CSA_ADDR_2 0x0E
216#define SDIOD_FBR_CSA_DATA 0x0F
217
218/* SDIO Function I/O Block Size */
219#define SDIOD_FBR_BLKSIZE_0 0x10
220#define SDIOD_FBR_BLKSIZE_1 0x11
221
222/* devctr */
223#define SDIOD_FBR_DEVCTR_DIC 0x0f /* device interface code */
224#define SDIOD_FBR_DECVTR_CSA 0x40 /* CSA support flag */
225#define SDIOD_FBR_DEVCTR_CSA_EN 0x80 /* CSA enabled */
226/* interface codes */
227#define SDIOD_DIC_NONE 0 /* SDIO standard interface is not supported */
228#define SDIOD_DIC_UART 1
229#define SDIOD_DIC_BLUETOOTH_A 2
230#define SDIOD_DIC_BLUETOOTH_B 3
231#define SDIOD_DIC_GPS 4
232#define SDIOD_DIC_CAMERA 5
233#define SDIOD_DIC_PHS 6
234#define SDIOD_DIC_WLAN 7
235#define SDIOD_DIC_EXT 0xf /* extended device interface, read ext_dev register */
236
237/* pwr_sel */
238#define SDIOD_PWR_SEL_SPS 0x01 /* supports power selection */
239#define SDIOD_PWR_SEL_EPS 0x02 /* enable power selection (low-current mode) */
240
241/* misc defines */
242#define SDIO_FUNC_0 0
243#define SDIO_FUNC_1 1
244#define SDIO_FUNC_2 2
245#define SDIO_FUNC_3 3
246#define SDIO_FUNC_4 4
247#define SDIO_FUNC_5 5
248#define SDIO_FUNC_6 6
249#define SDIO_FUNC_7 7
250
251#define SD_CARD_TYPE_UNKNOWN 0 /* bad type or unrecognized */
252#define SD_CARD_TYPE_IO 1 /* IO only card */
253#define SD_CARD_TYPE_MEMORY 2 /* memory only card */
254#define SD_CARD_TYPE_COMBO 3 /* IO and memory combo card */
255
256#define SDIO_MAX_BLOCK_SIZE 2048 /* maximum block size for block mode operation */
257#define SDIO_MIN_BLOCK_SIZE 1 /* minimum block size for block mode operation */
258
259/* Card registers: status bit position */
260#define CARDREG_STATUS_BIT_OUTOFRANGE 31
261#define CARDREG_STATUS_BIT_COMCRCERROR 23
262#define CARDREG_STATUS_BIT_ILLEGALCOMMAND 22
263#define CARDREG_STATUS_BIT_ERROR 19
264#define CARDREG_STATUS_BIT_IOCURRENTSTATE3 12
265#define CARDREG_STATUS_BIT_IOCURRENTSTATE2 11
266#define CARDREG_STATUS_BIT_IOCURRENTSTATE1 10
267#define CARDREG_STATUS_BIT_IOCURRENTSTATE0 9
268#define CARDREG_STATUS_BIT_FUN_NUM_ERROR 4
269
270
271
272#define SD_CMD_GO_IDLE_STATE 0 /* mandatory for SDIO */
273#define SD_CMD_SEND_OPCOND 1
274#define SD_CMD_MMC_SET_RCA 3
275#define SD_CMD_IO_SEND_OP_COND 5 /* mandatory for SDIO */
276#define SD_CMD_SELECT_DESELECT_CARD 7
277#define SD_CMD_SEND_CSD 9
278#define SD_CMD_SEND_CID 10
279#define SD_CMD_STOP_TRANSMISSION 12
280#define SD_CMD_SEND_STATUS 13
281#define SD_CMD_GO_INACTIVE_STATE 15
282#define SD_CMD_SET_BLOCKLEN 16
283#define SD_CMD_READ_SINGLE_BLOCK 17
284#define SD_CMD_READ_MULTIPLE_BLOCK 18
285#define SD_CMD_WRITE_BLOCK 24
286#define SD_CMD_WRITE_MULTIPLE_BLOCK 25
287#define SD_CMD_PROGRAM_CSD 27
288#define SD_CMD_SET_WRITE_PROT 28
289#define SD_CMD_CLR_WRITE_PROT 29
290#define SD_CMD_SEND_WRITE_PROT 30
291#define SD_CMD_ERASE_WR_BLK_START 32
292#define SD_CMD_ERASE_WR_BLK_END 33
293#define SD_CMD_ERASE 38
294#define SD_CMD_LOCK_UNLOCK 42
295#define SD_CMD_IO_RW_DIRECT 52 /* mandatory for SDIO */
296#define SD_CMD_IO_RW_EXTENDED 53 /* mandatory for SDIO */
297#define SD_CMD_APP_CMD 55
298#define SD_CMD_GEN_CMD 56
299#define SD_CMD_READ_OCR 58
300#define SD_CMD_CRC_ON_OFF 59 /* mandatory for SDIO */
301#define SD_ACMD_SD_STATUS 13
302#define SD_ACMD_SEND_NUM_WR_BLOCKS 22
303#define SD_ACMD_SET_WR_BLOCK_ERASE_CNT 23
304#define SD_ACMD_SD_SEND_OP_COND 41
305#define SD_ACMD_SET_CLR_CARD_DETECT 42
306#define SD_ACMD_SEND_SCR 51
307
308/* argument for SD_CMD_IO_RW_DIRECT and SD_CMD_IO_RW_EXTENDED */
309#define SD_IO_OP_READ 0 /* Read_Write: Read */
310#define SD_IO_OP_WRITE 1 /* Read_Write: Write */
311#define SD_IO_RW_NORMAL 0 /* no RAW */
312#define SD_IO_RW_RAW 1 /* RAW */
313#define SD_IO_BYTE_MODE 0 /* Byte Mode */
314#define SD_IO_BLOCK_MODE 1 /* BlockMode */
315#define SD_IO_FIXED_ADDRESS 0 /* fix Address */
316#define SD_IO_INCREMENT_ADDRESS 1 /* IncrementAddress */
317
318/* build SD_CMD_IO_RW_DIRECT Argument */
319#define SDIO_IO_RW_DIRECT_ARG(rw, raw, func, addr, data) \
320 ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((raw) & 1) << 27) | \
321 (((addr) & 0x1FFFF) << 9) | ((data) & 0xFF))
322
323/* build SD_CMD_IO_RW_EXTENDED Argument */
324#define SDIO_IO_RW_EXTENDED_ARG(rw, blk, func, addr, inc_addr, count) \
325 ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((blk) & 1) << 27) | \
326 (((inc_addr) & 1) << 26) | (((addr) & 0x1FFFF) << 9) | ((count) & 0x1FF))
327
328/* SDIO response parameters */
329#define SD_RSP_NO_NONE 0
330#define SD_RSP_NO_1 1
331#define SD_RSP_NO_2 2
332#define SD_RSP_NO_3 3
333#define SD_RSP_NO_4 4
334#define SD_RSP_NO_5 5
335#define SD_RSP_NO_6 6
336
337 /* Modified R6 response (to CMD3) */
338#define SD_RSP_MR6_COM_CRC_ERROR 0x8000
339#define SD_RSP_MR6_ILLEGAL_COMMAND 0x4000
340#define SD_RSP_MR6_ERROR 0x2000
341
342 /* Modified R1 in R4 Response (to CMD5) */
343#define SD_RSP_MR1_SBIT 0x80
344#define SD_RSP_MR1_PARAMETER_ERROR 0x40
345#define SD_RSP_MR1_RFU5 0x20
346#define SD_RSP_MR1_FUNC_NUM_ERROR 0x10
347#define SD_RSP_MR1_COM_CRC_ERROR 0x08
348#define SD_RSP_MR1_ILLEGAL_COMMAND 0x04
349#define SD_RSP_MR1_RFU1 0x02
350#define SD_RSP_MR1_IDLE_STATE 0x01
351
352 /* R5 response (to CMD52 and CMD53) */
353#define SD_RSP_R5_COM_CRC_ERROR 0x80
354#define SD_RSP_R5_ILLEGAL_COMMAND 0x40
355#define SD_RSP_R5_IO_CURRENTSTATE1 0x20
356#define SD_RSP_R5_IO_CURRENTSTATE0 0x10
357#define SD_RSP_R5_ERROR 0x08
358#define SD_RSP_R5_RFU 0x04
359#define SD_RSP_R5_FUNC_NUM_ERROR 0x02
360#define SD_RSP_R5_OUT_OF_RANGE 0x01
361
362#define SD_RSP_R5_ERRBITS 0xCB
363
364
365/* ------------------------------------------------
366 * SDIO Commands and responses
367 *
368 * I/O only commands are:
369 * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53
370 * ------------------------------------------------
371 */
372
373/* SDIO Commands */
374#define SDIOH_CMD_0 0
375#define SDIOH_CMD_3 3
376#define SDIOH_CMD_5 5
377#define SDIOH_CMD_7 7
378#define SDIOH_CMD_11 11
379#define SDIOH_CMD_14 14
380#define SDIOH_CMD_15 15
381#define SDIOH_CMD_19 19
382#define SDIOH_CMD_52 52
383#define SDIOH_CMD_53 53
384#define SDIOH_CMD_59 59
385
386/* SDIO Command Responses */
387#define SDIOH_RSP_NONE 0
388#define SDIOH_RSP_R1 1
389#define SDIOH_RSP_R2 2
390#define SDIOH_RSP_R3 3
391#define SDIOH_RSP_R4 4
392#define SDIOH_RSP_R5 5
393#define SDIOH_RSP_R6 6
394
395/*
396 * SDIO Response Error flags
397 */
398#define SDIOH_RSP5_ERROR_FLAGS 0xCB
399
400/* ------------------------------------------------
401 * SDIO Command structures. I/O only commands are:
402 *
403 * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53
404 * ------------------------------------------------
405 */
406
407#define CMD5_OCR_M BITFIELD_MASK(24)
408#define CMD5_OCR_S 0
409
410#define CMD5_S18R_M BITFIELD_MASK(1)
411#define CMD5_S18R_S 24
412
413#define CMD7_RCA_M BITFIELD_MASK(16)
414#define CMD7_RCA_S 16
415#define CMD14_RCA_M BITFIELD_MASK(16)
416#define CMD14_RCA_S 16
417#define CMD14_SLEEP_M BITFIELD_MASK(1)
418#define CMD14_SLEEP_S 15
419
420#define CMD_15_RCA_M BITFIELD_MASK(16)
421#define CMD_15_RCA_S 16
422
423#define CMD52_DATA_M BITFIELD_MASK(8) /* Bits [7:0] - Write Data/Stuff bits of CMD52
424 */
425#define CMD52_DATA_S 0
426#define CMD52_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */
427#define CMD52_REG_ADDR_S 9
428#define CMD52_RAW_M BITFIELD_MASK(1) /* Bit 27 - Read after Write flag */
429#define CMD52_RAW_S 27
430#define CMD52_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */
431#define CMD52_FUNCTION_S 28
432#define CMD52_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */
433#define CMD52_RW_FLAG_S 31
434
435
436#define CMD53_BYTE_BLK_CNT_M BITFIELD_MASK(9) /* Bits [8:0] - Byte/Block Count of CMD53 */
437#define CMD53_BYTE_BLK_CNT_S 0
438#define CMD53_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */
439#define CMD53_REG_ADDR_S 9
440#define CMD53_OP_CODE_M BITFIELD_MASK(1) /* Bit 26 - R/W Operation Code */
441#define CMD53_OP_CODE_S 26
442#define CMD53_BLK_MODE_M BITFIELD_MASK(1) /* Bit 27 - Block Mode */
443#define CMD53_BLK_MODE_S 27
444#define CMD53_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */
445#define CMD53_FUNCTION_S 28
446#define CMD53_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */
447#define CMD53_RW_FLAG_S 31
448
449/* ------------------------------------------------------
450 * SDIO Command Response structures for SD1 and SD4 modes
451 * -----------------------------------------------------
452 */
453#define RSP4_IO_OCR_M BITFIELD_MASK(24) /* Bits [23:0] - Card's OCR Bits [23:0] */
454#define RSP4_IO_OCR_S 0
455
456#define RSP4_S18A_M BITFIELD_MASK(1) /* Bits [23:0] - Card's OCR Bits [23:0] */
457#define RSP4_S18A_S 24
458
459#define RSP4_STUFF_M BITFIELD_MASK(3) /* Bits [26:24] - Stuff bits */
460#define RSP4_STUFF_S 24
461#define RSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 27 - Memory present */
462#define RSP4_MEM_PRESENT_S 27
463#define RSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [30:28] - Number of I/O funcs */
464#define RSP4_NUM_FUNCS_S 28
465#define RSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 31 - SDIO card ready */
466#define RSP4_CARD_READY_S 31
467
468#define RSP6_STATUS_M BITFIELD_MASK(16) /* Bits [15:0] - Card status bits [19,22,23,12:0]
469 */
470#define RSP6_STATUS_S 0
471#define RSP6_IO_RCA_M BITFIELD_MASK(16) /* Bits [31:16] - RCA bits[31-16] */
472#define RSP6_IO_RCA_S 16
473
474#define RSP1_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error */
475#define RSP1_AKE_SEQ_ERROR_S 3
476#define RSP1_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */
477#define RSP1_APP_CMD_S 5
478#define RSP1_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data (buff empty) */
479#define RSP1_READY_FOR_DATA_S 8
480#define RSP1_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - State of card
481 * when Cmd was received
482 */
483#define RSP1_CURR_STATE_S 9
484#define RSP1_EARSE_RESET_M BITFIELD_MASK(1) /* Bit 13 - Erase seq cleared */
485#define RSP1_EARSE_RESET_S 13
486#define RSP1_CARD_ECC_DISABLE_M BITFIELD_MASK(1) /* Bit 14 - Card ECC disabled */
487#define RSP1_CARD_ECC_DISABLE_S 14
488#define RSP1_WP_ERASE_SKIP_M BITFIELD_MASK(1) /* Bit 15 - Partial blocks erased due to W/P */
489#define RSP1_WP_ERASE_SKIP_S 15
490#define RSP1_CID_CSD_OVERW_M BITFIELD_MASK(1) /* Bit 16 - Illegal write to CID or R/O bits
491 * of CSD
492 */
493#define RSP1_CID_CSD_OVERW_S 16
494#define RSP1_ERROR_M BITFIELD_MASK(1) /* Bit 19 - General/Unknown error */
495#define RSP1_ERROR_S 19
496#define RSP1_CC_ERROR_M BITFIELD_MASK(1) /* Bit 20 - Internal Card Control error */
497#define RSP1_CC_ERROR_S 20
498#define RSP1_CARD_ECC_FAILED_M BITFIELD_MASK(1) /* Bit 21 - Card internal ECC failed
499 * to correct data
500 */
501#define RSP1_CARD_ECC_FAILED_S 21
502#define RSP1_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 22 - Cmd not legal for the card state */
503#define RSP1_ILLEGAL_CMD_S 22
504#define RSP1_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 23 - CRC check of previous command failed
505 */
506#define RSP1_COM_CRC_ERROR_S 23
507#define RSP1_LOCK_UNLOCK_FAIL_M BITFIELD_MASK(1) /* Bit 24 - Card lock-unlock Cmd Seq error */
508#define RSP1_LOCK_UNLOCK_FAIL_S 24
509#define RSP1_CARD_LOCKED_M BITFIELD_MASK(1) /* Bit 25 - Card locked by the host */
510#define RSP1_CARD_LOCKED_S 25
511#define RSP1_WP_VIOLATION_M BITFIELD_MASK(1) /* Bit 26 - Attempt to program
512 * write-protected blocks
513 */
514#define RSP1_WP_VIOLATION_S 26
515#define RSP1_ERASE_PARAM_M BITFIELD_MASK(1) /* Bit 27 - Invalid erase blocks */
516#define RSP1_ERASE_PARAM_S 27
517#define RSP1_ERASE_SEQ_ERR_M BITFIELD_MASK(1) /* Bit 28 - Erase Cmd seq error */
518#define RSP1_ERASE_SEQ_ERR_S 28
519#define RSP1_BLK_LEN_ERR_M BITFIELD_MASK(1) /* Bit 29 - Block length error */
520#define RSP1_BLK_LEN_ERR_S 29
521#define RSP1_ADDR_ERR_M BITFIELD_MASK(1) /* Bit 30 - Misaligned address */
522#define RSP1_ADDR_ERR_S 30
523#define RSP1_OUT_OF_RANGE_M BITFIELD_MASK(1) /* Bit 31 - Cmd arg was out of range */
524#define RSP1_OUT_OF_RANGE_S 31
525
526
527#define RSP5_DATA_M BITFIELD_MASK(8) /* Bits [0:7] - data */
528#define RSP5_DATA_S 0
529#define RSP5_FLAGS_M BITFIELD_MASK(8) /* Bit [15:8] - Rsp flags */
530#define RSP5_FLAGS_S 8
531#define RSP5_STUFF_M BITFIELD_MASK(16) /* Bits [31:16] - Stuff bits */
532#define RSP5_STUFF_S 16
533
534/* ----------------------------------------------
535 * SDIO Command Response structures for SPI mode
536 * ----------------------------------------------
537 */
538#define SPIRSP4_IO_OCR_M BITFIELD_MASK(16) /* Bits [15:0] - Card's OCR Bits [23:8] */
539#define SPIRSP4_IO_OCR_S 0
540#define SPIRSP4_STUFF_M BITFIELD_MASK(3) /* Bits [18:16] - Stuff bits */
541#define SPIRSP4_STUFF_S 16
542#define SPIRSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 19 - Memory present */
543#define SPIRSP4_MEM_PRESENT_S 19
544#define SPIRSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [22:20] - Number of I/O funcs */
545#define SPIRSP4_NUM_FUNCS_S 20
546#define SPIRSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 23 - SDIO card ready */
547#define SPIRSP4_CARD_READY_S 23
548#define SPIRSP4_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - idle state */
549#define SPIRSP4_IDLE_STATE_S 24
550#define SPIRSP4_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */
551#define SPIRSP4_ILLEGAL_CMD_S 26
552#define SPIRSP4_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */
553#define SPIRSP4_COM_CRC_ERROR_S 27
554#define SPIRSP4_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error
555 */
556#define SPIRSP4_FUNC_NUM_ERROR_S 28
557#define SPIRSP4_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */
558#define SPIRSP4_PARAM_ERROR_S 30
559#define SPIRSP4_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */
560#define SPIRSP4_START_BIT_S 31
561
562#define SPIRSP5_DATA_M BITFIELD_MASK(8) /* Bits [23:16] - R/W Data */
563#define SPIRSP5_DATA_S 16
564#define SPIRSP5_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - Idle state */
565#define SPIRSP5_IDLE_STATE_S 24
566#define SPIRSP5_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */
567#define SPIRSP5_ILLEGAL_CMD_S 26
568#define SPIRSP5_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */
569#define SPIRSP5_COM_CRC_ERROR_S 27
570#define SPIRSP5_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error
571 */
572#define SPIRSP5_FUNC_NUM_ERROR_S 28
573#define SPIRSP5_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */
574#define SPIRSP5_PARAM_ERROR_S 30
575#define SPIRSP5_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */
576#define SPIRSP5_START_BIT_S 31
577
578/* RSP6 card status format; Pg 68 Physical Layer spec v 1.10 */
579#define RSP6STAT_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error
580 */
581#define RSP6STAT_AKE_SEQ_ERROR_S 3
582#define RSP6STAT_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */
583#define RSP6STAT_APP_CMD_S 5
584#define RSP6STAT_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data
585 * (buff empty)
586 */
587#define RSP6STAT_READY_FOR_DATA_S 8
588#define RSP6STAT_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - Card state at
589 * Cmd reception
590 */
591#define RSP6STAT_CURR_STATE_S 9
592#define RSP6STAT_ERROR_M BITFIELD_MASK(1) /* Bit 13 - General/Unknown error Bit 19
593 */
594#define RSP6STAT_ERROR_S 13
595#define RSP6STAT_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 14 - Illegal cmd for
596 * card state Bit 22
597 */
598#define RSP6STAT_ILLEGAL_CMD_S 14
599#define RSP6STAT_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 15 - CRC previous command
600 * failed Bit 23
601 */
602#define RSP6STAT_COM_CRC_ERROR_S 15
603
604#define SDIOH_XFER_TYPE_READ SD_IO_OP_READ
605#define SDIOH_XFER_TYPE_WRITE SD_IO_OP_WRITE
606
607/* command issue options */
608#define CMD_OPTION_DEFAULT 0
609#define CMD_OPTION_TUNING 1
610
611#endif /* _SDIO_H */
diff --git a/drivers/net/wireless/bcmdhd/include/sdioh.h b/drivers/net/wireless/bcmdhd/include/sdioh.h
new file mode 100644
index 00000000000..3d37c7a7e30
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sdioh.h
@@ -0,0 +1,412 @@
1/*
2 * SDIO Host Controller Spec header file
3 * Register map and definitions for the Standard Host Controller
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: sdioh.h,v 13.17.2.3 2011-01-08 05:28:21 Exp $
26 */
27
28#ifndef _SDIOH_H
29#define _SDIOH_H
30
31#define SD_SysAddr 0x000
32#define SD_BlockSize 0x004
33#define SD_BlockCount 0x006
34#define SD_Arg0 0x008
35#define SD_Arg1 0x00A
36#define SD_TransferMode 0x00C
37#define SD_Command 0x00E
38#define SD_Response0 0x010
39#define SD_Response1 0x012
40#define SD_Response2 0x014
41#define SD_Response3 0x016
42#define SD_Response4 0x018
43#define SD_Response5 0x01A
44#define SD_Response6 0x01C
45#define SD_Response7 0x01E
46#define SD_BufferDataPort0 0x020
47#define SD_BufferDataPort1 0x022
48#define SD_PresentState 0x024
49#define SD_HostCntrl 0x028
50#define SD_PwrCntrl 0x029
51#define SD_BlockGapCntrl 0x02A
52#define SD_WakeupCntrl 0x02B
53#define SD_ClockCntrl 0x02C
54#define SD_TimeoutCntrl 0x02E
55#define SD_SoftwareReset 0x02F
56#define SD_IntrStatus 0x030
57#define SD_ErrorIntrStatus 0x032
58#define SD_IntrStatusEnable 0x034
59#define SD_ErrorIntrStatusEnable 0x036
60#define SD_IntrSignalEnable 0x038
61#define SD_ErrorIntrSignalEnable 0x03A
62#define SD_CMD12ErrorStatus 0x03C
63#define SD_Capabilities 0x040
64#define SD_Capabilities3 0x044
65#define SD_MaxCurCap 0x048
66#define SD_MaxCurCap_Reserved 0x04C
67#define SD_ADMA_ErrStatus 0x054
68#define SD_ADMA_SysAddr 0x58
69#define SD_SlotInterruptStatus 0x0FC
70#define SD_HostControllerVersion 0x0FE
71
72/* SD specific registers in PCI config space */
73#define SD_SlotInfo 0x40
74
75/* HC 3.0 specific registers and offsets */
76#define SD3_HostCntrl2 0x03E
77/* preset regsstart and count */
78#define SD3_PresetValStart 0x060
79#define SD3_PresetValCount 8
80/* preset-indiv regs */
81#define SD3_PresetVal_init 0x060
82#define SD3_PresetVal_default 0x062
83#define SD3_PresetVal_HS 0x064
84#define SD3_PresetVal_SDR12 0x066
85#define SD3_PresetVal_SDR25 0x068
86#define SD3_PresetVal_SDR50 0x06a
87#define SD3_PresetVal_SDR104 0x06c
88#define SD3_PresetVal_DDR50 0x06e
89
90/* preset value indices */
91#define SD3_PRESETVAL_INITIAL_IX 0
92#define SD3_PRESETVAL_DESPEED_IX 1
93#define SD3_PRESETVAL_HISPEED_IX 2
94#define SD3_PRESETVAL_SDR12_IX 3
95#define SD3_PRESETVAL_SDR25_IX 4
96#define SD3_PRESETVAL_SDR50_IX 5
97#define SD3_PRESETVAL_SDR104_IX 6
98#define SD3_PRESETVAL_DDR50_IX 7
99
100/* SD_Capabilities reg (0x040) */
101#define CAP_TO_CLKFREQ_M BITFIELD_MASK(6)
102#define CAP_TO_CLKFREQ_S 0
103#define CAP_TO_CLKUNIT_M BITFIELD_MASK(1)
104#define CAP_TO_CLKUNIT_S 7
105/* Note: for sdio-2.0 case, this mask has to be 6 bits, but msb 2
106 bits are reserved. going ahead with 8 bits, as it is req for 3.0
107*/
108#define CAP_BASECLK_M BITFIELD_MASK(8)
109#define CAP_BASECLK_S 8
110#define CAP_MAXBLOCK_M BITFIELD_MASK(2)
111#define CAP_MAXBLOCK_S 16
112#define CAP_ADMA2_M BITFIELD_MASK(1)
113#define CAP_ADMA2_S 19
114#define CAP_ADMA1_M BITFIELD_MASK(1)
115#define CAP_ADMA1_S 20
116#define CAP_HIGHSPEED_M BITFIELD_MASK(1)
117#define CAP_HIGHSPEED_S 21
118#define CAP_DMA_M BITFIELD_MASK(1)
119#define CAP_DMA_S 22
120#define CAP_SUSPEND_M BITFIELD_MASK(1)
121#define CAP_SUSPEND_S 23
122#define CAP_VOLT_3_3_M BITFIELD_MASK(1)
123#define CAP_VOLT_3_3_S 24
124#define CAP_VOLT_3_0_M BITFIELD_MASK(1)
125#define CAP_VOLT_3_0_S 25
126#define CAP_VOLT_1_8_M BITFIELD_MASK(1)
127#define CAP_VOLT_1_8_S 26
128#define CAP_64BIT_HOST_M BITFIELD_MASK(1)
129#define CAP_64BIT_HOST_S 28
130
131#define SDIO_OCR_READ_FAIL (2)
132
133
134#define CAP_ASYNCINT_SUP_M BITFIELD_MASK(1)
135#define CAP_ASYNCINT_SUP_S 29
136
137#define CAP_SLOTTYPE_M BITFIELD_MASK(2)
138#define CAP_SLOTTYPE_S 30
139
140#define CAP3_MSBits_OFFSET (32)
141/* note: following are caps MSB32 bits.
142 So the bits start from 0, instead of 32. that is why
143 CAP3_MSBits_OFFSET is subtracted.
144*/
145#define CAP3_SDR50_SUP_M BITFIELD_MASK(1)
146#define CAP3_SDR50_SUP_S (32 - CAP3_MSBits_OFFSET)
147
148#define CAP3_SDR104_SUP_M BITFIELD_MASK(1)
149#define CAP3_SDR104_SUP_S (33 - CAP3_MSBits_OFFSET)
150
151#define CAP3_DDR50_SUP_M BITFIELD_MASK(1)
152#define CAP3_DDR50_SUP_S (34 - CAP3_MSBits_OFFSET)
153
154/* for knowing the clk caps in a single read */
155#define CAP3_30CLKCAP_M BITFIELD_MASK(3)
156#define CAP3_30CLKCAP_S (32 - CAP3_MSBits_OFFSET)
157
158#define CAP3_DRIVTYPE_A_M BITFIELD_MASK(1)
159#define CAP3_DRIVTYPE_A_S (36 - CAP3_MSBits_OFFSET)
160
161#define CAP3_DRIVTYPE_C_M BITFIELD_MASK(1)
162#define CAP3_DRIVTYPE_C_S (37 - CAP3_MSBits_OFFSET)
163
164#define CAP3_DRIVTYPE_D_M BITFIELD_MASK(1)
165#define CAP3_DRIVTYPE_D_S (38 - CAP3_MSBits_OFFSET)
166
167#define CAP3_RETUNING_TC_M BITFIELD_MASK(4)
168#define CAP3_RETUNING_TC_S (40 - CAP3_MSBits_OFFSET)
169
170#define CAP3_TUNING_SDR50_M BITFIELD_MASK(1)
171#define CAP3_TUNING_SDR50_S (45 - CAP3_MSBits_OFFSET)
172
173#define CAP3_RETUNING_MODES_M BITFIELD_MASK(2)
174#define CAP3_RETUNING_MODES_S (46 - CAP3_MSBits_OFFSET)
175
176#define CAP3_CLK_MULT_M BITFIELD_MASK(8)
177#define CAP3_CLK_MULT_S (48 - CAP3_MSBits_OFFSET)
178
179#define PRESET_DRIVR_SELECT_M BITFIELD_MASK(2)
180#define PRESET_DRIVR_SELECT_S 14
181
182#define PRESET_CLK_DIV_M BITFIELD_MASK(10)
183#define PRESET_CLK_DIV_S 0
184
185/* SD_MaxCurCap reg (0x048) */
186#define CAP_CURR_3_3_M BITFIELD_MASK(8)
187#define CAP_CURR_3_3_S 0
188#define CAP_CURR_3_0_M BITFIELD_MASK(8)
189#define CAP_CURR_3_0_S 8
190#define CAP_CURR_1_8_M BITFIELD_MASK(8)
191#define CAP_CURR_1_8_S 16
192
193/* SD_SysAddr: Offset 0x0000, Size 4 bytes */
194
195/* SD_BlockSize: Offset 0x004, Size 2 bytes */
196#define BLKSZ_BLKSZ_M BITFIELD_MASK(12)
197#define BLKSZ_BLKSZ_S 0
198#define BLKSZ_BNDRY_M BITFIELD_MASK(3)
199#define BLKSZ_BNDRY_S 12
200
201/* SD_BlockCount: Offset 0x006, size 2 bytes */
202
203/* SD_Arg0: Offset 0x008, size = 4 bytes */
204/* SD_TransferMode Offset 0x00C, size = 2 bytes */
205#define XFER_DMA_ENABLE_M BITFIELD_MASK(1)
206#define XFER_DMA_ENABLE_S 0
207#define XFER_BLK_COUNT_EN_M BITFIELD_MASK(1)
208#define XFER_BLK_COUNT_EN_S 1
209#define XFER_CMD_12_EN_M BITFIELD_MASK(1)
210#define XFER_CMD_12_EN_S 2
211#define XFER_DATA_DIRECTION_M BITFIELD_MASK(1)
212#define XFER_DATA_DIRECTION_S 4
213#define XFER_MULTI_BLOCK_M BITFIELD_MASK(1)
214#define XFER_MULTI_BLOCK_S 5
215
216/* SD_Command: Offset 0x00E, size = 2 bytes */
217/* resp_type field */
218#define RESP_TYPE_NONE 0
219#define RESP_TYPE_136 1
220#define RESP_TYPE_48 2
221#define RESP_TYPE_48_BUSY 3
222/* type field */
223#define CMD_TYPE_NORMAL 0
224#define CMD_TYPE_SUSPEND 1
225#define CMD_TYPE_RESUME 2
226#define CMD_TYPE_ABORT 3
227
228#define CMD_RESP_TYPE_M BITFIELD_MASK(2) /* Bits [0-1] - Response type */
229#define CMD_RESP_TYPE_S 0
230#define CMD_CRC_EN_M BITFIELD_MASK(1) /* Bit 3 - CRC enable */
231#define CMD_CRC_EN_S 3
232#define CMD_INDEX_EN_M BITFIELD_MASK(1) /* Bit 4 - Enable index checking */
233#define CMD_INDEX_EN_S 4
234#define CMD_DATA_EN_M BITFIELD_MASK(1) /* Bit 5 - Using DAT line */
235#define CMD_DATA_EN_S 5
236#define CMD_TYPE_M BITFIELD_MASK(2) /* Bit [6-7] - Normal, abort, resume, etc
237 */
238#define CMD_TYPE_S 6
239#define CMD_INDEX_M BITFIELD_MASK(6) /* Bits [8-13] - Command number */
240#define CMD_INDEX_S 8
241
242/* SD_BufferDataPort0 : Offset 0x020, size = 2 or 4 bytes */
243/* SD_BufferDataPort1 : Offset 0x022, size = 2 bytes */
244/* SD_PresentState : Offset 0x024, size = 4 bytes */
245#define PRES_CMD_INHIBIT_M BITFIELD_MASK(1) /* Bit 0 May use CMD */
246#define PRES_CMD_INHIBIT_S 0
247#define PRES_DAT_INHIBIT_M BITFIELD_MASK(1) /* Bit 1 May use DAT */
248#define PRES_DAT_INHIBIT_S 1
249#define PRES_DAT_BUSY_M BITFIELD_MASK(1) /* Bit 2 DAT is busy */
250#define PRES_DAT_BUSY_S 2
251#define PRES_PRESENT_RSVD_M BITFIELD_MASK(5) /* Bit [3-7] rsvd */
252#define PRES_PRESENT_RSVD_S 3
253#define PRES_WRITE_ACTIVE_M BITFIELD_MASK(1) /* Bit 8 Write is active */
254#define PRES_WRITE_ACTIVE_S 8
255#define PRES_READ_ACTIVE_M BITFIELD_MASK(1) /* Bit 9 Read is active */
256#define PRES_READ_ACTIVE_S 9
257#define PRES_WRITE_DATA_RDY_M BITFIELD_MASK(1) /* Bit 10 Write buf is avail */
258#define PRES_WRITE_DATA_RDY_S 10
259#define PRES_READ_DATA_RDY_M BITFIELD_MASK(1) /* Bit 11 Read buf data avail */
260#define PRES_READ_DATA_RDY_S 11
261#define PRES_CARD_PRESENT_M BITFIELD_MASK(1) /* Bit 16 Card present - debounced */
262#define PRES_CARD_PRESENT_S 16
263#define PRES_CARD_STABLE_M BITFIELD_MASK(1) /* Bit 17 Debugging */
264#define PRES_CARD_STABLE_S 17
265#define PRES_CARD_PRESENT_RAW_M BITFIELD_MASK(1) /* Bit 18 Not debounced */
266#define PRES_CARD_PRESENT_RAW_S 18
267#define PRES_WRITE_ENABLED_M BITFIELD_MASK(1) /* Bit 19 Write protected? */
268#define PRES_WRITE_ENABLED_S 19
269#define PRES_DAT_SIGNAL_M BITFIELD_MASK(4) /* Bit [20-23] Debugging */
270#define PRES_DAT_SIGNAL_S 20
271#define PRES_CMD_SIGNAL_M BITFIELD_MASK(1) /* Bit 24 Debugging */
272#define PRES_CMD_SIGNAL_S 24
273
274/* SD_HostCntrl: Offset 0x028, size = 1 bytes */
275#define HOST_LED_M BITFIELD_MASK(1) /* Bit 0 LED On/Off */
276#define HOST_LED_S 0
277#define HOST_DATA_WIDTH_M BITFIELD_MASK(1) /* Bit 1 4 bit enable */
278#define HOST_DATA_WIDTH_S 1
279#define HOST_HI_SPEED_EN_M BITFIELD_MASK(1) /* Bit 2 High speed vs low speed */
280#define HOST_DMA_SEL_S 3
281#define HOST_DMA_SEL_M BITFIELD_MASK(2) /* Bit 4:3 DMA Select */
282#define HOST_HI_SPEED_EN_S 2
283
284/* Host Control2: */
285#define HOSTCtrl2_PRESVAL_EN_M BITFIELD_MASK(1) /* 1 bit */
286#define HOSTCtrl2_PRESVAL_EN_S 15 /* bit# */
287
288#define HOSTCtrl2_ASYINT_EN_M BITFIELD_MASK(1) /* 1 bit */
289#define HOSTCtrl2_ASYINT_EN_S 14 /* bit# */
290
291#define HOSTCtrl2_SAMPCLK_SEL_M BITFIELD_MASK(1) /* 1 bit */
292#define HOSTCtrl2_SAMPCLK_SEL_S 7 /* bit# */
293
294#define HOSTCtrl2_EXEC_TUNING_M BITFIELD_MASK(1) /* 1 bit */
295#define HOSTCtrl2_EXEC_TUNING_S 6 /* bit# */
296
297#define HOSTCtrl2_DRIVSTRENGTH_SEL_M BITFIELD_MASK(2) /* 2 bit */
298#define HOSTCtrl2_DRIVSTRENGTH_SEL_S 4 /* bit# */
299
300#define HOSTCtrl2_1_8SIG_EN_M BITFIELD_MASK(1) /* 1 bit */
301#define HOSTCtrl2_1_8SIG_EN_S 3 /* bit# */
302
303#define HOSTCtrl2_UHSMODE_SEL_M BITFIELD_MASK(3) /* 3 bit */
304#define HOSTCtrl2_UHSMODE_SEL_S 0 /* bit# */
305
306#define HOST_CONTR_VER_2 (1)
307#define HOST_CONTR_VER_3 (2)
308
309/* misc defines */
310#define SD1_MODE 0x1 /* SD Host Cntrlr Spec */
311#define SD4_MODE 0x2 /* SD Host Cntrlr Spec */
312
313/* SD_PwrCntrl: Offset 0x029, size = 1 bytes */
314#define PWR_BUS_EN_M BITFIELD_MASK(1) /* Bit 0 Power the bus */
315#define PWR_BUS_EN_S 0
316#define PWR_VOLTS_M BITFIELD_MASK(3) /* Bit [1-3] Voltage Select */
317#define PWR_VOLTS_S 1
318
319/* SD_SoftwareReset: Offset 0x02F, size = 1 byte */
320#define SW_RESET_ALL_M BITFIELD_MASK(1) /* Bit 0 Reset All */
321#define SW_RESET_ALL_S 0
322#define SW_RESET_CMD_M BITFIELD_MASK(1) /* Bit 1 CMD Line Reset */
323#define SW_RESET_CMD_S 1
324#define SW_RESET_DAT_M BITFIELD_MASK(1) /* Bit 2 DAT Line Reset */
325#define SW_RESET_DAT_S 2
326
327/* SD_IntrStatus: Offset 0x030, size = 2 bytes */
328/* Defs also serve SD_IntrStatusEnable and SD_IntrSignalEnable */
329#define INTSTAT_CMD_COMPLETE_M BITFIELD_MASK(1) /* Bit 0 */
330#define INTSTAT_CMD_COMPLETE_S 0
331#define INTSTAT_XFER_COMPLETE_M BITFIELD_MASK(1)
332#define INTSTAT_XFER_COMPLETE_S 1
333#define INTSTAT_BLOCK_GAP_EVENT_M BITFIELD_MASK(1)
334#define INTSTAT_BLOCK_GAP_EVENT_S 2
335#define INTSTAT_DMA_INT_M BITFIELD_MASK(1)
336#define INTSTAT_DMA_INT_S 3
337#define INTSTAT_BUF_WRITE_READY_M BITFIELD_MASK(1)
338#define INTSTAT_BUF_WRITE_READY_S 4
339#define INTSTAT_BUF_READ_READY_M BITFIELD_MASK(1)
340#define INTSTAT_BUF_READ_READY_S 5
341#define INTSTAT_CARD_INSERTION_M BITFIELD_MASK(1)
342#define INTSTAT_CARD_INSERTION_S 6
343#define INTSTAT_CARD_REMOVAL_M BITFIELD_MASK(1)
344#define INTSTAT_CARD_REMOVAL_S 7
345#define INTSTAT_CARD_INT_M BITFIELD_MASK(1)
346#define INTSTAT_CARD_INT_S 8
347#define INTSTAT_RETUNING_INT_M BITFIELD_MASK(1) /* Bit 12 */
348#define INTSTAT_RETUNING_INT_S 12
349#define INTSTAT_ERROR_INT_M BITFIELD_MASK(1) /* Bit 15 */
350#define INTSTAT_ERROR_INT_S 15
351
352/* SD_ErrorIntrStatus: Offset 0x032, size = 2 bytes */
353/* Defs also serve SD_ErrorIntrStatusEnable and SD_ErrorIntrSignalEnable */
354#define ERRINT_CMD_TIMEOUT_M BITFIELD_MASK(1)
355#define ERRINT_CMD_TIMEOUT_S 0
356#define ERRINT_CMD_CRC_M BITFIELD_MASK(1)
357#define ERRINT_CMD_CRC_S 1
358#define ERRINT_CMD_ENDBIT_M BITFIELD_MASK(1)
359#define ERRINT_CMD_ENDBIT_S 2
360#define ERRINT_CMD_INDEX_M BITFIELD_MASK(1)
361#define ERRINT_CMD_INDEX_S 3
362#define ERRINT_DATA_TIMEOUT_M BITFIELD_MASK(1)
363#define ERRINT_DATA_TIMEOUT_S 4
364#define ERRINT_DATA_CRC_M BITFIELD_MASK(1)
365#define ERRINT_DATA_CRC_S 5
366#define ERRINT_DATA_ENDBIT_M BITFIELD_MASK(1)
367#define ERRINT_DATA_ENDBIT_S 6
368#define ERRINT_CURRENT_LIMIT_M BITFIELD_MASK(1)
369#define ERRINT_CURRENT_LIMIT_S 7
370#define ERRINT_AUTO_CMD12_M BITFIELD_MASK(1)
371#define ERRINT_AUTO_CMD12_S 8
372#define ERRINT_VENDOR_M BITFIELD_MASK(4)
373#define ERRINT_VENDOR_S 12
374#define ERRINT_ADMA_M BITFIELD_MASK(1)
375#define ERRINT_ADMA_S 9
376
377/* Also provide definitions in "normal" form to allow combined masks */
378#define ERRINT_CMD_TIMEOUT_BIT 0x0001
379#define ERRINT_CMD_CRC_BIT 0x0002
380#define ERRINT_CMD_ENDBIT_BIT 0x0004
381#define ERRINT_CMD_INDEX_BIT 0x0008
382#define ERRINT_DATA_TIMEOUT_BIT 0x0010
383#define ERRINT_DATA_CRC_BIT 0x0020
384#define ERRINT_DATA_ENDBIT_BIT 0x0040
385#define ERRINT_CURRENT_LIMIT_BIT 0x0080
386#define ERRINT_AUTO_CMD12_BIT 0x0100
387#define ERRINT_ADMA_BIT 0x0200
388
389/* Masks to select CMD vs. DATA errors */
390#define ERRINT_CMD_ERRS (ERRINT_CMD_TIMEOUT_BIT | ERRINT_CMD_CRC_BIT |\
391 ERRINT_CMD_ENDBIT_BIT | ERRINT_CMD_INDEX_BIT)
392#define ERRINT_DATA_ERRS (ERRINT_DATA_TIMEOUT_BIT | ERRINT_DATA_CRC_BIT |\
393 ERRINT_DATA_ENDBIT_BIT | ERRINT_ADMA_BIT)
394#define ERRINT_TRANSFER_ERRS (ERRINT_CMD_ERRS | ERRINT_DATA_ERRS)
395
396/* SD_WakeupCntr_BlockGapCntrl : Offset 0x02A , size = bytes */
397/* SD_ClockCntrl : Offset 0x02C , size = bytes */
398/* SD_SoftwareReset_TimeoutCntrl : Offset 0x02E , size = bytes */
399/* SD_IntrStatus : Offset 0x030 , size = bytes */
400/* SD_ErrorIntrStatus : Offset 0x032 , size = bytes */
401/* SD_IntrStatusEnable : Offset 0x034 , size = bytes */
402/* SD_ErrorIntrStatusEnable : Offset 0x036 , size = bytes */
403/* SD_IntrSignalEnable : Offset 0x038 , size = bytes */
404/* SD_ErrorIntrSignalEnable : Offset 0x03A , size = bytes */
405/* SD_CMD12ErrorStatus : Offset 0x03C , size = bytes */
406/* SD_Capabilities : Offset 0x040 , size = bytes */
407/* SD_MaxCurCap : Offset 0x048 , size = bytes */
408/* SD_MaxCurCap_Reserved: Offset 0x04C , size = bytes */
409/* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */
410/* SD_HostControllerVersion : Offset 0x0FE , size = bytes */
411
412#endif /* _SDIOH_H */
diff --git a/drivers/net/wireless/bcmdhd/include/sdiovar.h b/drivers/net/wireless/bcmdhd/include/sdiovar.h
new file mode 100644
index 00000000000..2c5bcf97e91
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/sdiovar.h
@@ -0,0 +1,58 @@
1/*
2 * Structure used by apps whose drivers access SDIO drivers.
3 * Pulled out separately so dhdu and wlu can both use it.
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: sdiovar.h,v 13.9 2009-12-08 22:30:15 Exp $
26 */
27
28#ifndef _sdiovar_h_
29#define _sdiovar_h_
30
31#include <typedefs.h>
32
33/* require default structure packing */
34#define BWL_DEFAULT_PACKING
35#include <packed_section_start.h>
36
37typedef struct sdreg {
38 int func;
39 int offset;
40 int value;
41} sdreg_t;
42
43/* Common msglevel constants */
44#define SDH_ERROR_VAL 0x0001 /* Error */
45#define SDH_TRACE_VAL 0x0002 /* Trace */
46#define SDH_INFO_VAL 0x0004 /* Info */
47#define SDH_DEBUG_VAL 0x0008 /* Debug */
48#define SDH_DATA_VAL 0x0010 /* Data */
49#define SDH_CTRL_VAL 0x0020 /* Control Regs */
50#define SDH_LOG_VAL 0x0040 /* Enable bcmlog */
51#define SDH_DMA_VAL 0x0080 /* DMA */
52
53#define NUM_PREV_TRANSACTIONS 16
54
55
56#include <packed_section_end.h>
57
58#endif /* _sdiovar_h_ */
diff --git a/drivers/net/wireless/bcmdhd/include/siutils.h b/drivers/net/wireless/bcmdhd/include/siutils.h
new file mode 100644
index 00000000000..c5a33832b58
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/siutils.h
@@ -0,0 +1,247 @@
1/*
2 * Misc utility routines for accessing the SOC Interconnects
3 * of Broadcom HNBU chips.
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: siutils.h,v 13.251.2.10 2011-02-04 05:06:32 Exp $
26 */
27
28
29#ifndef _siutils_h_
30#define _siutils_h_
31
32
33struct si_pub {
34 uint socitype;
35
36 uint bustype;
37 uint buscoretype;
38 uint buscorerev;
39 uint buscoreidx;
40 int ccrev;
41 uint32 cccaps;
42 uint32 cccaps_ext;
43 int pmurev;
44 uint32 pmucaps;
45 uint boardtype;
46 uint boardvendor;
47 uint boardflags;
48 uint boardflags2;
49 uint chip;
50 uint chiprev;
51 uint chippkg;
52 uint32 chipst;
53 bool issim;
54 uint socirev;
55 bool pci_pr32414;
56
57};
58
59
60typedef const struct si_pub si_t;
61
62
63#define SI_OSH NULL
64
65#define BADIDX (SI_MAXCORES + 1)
66
67
68#define XTAL 0x1
69#define PLL 0x2
70
71
72#define CLK_FAST 0
73#define CLK_DYNAMIC 2
74
75
76#define GPIO_DRV_PRIORITY 0
77#define GPIO_APP_PRIORITY 1
78#define GPIO_HI_PRIORITY 2
79
80
81#define GPIO_PULLUP 0
82#define GPIO_PULLDN 1
83
84
85#define GPIO_REGEVT 0
86#define GPIO_REGEVT_INTMSK 1
87#define GPIO_REGEVT_INTPOL 2
88
89
90#define SI_DEVPATH_BUFSZ 16
91
92
93#define SI_DOATTACH 1
94#define SI_PCIDOWN 2
95#define SI_PCIUP 3
96
97#define ISSIM_ENAB(sih) 0
98
99
100#if defined(BCMPMUCTL)
101#define PMUCTL_ENAB(sih) (BCMPMUCTL)
102#else
103#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU)
104#endif
105
106
107#if defined(BCMPMUCTL) && BCMPMUCTL
108#define CCCTL_ENAB(sih) (0)
109#define CCPLL_ENAB(sih) (0)
110#else
111#define CCCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PWR_CTL)
112#define CCPLL_ENAB(sih) ((sih)->cccaps & CC_CAP_PLL_MASK)
113#endif
114
115typedef void (*gpio_handler_t)(uint32 stat, void *arg);
116
117
118
119extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype,
120 void *sdh, char **vars, uint *varsz);
121extern si_t *si_kattach(osl_t *osh);
122extern void si_detach(si_t *sih);
123extern bool si_pci_war16165(si_t *sih);
124
125extern uint si_corelist(si_t *sih, uint coreid[]);
126extern uint si_coreid(si_t *sih);
127extern uint si_flag(si_t *sih);
128extern uint si_intflag(si_t *sih);
129extern uint si_coreidx(si_t *sih);
130extern uint si_coreunit(si_t *sih);
131extern uint si_corevendor(si_t *sih);
132extern uint si_corerev(si_t *sih);
133extern void *si_osh(si_t *sih);
134extern void si_setosh(si_t *sih, osl_t *osh);
135extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val);
136extern void *si_coreregs(si_t *sih);
137extern uint si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val);
138extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val);
139extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val);
140extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val);
141extern bool si_iscoreup(si_t *sih);
142extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit);
143extern void *si_setcoreidx(si_t *sih, uint coreidx);
144extern void *si_setcore(si_t *sih, uint coreid, uint coreunit);
145extern void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val);
146extern void si_restore_core(si_t *sih, uint coreid, uint intr_val);
147extern int si_numaddrspaces(si_t *sih);
148extern uint32 si_addrspace(si_t *sih, uint asidx);
149extern uint32 si_addrspacesize(si_t *sih, uint asidx);
150extern int si_corebist(si_t *sih);
151extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits);
152extern void si_core_disable(si_t *sih, uint32 bits);
153extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m);
154extern bool si_read_pmu_autopll(si_t *sih);
155extern uint32 si_clock(si_t *sih);
156extern uint32 si_alp_clock(si_t *sih);
157extern uint32 si_ilp_clock(si_t *sih);
158extern void si_pci_setup(si_t *sih, uint coremask);
159extern void si_pcmcia_init(si_t *sih);
160extern void si_setint(si_t *sih, int siflag);
161extern bool si_backplane64(si_t *sih);
162extern void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn,
163 void *intrsenabled_fn, void *intr_arg);
164extern void si_deregister_intr_callback(si_t *sih);
165extern void si_clkctl_init(si_t *sih);
166extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih);
167extern bool si_clkctl_cc(si_t *sih, uint mode);
168extern int si_clkctl_xtal(si_t *sih, uint what, bool on);
169extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val);
170extern void si_btcgpiowar(si_t *sih);
171extern bool si_deviceremoved(si_t *sih);
172extern uint32 si_socram_size(si_t *sih);
173extern uint32 si_socdevram_size(si_t *sih);
174extern void si_socdevram(si_t *sih, bool set, uint8 *ennable, uint8 *protect);
175extern bool si_socdevram_pkg(si_t *sih);
176
177extern void si_watchdog(si_t *sih, uint ticks);
178extern void si_watchdog_ms(si_t *sih, uint32 ms);
179extern void *si_gpiosetcore(si_t *sih);
180extern uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority);
181extern uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority);
182extern uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority);
183extern uint32 si_gpioin(si_t *sih);
184extern uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority);
185extern uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority);
186extern uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val);
187extern uint32 si_gpioreserve(si_t *sih, uint32 gpio_num, uint8 priority);
188extern uint32 si_gpiorelease(si_t *sih, uint32 gpio_num, uint8 priority);
189extern uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val);
190extern uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val);
191extern uint32 si_gpio_int_enable(si_t *sih, bool enable);
192
193
194extern void *si_gpio_handler_register(si_t *sih, uint32 e, bool lev, gpio_handler_t cb, void *arg);
195extern void si_gpio_handler_unregister(si_t *sih, void* gpioh);
196extern void si_gpio_handler_process(si_t *sih);
197
198
199extern bool si_pci_pmecap(si_t *sih);
200struct osl_info;
201extern bool si_pci_fastpmecap(struct osl_info *osh);
202extern bool si_pci_pmestat(si_t *sih);
203extern void si_pci_pmeclr(si_t *sih);
204extern void si_pci_pmeen(si_t *sih);
205extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset);
206
207extern void si_sdio_init(si_t *sih);
208
209extern uint16 si_d11_devid(si_t *sih);
210extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice,
211 uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader);
212
213#define si_eci(sih) 0
214#define si_eci_init(sih) (0)
215#define si_eci_notify_bt(sih, type, val) (0)
216
217
218
219extern int si_devpath(si_t *sih, char *path, int size);
220
221extern char *si_getdevpathvar(si_t *sih, const char *name);
222extern int si_getdevpathintvar(si_t *sih, const char *name);
223
224
225extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val);
226extern uint32 si_pcielcreg(si_t *sih, uint32 mask, uint32 val);
227extern void si_war42780_clkreq(si_t *sih, bool clkreq);
228extern void si_pci_sleep(si_t *sih);
229extern void si_pci_down(si_t *sih);
230extern void si_pci_up(si_t *sih);
231extern void si_pcie_war_ovr_update(si_t *sih, uint8 aspm);
232extern void si_pcie_extendL1timer(si_t *sih, bool extend);
233extern int si_pci_fixcfg(si_t *sih);
234extern uint si_pll_reset(si_t *sih);
235
236
237
238extern bool si_taclear(si_t *sih, bool details);
239
240
241
242extern uint32 si_pciereg(si_t *sih, uint32 offset, uint32 mask, uint32 val, uint type);
243extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint32 mask, uint32 val);
244
245char *si_getnvramflvar(si_t *sih, const char *name);
246
247#endif
diff --git a/drivers/net/wireless/bcmdhd/include/trxhdr.h b/drivers/net/wireless/bcmdhd/include/trxhdr.h
new file mode 100644
index 00000000000..397006ab005
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/trxhdr.h
@@ -0,0 +1,52 @@
1/*
2 * TRX image file header format.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: trxhdr.h,v 13.15.108.2 2010-11-15 17:57:30 Exp $
25 */
26
27#ifndef _TRX_HDR_H_
28#define _TRX_HDR_H_
29
30#include <typedefs.h>
31
32#define TRX_MAGIC 0x30524448 /* "HDR0" */
33#define TRX_VERSION 1 /* Version 1 */
34#define TRX_MAX_LEN 0x3B0000 /* Max length */
35#define TRX_NO_HEADER 1 /* Do not write TRX header */
36#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
37#define TRX_OVERLAYS 0x4 /* Contains an overlay header after the trx header */
38#define TRX_MAX_OFFSET 3 /* Max number of individual files */
39#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */
40
41struct trx_header {
42 uint32 magic; /* "HDR0" */
43 uint32 len; /* Length of file including header */
44 uint32 crc32; /* 32-bit CRC from flag_version to end of file */
45 uint32 flag_version; /* 0:15 flags, 16:31 version */
46 uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
47};
48
49/* Compatibility */
50typedef struct trx_header TRXHDR, *PTRXHDR;
51
52#endif /* _TRX_HDR_H_ */
diff --git a/drivers/net/wireless/bcmdhd/include/typedefs.h b/drivers/net/wireless/bcmdhd/include/typedefs.h
new file mode 100644
index 00000000000..228b5dcf11c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/typedefs.h
@@ -0,0 +1,309 @@
1/*
2 * Copyright (C) 1999-2011, Broadcom Corporation
3 *
4 * Unless you and Broadcom execute a separate written software license
5 * agreement governing use of this software, this software is licensed to you
6 * under the terms of the GNU General Public License version 2 (the "GPL"),
7 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
8 * following added to such license:
9 *
10 * As a special exception, the copyright holders of this software give you
11 * permission to link this software with independent modules, and to copy and
12 * distribute the resulting executable under terms of your choice, provided that
13 * you also meet, for each linked independent module, the terms and conditions of
14 * the license of that module. An independent module is a module which is not
15 * derived from this software. The special exception does not apply to any
16 * modifications of the software.
17 *
18 * Notwithstanding the above, under no circumstances may you combine this
19 * software in any way with any other Broadcom software provided under a license
20 * other than the GPL, without Broadcom's express prior written consent.
21 * $Id: typedefs.h,v 1.103.2.1 2010-05-11 18:19:28 Exp $
22 */
23
24
25#ifndef _TYPEDEFS_H_
26#define _TYPEDEFS_H_
27
28#ifdef SITE_TYPEDEFS
29
30
31
32#include "site_typedefs.h"
33
34#else
35
36
37
38#ifdef __cplusplus
39
40#define TYPEDEF_BOOL
41#ifndef FALSE
42#define FALSE false
43#endif
44#ifndef TRUE
45#define TRUE true
46#endif
47
48#else
49
50
51#endif
52
53#if defined(__x86_64__)
54#define TYPEDEF_UINTPTR
55typedef unsigned long long int uintptr;
56#endif
57
58
59
60
61
62#if defined(_NEED_SIZE_T_)
63typedef long unsigned int size_t;
64#endif
65
66
67
68
69
70#if defined(__sparc__)
71#define TYPEDEF_ULONG
72#endif
73
74
75
76#if !defined(LINUX_HYBRID) || defined(LINUX_PORT)
77#define TYPEDEF_UINT
78#ifndef TARGETENV_android
79#define TYPEDEF_USHORT
80#define TYPEDEF_ULONG
81#endif
82#ifdef __KERNEL__
83#include <linux/version.h>
84#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19))
85#define TYPEDEF_BOOL
86#endif
87
88#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 18))
89#include <linux/compiler.h>
90#ifdef noinline_for_stack
91#define TYPEDEF_BOOL
92#endif
93#endif
94#endif
95#endif
96
97
98
99
100
101#if defined(__GNUC__) && defined(__STRICT_ANSI__)
102#define TYPEDEF_INT64
103#define TYPEDEF_UINT64
104#endif
105
106
107#if defined(__ICL)
108
109#define TYPEDEF_INT64
110
111#if defined(__STDC__)
112#define TYPEDEF_UINT64
113#endif
114
115#endif
116
117#if !defined(__DJGPP__)
118
119
120#if defined(__KERNEL__)
121
122
123#if !defined(LINUX_HYBRID) || defined(LINUX_PORT)
124#include <linux/types.h>
125#endif
126
127#else
128
129
130#include <sys/types.h>
131
132#endif
133
134#endif
135
136
137
138
139#define USE_TYPEDEF_DEFAULTS
140
141#endif
142
143
144
145
146#ifdef USE_TYPEDEF_DEFAULTS
147#undef USE_TYPEDEF_DEFAULTS
148
149#ifndef TYPEDEF_BOOL
150typedef unsigned char bool;
151#endif
152
153
154
155#ifndef TYPEDEF_UCHAR
156typedef unsigned char uchar;
157#endif
158
159#ifndef TYPEDEF_USHORT
160typedef unsigned short ushort;
161#endif
162
163#ifndef TYPEDEF_UINT
164typedef unsigned int uint;
165#endif
166
167#ifndef TYPEDEF_ULONG
168typedef unsigned long ulong;
169#endif
170
171
172
173#ifndef TYPEDEF_UINT8
174typedef unsigned char uint8;
175#endif
176
177#ifndef TYPEDEF_UINT16
178typedef unsigned short uint16;
179#endif
180
181#ifndef TYPEDEF_UINT32
182typedef unsigned int uint32;
183#endif
184
185#ifndef TYPEDEF_UINT64
186typedef unsigned long long uint64;
187#endif
188
189#ifndef TYPEDEF_UINTPTR
190typedef unsigned int uintptr;
191#endif
192
193#ifndef TYPEDEF_INT8
194typedef signed char int8;
195#endif
196
197#ifndef TYPEDEF_INT16
198typedef signed short int16;
199#endif
200
201#ifndef TYPEDEF_INT32
202typedef signed int int32;
203#endif
204
205#ifndef TYPEDEF_INT64
206typedef signed long long int64;
207#endif
208
209
210
211#ifndef TYPEDEF_FLOAT32
212typedef float float32;
213#endif
214
215#ifndef TYPEDEF_FLOAT64
216typedef double float64;
217#endif
218
219
220
221#ifndef TYPEDEF_FLOAT_T
222
223#if defined(FLOAT32)
224typedef float32 float_t;
225#else
226typedef float64 float_t;
227#endif
228
229#endif
230
231
232
233#ifndef FALSE
234#define FALSE 0
235#endif
236
237#ifndef TRUE
238#define TRUE 1
239#endif
240
241#ifndef NULL
242#define NULL 0
243#endif
244
245#ifndef OFF
246#define OFF 0
247#endif
248
249#ifndef ON
250#define ON 1
251#endif
252
253#define AUTO (-1)
254
255
256
257#ifndef PTRSZ
258#define PTRSZ sizeof(char*)
259#endif
260
261
262
263#if defined(__GNUC__)
264 #define BWL_COMPILER_GNU
265#elif defined(__CC_ARM) && __CC_ARM
266 #define BWL_COMPILER_ARMCC
267#else
268 #error "Unknown compiler!"
269#endif
270
271
272#ifndef INLINE
273 #if defined(BWL_COMPILER_MICROSOFT)
274 #define INLINE __inline
275 #elif defined(BWL_COMPILER_GNU)
276 #define INLINE __inline__
277 #elif defined(BWL_COMPILER_ARMCC)
278 #define INLINE __inline
279 #else
280 #define INLINE
281 #endif
282#endif
283
284#undef TYPEDEF_BOOL
285#undef TYPEDEF_UCHAR
286#undef TYPEDEF_USHORT
287#undef TYPEDEF_UINT
288#undef TYPEDEF_ULONG
289#undef TYPEDEF_UINT8
290#undef TYPEDEF_UINT16
291#undef TYPEDEF_UINT32
292#undef TYPEDEF_UINT64
293#undef TYPEDEF_UINTPTR
294#undef TYPEDEF_INT8
295#undef TYPEDEF_INT16
296#undef TYPEDEF_INT32
297#undef TYPEDEF_INT64
298#undef TYPEDEF_FLOAT32
299#undef TYPEDEF_FLOAT64
300#undef TYPEDEF_FLOAT_T
301
302#endif
303
304
305#define UNUSED_PARAMETER(x) (void)(x)
306
307
308#include <bcmdefs.h>
309#endif
diff --git a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
new file mode 100644
index 00000000000..7230d3b67ab
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h
@@ -0,0 +1,198 @@
1/*
2* Copyright (C) 1999-2011, Broadcom Corporation
3*
4* Unless you and Broadcom execute a separate written software license
5* agreement governing use of this software, this software is licensed to you
6* under the terms of the GNU General Public License version 2 (the "GPL"),
7* available at http://www.broadcom.com/licenses/GPLv2.php, with the
8* following added to such license:
9*
10* As a special exception, the copyright holders of this software give you
11* permission to link this software with independent modules, and to copy and
12* distribute the resulting executable under terms of your choice, provided that
13* you also meet, for each linked independent module, the terms and conditions of
14* the license of that module. An independent module is a module which is not
15* derived from this software. The special exception does not apply to any
16* modifications of the software.
17*
18* Notwithstanding the above, under no circumstances may you combine this
19* software in any way with any other Broadcom software provided under a license
20* other than the GPL, without Broadcom's express prior written consent.
21* $Id: wlfc_proto.h,v 1.1.6.2 2010-05-08 01:30:41 Exp $
22*
23*/
24#ifndef __wlfc_proto_definitions_h__
25#define __wlfc_proto_definitions_h__
26
27 /* Use TLV to convey WLFC information.
28 ---------------------------------------------------------------------------
29 | Type | Len | value | Description
30 ---------------------------------------------------------------------------
31 | 1 | 1 | (handle) | MAC OPEN
32 ---------------------------------------------------------------------------
33 | 2 | 1 | (handle) | MAC CLOSE
34 ---------------------------------------------------------------------------
35 | 3 | 2 | (count, handle, prec_bmp)| Set the credit depth for a MAC dstn
36 ---------------------------------------------------------------------------
37 | 4 | 4 | see pkttag comments | TXSTATUS
38 ---------------------------------------------------------------------------
39 | 5 | 4 | see pkttag comments | PKKTTAG [host->firmware]
40 ---------------------------------------------------------------------------
41 | 6 | 8 | (handle, ifid, MAC) | MAC ADD
42 ---------------------------------------------------------------------------
43 | 7 | 8 | (handle, ifid, MAC) | MAC DEL
44 ---------------------------------------------------------------------------
45 | 8 | 1 | (rssi) | RSSI - RSSI value for the packet.
46 ---------------------------------------------------------------------------
47 | 9 | 1 | (interface ID) | Interface OPEN
48 ---------------------------------------------------------------------------
49 | 10 | 1 | (interface ID) | Interface CLOSE
50 ---------------------------------------------------------------------------
51 | 11 | 8 | fifo credit returns map | FIFO credits back to the host
52 | | | |
53 | | | | --------------------------------------
54 | | | | | ac0 | ac1 | ac2 | ac3 | bcmc | atim |
55 | | | | --------------------------------------
56 | | | |
57 ---------------------------------------------------------------------------
58 | 12 | 2 | MAC handle, | Host provides a bitmap of pending
59 | | | AC[0-3] traffic bitmap | unicast traffic for MAC-handle dstn.
60 | | | | [host->firmware]
61 ---------------------------------------------------------------------------
62 | 13 | 3 | (count, handle, prec_bmp)| One time request for packet to a specific
63 | | | | MAC destination.
64 ---------------------------------------------------------------------------
65 | 255 | N/A | N/A | FILLER - This is a special type
66 | | | | that has no length or value.
67 | | | | Typically used for padding.
68 ---------------------------------------------------------------------------
69 */
70
71#define WLFC_CTL_TYPE_MAC_OPEN 1
72#define WLFC_CTL_TYPE_MAC_CLOSE 2
73#define WLFC_CTL_TYPE_MAC_REQUEST_CREDIT 3
74#define WLFC_CTL_TYPE_TXSTATUS 4
75#define WLFC_CTL_TYPE_PKTTAG 5
76
77#define WLFC_CTL_TYPE_MACDESC_ADD 6
78#define WLFC_CTL_TYPE_MACDESC_DEL 7
79#define WLFC_CTL_TYPE_RSSI 8
80
81#define WLFC_CTL_TYPE_INTERFACE_OPEN 9
82#define WLFC_CTL_TYPE_INTERFACE_CLOSE 10
83
84#define WLFC_CTL_TYPE_FIFO_CREDITBACK 11
85
86#define WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP 12
87#define WLFC_CTL_TYPE_MAC_REQUEST_PACKET 13
88
89#define WLFC_CTL_TYPE_FILLER 255
90
91#define WLFC_CTL_VALUE_LEN_MACDESC 8 /* handle, interface, MAC */
92
93#define WLFC_CTL_VALUE_LEN_MAC 1 /* MAC-handle */
94#define WLFC_CTL_VALUE_LEN_RSSI 1
95
96#define WLFC_CTL_VALUE_LEN_INTERFACE 1
97#define WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP 2
98
99#define WLFC_CTL_VALUE_LEN_TXSTATUS 4
100#define WLFC_CTL_VALUE_LEN_PKTTAG 4
101
102/* enough space to host all 4 ACs, bc/mc and atim fifo credit */
103#define WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK 6
104
105#define WLFC_CTL_VALUE_LEN_REQUEST_CREDIT 3 /* credit, MAC-handle, prec_bitmap */
106#define WLFC_CTL_VALUE_LEN_REQUEST_PACKET 3 /* credit, MAC-handle, prec_bitmap */
107
108
109
110#define WLFC_PKTID_GEN_MASK 0x80000000
111#define WLFC_PKTID_GEN_SHIFT 31
112
113#define WLFC_PKTID_GEN(x) (((x) & WLFC_PKTID_GEN_MASK) >> WLFC_PKTID_GEN_SHIFT)
114#define WLFC_PKTID_SETGEN(x, gen) (x) = ((x) & ~WLFC_PKTID_GEN_MASK) | \
115 (((gen) << WLFC_PKTID_GEN_SHIFT) & WLFC_PKTID_GEN_MASK)
116
117#define WLFC_PKTFLAG_PKTFROMHOST 0x01
118#define WLFC_PKTFLAG_PKT_REQUESTED 0x02
119
120#define WL_TXSTATUS_FLAGS_MASK 0xf /* allow 4 bits only */
121#define WL_TXSTATUS_FLAGS_SHIFT 27
122
123#define WL_TXSTATUS_SET_FLAGS(x, flags) ((x) = \
124 ((x) & ~(WL_TXSTATUS_FLAGS_MASK << WL_TXSTATUS_FLAGS_SHIFT)) | \
125 (((flags) & WL_TXSTATUS_FLAGS_MASK) << WL_TXSTATUS_FLAGS_SHIFT))
126#define WL_TXSTATUS_GET_FLAGS(x) (((x) >> WL_TXSTATUS_FLAGS_SHIFT) & \
127 WL_TXSTATUS_FLAGS_MASK)
128
129#define WL_TXSTATUS_FIFO_MASK 0x7 /* allow 3 bits for FIFO ID */
130#define WL_TXSTATUS_FIFO_SHIFT 24
131
132#define WL_TXSTATUS_SET_FIFO(x, flags) ((x) = \
133 ((x) & ~(WL_TXSTATUS_FIFO_MASK << WL_TXSTATUS_FIFO_SHIFT)) | \
134 (((flags) & WL_TXSTATUS_FIFO_MASK) << WL_TXSTATUS_FIFO_SHIFT))
135#define WL_TXSTATUS_GET_FIFO(x) (((x) >> WL_TXSTATUS_FIFO_SHIFT) & WL_TXSTATUS_FIFO_MASK)
136
137#define WL_TXSTATUS_PKTID_MASK 0xffffff /* allow 24 bits */
138#define WL_TXSTATUS_SET_PKTID(x, num) ((x) = \
139 ((x) & ~WL_TXSTATUS_PKTID_MASK) | (num))
140#define WL_TXSTATUS_GET_PKTID(x) ((x) & WL_TXSTATUS_PKTID_MASK)
141
142/* 32 STA should be enough??, 6 bits; Must be power of 2 */
143#define WLFC_MAC_DESC_TABLE_SIZE 32
144#define WLFC_MAX_IFNUM 16
145#define WLFC_MAC_DESC_ID_INVALID 0xff
146
147/* b[7:5] -reuse guard, b[4:0] -value */
148#define WLFC_MAC_DESC_GET_LOOKUP_INDEX(x) ((x) & 0x1f)
149
150#define WLFC_PKTFLAG_SET_PKTREQUESTED(x) (x) |= \
151 (WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT)
152
153#define WLFC_PKTFLAG_CLR_PKTREQUESTED(x) (x) &= \
154 ~(WLFC_PKTFLAG_PKT_REQUESTED << WL_TXSTATUS_FLAGS_SHIFT)
155
156#define WL_TXSTATUS_GENERATION_MASK 1
157#define WL_TXSTATUS_GENERATION_SHIFT 31
158
159#define WLFC_PKTFLAG_SET_GENERATION(x, gen) ((x) = \
160 ((x) & ~(WL_TXSTATUS_GENERATION_MASK << WL_TXSTATUS_GENERATION_SHIFT)) | \
161 (((gen) & WL_TXSTATUS_GENERATION_MASK) << WL_TXSTATUS_GENERATION_SHIFT))
162
163#define WLFC_PKTFLAG_GENERATION(x) (((x) >> WL_TXSTATUS_GENERATION_SHIFT) & \
164 WL_TXSTATUS_GENERATION_MASK)
165
166#define WLFC_MAX_PENDING_DATALEN 120
167
168/* host is free to discard the packet */
169#define WLFC_CTL_PKTFLAG_DISCARD 0
170/* D11 suppressed a packet */
171#define WLFC_CTL_PKTFLAG_D11SUPPRESS 1
172/* WL firmware suppressed a packet because MAC is
173 already in PSMode (short time window)
174*/
175#define WLFC_CTL_PKTFLAG_WLSUPPRESS 2
176/* Firmware tossed this packet */
177#define WLFC_CTL_PKTFLAG_TOSSED_BYWLC 3
178
179#define WLFC_D11_STATUS_INTERPRET(txs) ((((txs)->status & TX_STATUS_SUPR_MASK) >> \
180 TX_STATUS_SUPR_SHIFT)) ? WLFC_CTL_PKTFLAG_D11SUPPRESS : WLFC_CTL_PKTFLAG_DISCARD
181
182#ifdef PROP_TXSTATUS_DEBUG
183#define WLFC_DBGMESG(x) printf x
184/* wlfc-breadcrumb */
185#define WLFC_BREADCRUMB(x) do {if ((x) == NULL) \
186 {printf("WLFC: %s():%d:caller:%p\n", \
187 __FUNCTION__, __LINE__, __builtin_return_address(0));}} while (0)
188#define WLFC_PRINTMAC(banner, ea) do {printf("%s MAC: [%02x:%02x:%02x:%02x:%02x:%02x]\n", \
189 banner, ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]); } while (0)
190#define WLFC_WHEREIS(s) printf("WLFC: at %s():%d, %s\n", __FUNCTION__, __LINE__, (s))
191#else
192#define WLFC_DBGMESG(x)
193#define WLFC_BREADCRUMB(x)
194#define WLFC_PRINTMAC(banner, ea)
195#define WLFC_WHEREIS(s)
196#endif
197
198#endif /* __wlfc_proto_definitions_h__ */
diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h
new file mode 100644
index 00000000000..9357552c919
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h
@@ -0,0 +1,2757 @@
1/*
2 * Custom OID/ioctl definitions for
3 * Broadcom 802.11abg Networking Device Driver
4 *
5 * Definitions subject to change without notice.
6 *
7 * Copyright (C) 1999-2011, Broadcom Corporation
8 *
9 * Unless you and Broadcom execute a separate written software license
10 * agreement governing use of this software, this software is licensed to you
11 * under the terms of the GNU General Public License version 2 (the "GPL"),
12 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
13 * following added to such license:
14 *
15 * As a special exception, the copyright holders of this software give you
16 * permission to link this software with independent modules, and to copy and
17 * distribute the resulting executable under terms of your choice, provided that
18 * you also meet, for each linked independent module, the terms and conditions of
19 * the license of that module. An independent module is a module which is not
20 * derived from this software. The special exception does not apply to any
21 * modifications of the software.
22 *
23 * Notwithstanding the above, under no circumstances may you combine this
24 * software in any way with any other Broadcom software provided under a license
25 * other than the GPL, without Broadcom's express prior written consent.
26 *
27 * $Id: wlioctl.h,v 1.767.2.38 2011-02-01 23:04:28 Exp $
28 */
29
30
31#ifndef _wlioctl_h_
32#define _wlioctl_h_
33
34#include <typedefs.h>
35#include <proto/ethernet.h>
36#include <proto/bcmeth.h>
37#include <proto/bcmevent.h>
38#include <proto/802.11.h>
39#include <bcmwifi.h>
40
41#include <bcmcdc.h>
42
43#ifndef INTF_NAME_SIZ
44#define INTF_NAME_SIZ 16
45#endif
46
47
48typedef struct remote_ioctl {
49 cdc_ioctl_t msg;
50 uint data_len;
51 char intf_name[INTF_NAME_SIZ];
52} rem_ioctl_t;
53#define REMOTE_SIZE sizeof(rem_ioctl_t)
54
55#define ACTION_FRAME_SIZE 1040
56
57typedef struct wl_action_frame {
58 struct ether_addr da;
59 uint16 len;
60 uint32 packetId;
61 uint8 data[ACTION_FRAME_SIZE];
62} wl_action_frame_t;
63
64#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame)
65
66typedef struct ssid_info
67{
68 uint8 ssid_len;
69 uint8 ssid[32];
70} ssid_info_t;
71
72typedef struct wl_af_params {
73 uint32 channel;
74 int32 dwell_time;
75 struct ether_addr BSSID;
76 wl_action_frame_t action_frame;
77} wl_af_params_t;
78
79#define WL_WIFI_AF_PARAMS_SIZE sizeof(struct wl_af_params)
80
81
82#define BWL_DEFAULT_PACKING
83#include <packed_section_start.h>
84
85
86
87
88
89#define LEGACY2_WL_BSS_INFO_VERSION 108
90
91
92typedef struct wl_bss_info_108 {
93 uint32 version;
94 uint32 length;
95 struct ether_addr BSSID;
96 uint16 beacon_period;
97 uint16 capability;
98 uint8 SSID_len;
99 uint8 SSID[32];
100 struct {
101 uint count;
102 uint8 rates[16];
103 } rateset;
104 chanspec_t chanspec;
105 uint16 atim_window;
106 uint8 dtim_period;
107 int16 RSSI;
108 int8 phy_noise;
109
110 uint8 n_cap;
111 uint32 nbss_cap;
112 uint8 ctl_ch;
113 uint32 reserved32[1];
114 uint8 flags;
115 uint8 reserved[3];
116 uint8 basic_mcs[MCSSET_LEN];
117
118 uint16 ie_offset;
119 uint32 ie_length;
120
121
122} wl_bss_info_108_t;
123
124#define WL_BSS_INFO_VERSION 109
125
126
127typedef struct wl_bss_info {
128 uint32 version;
129 uint32 length;
130 struct ether_addr BSSID;
131 uint16 beacon_period;
132 uint16 capability;
133 uint8 SSID_len;
134 uint8 SSID[32];
135 struct {
136 uint count;
137 uint8 rates[16];
138 } rateset;
139 chanspec_t chanspec;
140 uint16 atim_window;
141 uint8 dtim_period;
142 int16 RSSI;
143 int8 phy_noise;
144
145 uint8 n_cap;
146 uint32 nbss_cap;
147 uint8 ctl_ch;
148 uint32 reserved32[1];
149 uint8 flags;
150 uint8 reserved[3];
151 uint8 basic_mcs[MCSSET_LEN];
152
153 uint16 ie_offset;
154 uint32 ie_length;
155 int16 SNR;
156
157
158} wl_bss_info_t;
159
160typedef struct wl_bsscfg {
161 uint32 wsec;
162 uint32 WPA_auth;
163 uint32 wsec_index;
164 uint32 associated;
165 uint32 BSS;
166 uint32 phytest_on;
167 struct ether_addr prev_BSSID;
168 struct ether_addr BSSID;
169} wl_bsscfg_t;
170
171typedef struct wl_bss_config {
172 uint32 atim_window;
173 uint32 beacon_period;
174 uint32 chanspec;
175} wl_bss_config_t;
176
177
178typedef struct wlc_ssid {
179 uint32 SSID_len;
180 uchar SSID[32];
181} wlc_ssid_t;
182
183
184#define WL_BSSTYPE_INFRA 1
185#define WL_BSSTYPE_INDEP 0
186#define WL_BSSTYPE_ANY 2
187
188
189#define WL_SCANFLAGS_PASSIVE 0x01
190#define WL_SCANFLAGS_RESERVED 0x02
191#define WL_SCANFLAGS_PROHIBITED 0x04
192
193#define WL_SCAN_PARAMS_SSID_MAX 10
194typedef struct wl_scan_params {
195 wlc_ssid_t ssid;
196 struct ether_addr bssid;
197 int8 bss_type;
198 uint8 scan_type;
199 int32 nprobes;
200 int32 active_time;
201 int32 passive_time;
202 int32 home_time;
203 int32 channel_num;
204 uint16 channel_list[1];
205} wl_scan_params_t;
206
207
208#define WL_SCAN_PARAMS_FIXED_SIZE 64
209
210
211#define WL_SCAN_PARAMS_COUNT_MASK 0x0000ffff
212#define WL_SCAN_PARAMS_NSSID_SHIFT 16
213
214#define WL_SCAN_ACTION_START 1
215#define WL_SCAN_ACTION_CONTINUE 2
216#define WL_SCAN_ACTION_ABORT 3
217
218#define ISCAN_REQ_VERSION 1
219
220
221typedef struct wl_iscan_params {
222 uint32 version;
223 uint16 action;
224 uint16 scan_duration;
225 wl_scan_params_t params;
226} wl_iscan_params_t;
227
228
229#define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t))
230
231typedef struct wl_scan_results {
232 uint32 buflen;
233 uint32 version;
234 uint32 count;
235 wl_bss_info_t bss_info[1];
236} wl_scan_results_t;
237
238
239#define WL_SCAN_RESULTS_FIXED_SIZE (sizeof(wl_scan_results_t) - sizeof(wl_bss_info_t))
240
241
242#define WL_SCAN_RESULTS_SUCCESS 0
243#define WL_SCAN_RESULTS_PARTIAL 1
244#define WL_SCAN_RESULTS_PENDING 2
245#define WL_SCAN_RESULTS_ABORTED 3
246#define WL_SCAN_RESULTS_NO_MEM 4
247
248
249#define DNGL_RXCTXT_SIZE 45
250
251#if defined(SIMPLE_ISCAN)
252#define ISCAN_RETRY_CNT 5
253#define ISCAN_STATE_IDLE 0
254#define ISCAN_STATE_SCANING 1
255#define ISCAN_STATE_PENDING 2
256
257
258#define WLC_IW_ISCAN_MAXLEN 2048
259typedef struct iscan_buf {
260 struct iscan_buf * next;
261 char iscan_buf[WLC_IW_ISCAN_MAXLEN];
262} iscan_buf_t;
263#endif
264
265#define ESCAN_REQ_VERSION 1
266
267typedef struct wl_escan_params {
268 uint32 version;
269 uint16 action;
270 uint16 sync_id;
271 wl_scan_params_t params;
272} wl_escan_params_t;
273
274#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t))
275
276typedef struct wl_escan_result {
277 uint32 buflen;
278 uint32 version;
279 uint16 sync_id;
280 uint16 bss_count;
281 wl_bss_info_t bss_info[1];
282} wl_escan_result_t;
283
284#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t))
285
286
287typedef struct wl_iscan_results {
288 uint32 status;
289 wl_scan_results_t results;
290} wl_iscan_results_t;
291
292
293#define WL_ISCAN_RESULTS_FIXED_SIZE \
294 (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results))
295
296typedef struct wl_probe_params {
297 wlc_ssid_t ssid;
298 struct ether_addr bssid;
299 struct ether_addr mac;
300} wl_probe_params_t;
301
302#define WL_NUMRATES 16
303typedef struct wl_rateset {
304 uint32 count;
305 uint8 rates[WL_NUMRATES];
306} wl_rateset_t;
307
308typedef struct wl_rateset_args {
309 uint32 count;
310 uint8 rates[WL_NUMRATES];
311 uint8 mcs[MCSSET_LEN];
312} wl_rateset_args_t;
313
314
315typedef struct wl_uint32_list {
316
317 uint32 count;
318
319 uint32 element[1];
320} wl_uint32_list_t;
321
322
323typedef struct wl_assoc_params {
324 struct ether_addr bssid;
325 uint16 bssid_cnt;
326 int32 chanspec_num;
327 chanspec_t chanspec_list[1];
328} wl_assoc_params_t;
329#define WL_ASSOC_PARAMS_FIXED_SIZE (sizeof(wl_assoc_params_t) - sizeof(chanspec_t))
330
331
332typedef wl_assoc_params_t wl_reassoc_params_t;
333#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE
334
335
336typedef wl_assoc_params_t wl_join_assoc_params_t;
337#define WL_JOIN_ASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE
338
339
340typedef struct wl_join_params {
341 wlc_ssid_t ssid;
342 wl_assoc_params_t params;
343} wl_join_params_t;
344#define WL_JOIN_PARAMS_FIXED_SIZE (sizeof(wl_join_params_t) - sizeof(chanspec_t))
345
346
347typedef struct wl_join_scan_params {
348 uint8 scan_type;
349 int32 nprobes;
350 int32 active_time;
351 int32 passive_time;
352 int32 home_time;
353} wl_join_scan_params_t;
354
355
356typedef struct wl_extjoin_params {
357 wlc_ssid_t ssid;
358 wl_join_scan_params_t scan;
359 wl_join_assoc_params_t assoc;
360} wl_extjoin_params_t;
361#define WL_EXTJOIN_PARAMS_FIXED_SIZE (sizeof(wl_extjoin_params_t) - sizeof(chanspec_t))
362
363typedef struct {
364 uint32 num;
365 chanspec_t list[1];
366} chanspec_list_t;
367
368
369#define NRATE_MCS_INUSE 0x00000080
370#define NRATE_RATE_MASK 0x0000007f
371#define NRATE_STF_MASK 0x0000ff00
372#define NRATE_STF_SHIFT 8
373#define NRATE_OVERRIDE 0x80000000
374#define NRATE_OVERRIDE_MCS_ONLY 0x40000000
375#define NRATE_SGI_MASK 0x00800000
376#define NRATE_SGI_SHIFT 23
377#define NRATE_LDPC_CODING 0x00400000
378#define NRATE_LDPC_SHIFT 22
379
380#define NRATE_STF_SISO 0
381#define NRATE_STF_CDD 1
382#define NRATE_STF_STBC 2
383#define NRATE_STF_SDM 3
384
385#define ANTENNA_NUM_1 1
386#define ANTENNA_NUM_2 2
387#define ANTENNA_NUM_3 3
388#define ANTENNA_NUM_4 4
389
390#define ANT_SELCFG_AUTO 0x80
391#define ANT_SELCFG_MASK 0x33
392#define ANT_SELCFG_MAX 4
393#define ANT_SELCFG_TX_UNICAST 0
394#define ANT_SELCFG_RX_UNICAST 1
395#define ANT_SELCFG_TX_DEF 2
396#define ANT_SELCFG_RX_DEF 3
397
398#define MAX_STREAMS_SUPPORTED 4
399
400typedef struct {
401 uint8 ant_config[ANT_SELCFG_MAX];
402 uint8 num_antcfg;
403} wlc_antselcfg_t;
404
405#define HIGHEST_SINGLE_STREAM_MCS 7
406
407#define MAX_CCA_CHANNELS 38
408#define MAX_CCA_SECS 60
409
410#define IBSS_MED 15
411#define IBSS_HI 25
412#define OBSS_MED 12
413#define OBSS_HI 25
414#define INTERFER_MED 5
415#define INTERFER_HI 10
416
417#define CCA_FLAG_2G_ONLY 0x01
418#define CCA_FLAG_5G_ONLY 0x02
419#define CCA_FLAG_IGNORE_DURATION 0x04
420#define CCA_FLAGS_PREFER_1_6_11 0x10
421#define CCA_FLAG_IGNORE_INTERFER 0x20
422
423#define CCA_ERRNO_BAND 1
424#define CCA_ERRNO_DURATION 2
425#define CCA_ERRNO_PREF_CHAN 3
426#define CCA_ERRNO_INTERFER 4
427#define CCA_ERRNO_TOO_FEW 5
428
429typedef struct {
430 uint32 duration;
431 uint32 congest_ibss;
432
433 uint32 congest_obss;
434 uint32 interference;
435 uint32 timestamp;
436} cca_congest_t;
437
438typedef struct {
439 chanspec_t chanspec;
440 uint8 num_secs;
441 cca_congest_t secs[1];
442} cca_congest_channel_req_t;
443
444#define WLC_CNTRY_BUF_SZ 4
445
446typedef struct wl_country {
447 char country_abbrev[WLC_CNTRY_BUF_SZ];
448 int32 rev;
449 char ccode[WLC_CNTRY_BUF_SZ];
450} wl_country_t;
451
452typedef struct wl_channels_in_country {
453 uint32 buflen;
454 uint32 band;
455 char country_abbrev[WLC_CNTRY_BUF_SZ];
456 uint32 count;
457 uint32 channel[1];
458} wl_channels_in_country_t;
459
460typedef struct wl_country_list {
461 uint32 buflen;
462 uint32 band_set;
463 uint32 band;
464 uint32 count;
465 char country_abbrev[1];
466} wl_country_list_t;
467
468#define WL_NUM_RPI_BINS 8
469#define WL_RM_TYPE_BASIC 1
470#define WL_RM_TYPE_CCA 2
471#define WL_RM_TYPE_RPI 3
472
473#define WL_RM_FLAG_PARALLEL (1<<0)
474
475#define WL_RM_FLAG_LATE (1<<1)
476#define WL_RM_FLAG_INCAPABLE (1<<2)
477#define WL_RM_FLAG_REFUSED (1<<3)
478
479typedef struct wl_rm_req_elt {
480 int8 type;
481 int8 flags;
482 chanspec_t chanspec;
483 uint32 token;
484 uint32 tsf_h;
485 uint32 tsf_l;
486 uint32 dur;
487} wl_rm_req_elt_t;
488
489typedef struct wl_rm_req {
490 uint32 token;
491 uint32 count;
492 void *cb;
493 void *cb_arg;
494 wl_rm_req_elt_t req[1];
495} wl_rm_req_t;
496#define WL_RM_REQ_FIXED_LEN OFFSETOF(wl_rm_req_t, req)
497
498typedef struct wl_rm_rep_elt {
499 int8 type;
500 int8 flags;
501 chanspec_t chanspec;
502 uint32 token;
503 uint32 tsf_h;
504 uint32 tsf_l;
505 uint32 dur;
506 uint32 len;
507 uint8 data[1];
508} wl_rm_rep_elt_t;
509#define WL_RM_REP_ELT_FIXED_LEN 24
510
511#define WL_RPI_REP_BIN_NUM 8
512typedef struct wl_rm_rpi_rep {
513 uint8 rpi[WL_RPI_REP_BIN_NUM];
514 int8 rpi_max[WL_RPI_REP_BIN_NUM];
515} wl_rm_rpi_rep_t;
516
517typedef struct wl_rm_rep {
518 uint32 token;
519 uint32 len;
520 wl_rm_rep_elt_t rep[1];
521} wl_rm_rep_t;
522#define WL_RM_REP_FIXED_LEN 8
523
524
525typedef enum sup_auth_status {
526
527 WLC_SUP_DISCONNECTED = 0,
528 WLC_SUP_CONNECTING,
529 WLC_SUP_IDREQUIRED,
530 WLC_SUP_AUTHENTICATING,
531 WLC_SUP_AUTHENTICATED,
532 WLC_SUP_KEYXCHANGE,
533 WLC_SUP_KEYED,
534 WLC_SUP_TIMEOUT,
535 WLC_SUP_LAST_BASIC_STATE,
536
537
538
539 WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED,
540
541 WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE,
542
543 WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE,
544 WLC_SUP_KEYXCHANGE_PREP_M4,
545 WLC_SUP_KEYXCHANGE_WAIT_G1,
546 WLC_SUP_KEYXCHANGE_PREP_G2
547} sup_auth_status_t;
548
549
550#define CRYPTO_ALGO_OFF 0
551#define CRYPTO_ALGO_WEP1 1
552#define CRYPTO_ALGO_TKIP 2
553#define CRYPTO_ALGO_WEP128 3
554#define CRYPTO_ALGO_AES_CCM 4
555#define CRYPTO_ALGO_AES_OCB_MSDU 5
556#define CRYPTO_ALGO_AES_OCB_MPDU 6
557#define CRYPTO_ALGO_NALG 7
558#define CRYPTO_ALGO_PMK 12
559
560#define WSEC_GEN_MIC_ERROR 0x0001
561#define WSEC_GEN_REPLAY 0x0002
562#define WSEC_GEN_ICV_ERROR 0x0004
563
564#define WL_SOFT_KEY (1 << 0)
565#define WL_PRIMARY_KEY (1 << 1)
566#define WL_KF_RES_4 (1 << 4)
567#define WL_KF_RES_5 (1 << 5)
568#define WL_IBSS_PEER_GROUP_KEY (1 << 6)
569
570typedef struct wl_wsec_key {
571 uint32 index;
572 uint32 len;
573 uint8 data[DOT11_MAX_KEY_SIZE];
574 uint32 pad_1[18];
575 uint32 algo;
576 uint32 flags;
577 uint32 pad_2[2];
578 int pad_3;
579 int iv_initialized;
580 int pad_4;
581
582 struct {
583 uint32 hi;
584 uint16 lo;
585 } rxiv;
586 uint32 pad_5[2];
587 struct ether_addr ea;
588} wl_wsec_key_t;
589
590#define WSEC_MIN_PSK_LEN 8
591#define WSEC_MAX_PSK_LEN 64
592
593
594#define WSEC_PASSPHRASE (1<<0)
595
596
597typedef struct {
598 ushort key_len;
599 ushort flags;
600 uint8 key[WSEC_MAX_PSK_LEN];
601} wsec_pmk_t;
602
603
604#define WEP_ENABLED 0x0001
605#define TKIP_ENABLED 0x0002
606#define AES_ENABLED 0x0004
607#define WSEC_SWFLAG 0x0008
608#define SES_OW_ENABLED 0x0040
609
610
611#define WPA_AUTH_DISABLED 0x0000
612#define WPA_AUTH_NONE 0x0001
613#define WPA_AUTH_UNSPECIFIED 0x0002
614#define WPA_AUTH_PSK 0x0004
615
616#define WPA2_AUTH_UNSPECIFIED 0x0040
617#define WPA2_AUTH_PSK 0x0080
618#define BRCM_AUTH_PSK 0x0100
619#define BRCM_AUTH_DPT 0x0200
620#define WPA2_AUTH_MFP 0x1000
621#define WPA2_AUTH_TPK 0x2000
622#define WPA2_AUTH_FT 0x4000
623
624
625#define MAXPMKID 16
626
627typedef struct _pmkid {
628 struct ether_addr BSSID;
629 uint8 PMKID[WPA2_PMKID_LEN];
630} pmkid_t;
631
632typedef struct _pmkid_list {
633 uint32 npmkid;
634 pmkid_t pmkid[1];
635} pmkid_list_t;
636
637typedef struct _pmkid_cand {
638 struct ether_addr BSSID;
639 uint8 preauth;
640} pmkid_cand_t;
641
642typedef struct _pmkid_cand_list {
643 uint32 npmkid_cand;
644 pmkid_cand_t pmkid_cand[1];
645} pmkid_cand_list_t;
646
647typedef struct wl_assoc_info {
648 uint32 req_len;
649 uint32 resp_len;
650 uint32 flags;
651 struct dot11_assoc_req req;
652 struct ether_addr reassoc_bssid;
653 struct dot11_assoc_resp resp;
654} wl_assoc_info_t;
655
656
657#define WLC_ASSOC_REQ_IS_REASSOC 0x01
658
659
660typedef struct {
661 uint16 ver;
662 uint16 len;
663 uint16 cap;
664 uint32 flags;
665 uint32 idle;
666 struct ether_addr ea;
667 wl_rateset_t rateset;
668 uint32 in;
669 uint32 listen_interval_inms;
670 uint32 tx_pkts;
671 uint32 tx_failures;
672 uint32 rx_ucast_pkts;
673 uint32 rx_mcast_pkts;
674 uint32 tx_rate;
675 uint32 rx_rate;
676 uint32 rx_decrypt_succeeds;
677 uint32 rx_decrypt_failures;
678} sta_info_t;
679
680#define WL_OLD_STAINFO_SIZE OFFSETOF(sta_info_t, tx_pkts)
681
682#define WL_STA_VER 3
683
684
685#define WL_STA_BRCM 0x1
686#define WL_STA_WME 0x2
687#define WL_STA_ABCAP 0x4
688#define WL_STA_AUTHE 0x8
689#define WL_STA_ASSOC 0x10
690#define WL_STA_AUTHO 0x20
691#define WL_STA_WDS 0x40
692#define WL_STA_WDS_LINKUP 0x80
693#define WL_STA_PS 0x100
694#define WL_STA_APSD_BE 0x200
695#define WL_STA_APSD_BK 0x400
696#define WL_STA_APSD_VI 0x800
697#define WL_STA_APSD_VO 0x1000
698#define WL_STA_N_CAP 0x2000
699#define WL_STA_SCBSTATS 0x4000
700
701#define WL_WDS_LINKUP WL_STA_WDS_LINKUP
702
703
704#define WLC_TXFILTER_OVERRIDE_DISABLED 0
705#define WLC_TXFILTER_OVERRIDE_ENABLED 1
706
707
708typedef struct {
709 uint32 val;
710 struct ether_addr ea;
711} scb_val_t;
712
713
714typedef struct {
715 uint32 code;
716 scb_val_t ioctl_args;
717} authops_t;
718
719
720typedef struct channel_info {
721 int hw_channel;
722 int target_channel;
723 int scan_channel;
724} channel_info_t;
725
726
727struct maclist {
728 uint count;
729 struct ether_addr ea[1];
730};
731
732
733typedef struct get_pktcnt {
734 uint rx_good_pkt;
735 uint rx_bad_pkt;
736 uint tx_good_pkt;
737 uint tx_bad_pkt;
738 uint rx_ocast_good_pkt;
739} get_pktcnt_t;
740
741#define WL_IOCTL_ACTION_GET 0x0
742#define WL_IOCTL_ACTION_SET 0x1
743#define WL_IOCTL_ACTION_OVL_IDX_MASK 0x1e
744#define WL_IOCTL_ACTION_OVL_RSV 0x20
745#define WL_IOCTL_ACTION_OVL 0x40
746#define WL_IOCTL_ACTION_MASK 0x7e
747#define WL_IOCTL_ACTION_OVL_SHIFT 1
748
749
750typedef struct wl_ioctl {
751 uint cmd;
752 void *buf;
753 uint len;
754 uint8 set;
755 uint used;
756 uint needed;
757} wl_ioctl_t;
758
759
760#define ioctl_subtype set
761#define ioctl_pid used
762#define ioctl_status needed
763
764
765typedef struct wlc_rev_info {
766 uint vendorid;
767 uint deviceid;
768 uint radiorev;
769 uint chiprev;
770 uint corerev;
771 uint boardid;
772 uint boardvendor;
773 uint boardrev;
774 uint driverrev;
775 uint ucoderev;
776 uint bus;
777 uint chipnum;
778 uint phytype;
779 uint phyrev;
780 uint anarev;
781 uint chippkg;
782} wlc_rev_info_t;
783
784#define WL_REV_INFO_LEGACY_LENGTH 48
785
786#define WL_BRAND_MAX 10
787typedef struct wl_instance_info {
788 uint instance;
789 char brand[WL_BRAND_MAX];
790} wl_instance_info_t;
791
792
793typedef struct wl_txfifo_sz {
794 uint16 magic;
795 uint16 fifo;
796 uint16 size;
797} wl_txfifo_sz_t;
798
799#define WL_TXFIFO_SZ_MAGIC 0xa5a5
800
801
802
803#define WLC_IOV_NAME_LEN 30
804typedef struct wlc_iov_trx_s {
805 uint8 module;
806 uint8 type;
807 char name[WLC_IOV_NAME_LEN];
808} wlc_iov_trx_t;
809
810
811#define WLC_IOCTL_MAGIC 0x14e46c77
812
813
814#define WLC_IOCTL_VERSION 1
815
816#define WLC_IOCTL_MAXLEN 8192
817#define WLC_IOCTL_SMLEN 256
818#define WLC_IOCTL_MEDLEN 1536
819#ifdef WLC_HIGH_ONLY
820#define WLC_SAMPLECOLLECT_MAXLEN 1024
821#else
822#define WLC_SAMPLECOLLECT_MAXLEN 10240
823#endif
824
825
826#define WLC_GET_MAGIC 0
827#define WLC_GET_VERSION 1
828#define WLC_UP 2
829#define WLC_DOWN 3
830#define WLC_GET_LOOP 4
831#define WLC_SET_LOOP 5
832#define WLC_DUMP 6
833#define WLC_GET_MSGLEVEL 7
834#define WLC_SET_MSGLEVEL 8
835#define WLC_GET_PROMISC 9
836#define WLC_SET_PROMISC 10
837#define WLC_OVERLAY_IOCTL 11
838#define WLC_GET_RATE 12
839
840#define WLC_GET_INSTANCE 14
841
842
843
844
845#define WLC_GET_INFRA 19
846#define WLC_SET_INFRA 20
847#define WLC_GET_AUTH 21
848#define WLC_SET_AUTH 22
849#define WLC_GET_BSSID 23
850#define WLC_SET_BSSID 24
851#define WLC_GET_SSID 25
852#define WLC_SET_SSID 26
853#define WLC_RESTART 27
854
855#define WLC_GET_CHANNEL 29
856#define WLC_SET_CHANNEL 30
857#define WLC_GET_SRL 31
858#define WLC_SET_SRL 32
859#define WLC_GET_LRL 33
860#define WLC_SET_LRL 34
861#define WLC_GET_PLCPHDR 35
862#define WLC_SET_PLCPHDR 36
863#define WLC_GET_RADIO 37
864#define WLC_SET_RADIO 38
865#define WLC_GET_PHYTYPE 39
866#define WLC_DUMP_RATE 40
867#define WLC_SET_RATE_PARAMS 41
868#define WLC_GET_FIXRATE 42
869#define WLC_SET_FIXRATE 43
870
871
872#define WLC_GET_KEY 44
873#define WLC_SET_KEY 45
874#define WLC_GET_REGULATORY 46
875#define WLC_SET_REGULATORY 47
876#define WLC_GET_PASSIVE_SCAN 48
877#define WLC_SET_PASSIVE_SCAN 49
878#define WLC_SCAN 50
879#define WLC_SCAN_RESULTS 51
880#define WLC_DISASSOC 52
881#define WLC_REASSOC 53
882#define WLC_GET_ROAM_TRIGGER 54
883#define WLC_SET_ROAM_TRIGGER 55
884#define WLC_GET_ROAM_DELTA 56
885#define WLC_SET_ROAM_DELTA 57
886#define WLC_GET_ROAM_SCAN_PERIOD 58
887#define WLC_SET_ROAM_SCAN_PERIOD 59
888#define WLC_EVM 60
889#define WLC_GET_TXANT 61
890#define WLC_SET_TXANT 62
891#define WLC_GET_ANTDIV 63
892#define WLC_SET_ANTDIV 64
893
894
895#define WLC_GET_CLOSED 67
896#define WLC_SET_CLOSED 68
897#define WLC_GET_MACLIST 69
898#define WLC_SET_MACLIST 70
899#define WLC_GET_RATESET 71
900#define WLC_SET_RATESET 72
901
902#define WLC_LONGTRAIN 74
903#define WLC_GET_BCNPRD 75
904#define WLC_SET_BCNPRD 76
905#define WLC_GET_DTIMPRD 77
906#define WLC_SET_DTIMPRD 78
907#define WLC_GET_SROM 79
908#define WLC_SET_SROM 80
909#define WLC_GET_WEP_RESTRICT 81
910#define WLC_SET_WEP_RESTRICT 82
911#define WLC_GET_COUNTRY 83
912#define WLC_SET_COUNTRY 84
913#define WLC_GET_PM 85
914#define WLC_SET_PM 86
915#define WLC_GET_WAKE 87
916#define WLC_SET_WAKE 88
917
918#define WLC_GET_FORCELINK 90
919#define WLC_SET_FORCELINK 91
920#define WLC_FREQ_ACCURACY 92
921#define WLC_CARRIER_SUPPRESS 93
922#define WLC_GET_PHYREG 94
923#define WLC_SET_PHYREG 95
924#define WLC_GET_RADIOREG 96
925#define WLC_SET_RADIOREG 97
926#define WLC_GET_REVINFO 98
927#define WLC_GET_UCANTDIV 99
928#define WLC_SET_UCANTDIV 100
929#define WLC_R_REG 101
930#define WLC_W_REG 102
931
932
933#define WLC_GET_MACMODE 105
934#define WLC_SET_MACMODE 106
935#define WLC_GET_MONITOR 107
936#define WLC_SET_MONITOR 108
937#define WLC_GET_GMODE 109
938#define WLC_SET_GMODE 110
939#define WLC_GET_LEGACY_ERP 111
940#define WLC_SET_LEGACY_ERP 112
941#define WLC_GET_RX_ANT 113
942#define WLC_GET_CURR_RATESET 114
943#define WLC_GET_SCANSUPPRESS 115
944#define WLC_SET_SCANSUPPRESS 116
945#define WLC_GET_AP 117
946#define WLC_SET_AP 118
947#define WLC_GET_EAP_RESTRICT 119
948#define WLC_SET_EAP_RESTRICT 120
949#define WLC_SCB_AUTHORIZE 121
950#define WLC_SCB_DEAUTHORIZE 122
951#define WLC_GET_WDSLIST 123
952#define WLC_SET_WDSLIST 124
953#define WLC_GET_ATIM 125
954#define WLC_SET_ATIM 126
955#define WLC_GET_RSSI 127
956#define WLC_GET_PHYANTDIV 128
957#define WLC_SET_PHYANTDIV 129
958#define WLC_AP_RX_ONLY 130
959#define WLC_GET_TX_PATH_PWR 131
960#define WLC_SET_TX_PATH_PWR 132
961#define WLC_GET_WSEC 133
962#define WLC_SET_WSEC 134
963#define WLC_GET_PHY_NOISE 135
964#define WLC_GET_BSS_INFO 136
965#define WLC_GET_PKTCNTS 137
966#define WLC_GET_LAZYWDS 138
967#define WLC_SET_LAZYWDS 139
968#define WLC_GET_BANDLIST 140
969#define WLC_GET_BAND 141
970#define WLC_SET_BAND 142
971#define WLC_SCB_DEAUTHENTICATE 143
972#define WLC_GET_SHORTSLOT 144
973#define WLC_GET_SHORTSLOT_OVERRIDE 145
974#define WLC_SET_SHORTSLOT_OVERRIDE 146
975#define WLC_GET_SHORTSLOT_RESTRICT 147
976#define WLC_SET_SHORTSLOT_RESTRICT 148
977#define WLC_GET_GMODE_PROTECTION 149
978#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150
979#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151
980#define WLC_UPGRADE 152
981
982
983#define WLC_GET_IGNORE_BCNS 155
984#define WLC_SET_IGNORE_BCNS 156
985#define WLC_GET_SCB_TIMEOUT 157
986#define WLC_SET_SCB_TIMEOUT 158
987#define WLC_GET_ASSOCLIST 159
988#define WLC_GET_CLK 160
989#define WLC_SET_CLK 161
990#define WLC_GET_UP 162
991#define WLC_OUT 163
992#define WLC_GET_WPA_AUTH 164
993#define WLC_SET_WPA_AUTH 165
994#define WLC_GET_UCFLAGS 166
995#define WLC_SET_UCFLAGS 167
996#define WLC_GET_PWRIDX 168
997#define WLC_SET_PWRIDX 169
998#define WLC_GET_TSSI 170
999#define WLC_GET_SUP_RATESET_OVERRIDE 171
1000#define WLC_SET_SUP_RATESET_OVERRIDE 172
1001
1002
1003
1004
1005
1006#define WLC_GET_PROTECTION_CONTROL 178
1007#define WLC_SET_PROTECTION_CONTROL 179
1008#define WLC_GET_PHYLIST 180
1009#define WLC_ENCRYPT_STRENGTH 181
1010#define WLC_DECRYPT_STATUS 182
1011#define WLC_GET_KEY_SEQ 183
1012#define WLC_GET_SCAN_CHANNEL_TIME 184
1013#define WLC_SET_SCAN_CHANNEL_TIME 185
1014#define WLC_GET_SCAN_UNASSOC_TIME 186
1015#define WLC_SET_SCAN_UNASSOC_TIME 187
1016#define WLC_GET_SCAN_HOME_TIME 188
1017#define WLC_SET_SCAN_HOME_TIME 189
1018#define WLC_GET_SCAN_NPROBES 190
1019#define WLC_SET_SCAN_NPROBES 191
1020#define WLC_GET_PRB_RESP_TIMEOUT 192
1021#define WLC_SET_PRB_RESP_TIMEOUT 193
1022#define WLC_GET_ATTEN 194
1023#define WLC_SET_ATTEN 195
1024#define WLC_GET_SHMEM 196
1025#define WLC_SET_SHMEM 197
1026
1027
1028#define WLC_SET_WSEC_TEST 200
1029#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201
1030#define WLC_TKIP_COUNTERMEASURES 202
1031#define WLC_GET_PIOMODE 203
1032#define WLC_SET_PIOMODE 204
1033#define WLC_SET_ASSOC_PREFER 205
1034#define WLC_GET_ASSOC_PREFER 206
1035#define WLC_SET_ROAM_PREFER 207
1036#define WLC_GET_ROAM_PREFER 208
1037#define WLC_SET_LED 209
1038#define WLC_GET_LED 210
1039#define WLC_GET_INTERFERENCE_MODE 211
1040#define WLC_SET_INTERFERENCE_MODE 212
1041#define WLC_GET_CHANNEL_QA 213
1042#define WLC_START_CHANNEL_QA 214
1043#define WLC_GET_CHANNEL_SEL 215
1044#define WLC_START_CHANNEL_SEL 216
1045#define WLC_GET_VALID_CHANNELS 217
1046#define WLC_GET_FAKEFRAG 218
1047#define WLC_SET_FAKEFRAG 219
1048#define WLC_GET_PWROUT_PERCENTAGE 220
1049#define WLC_SET_PWROUT_PERCENTAGE 221
1050#define WLC_SET_BAD_FRAME_PREEMPT 222
1051#define WLC_GET_BAD_FRAME_PREEMPT 223
1052#define WLC_SET_LEAP_LIST 224
1053#define WLC_GET_LEAP_LIST 225
1054#define WLC_GET_CWMIN 226
1055#define WLC_SET_CWMIN 227
1056#define WLC_GET_CWMAX 228
1057#define WLC_SET_CWMAX 229
1058#define WLC_GET_WET 230
1059#define WLC_SET_WET 231
1060#define WLC_GET_PUB 232
1061
1062
1063#define WLC_GET_KEY_PRIMARY 235
1064#define WLC_SET_KEY_PRIMARY 236
1065
1066#define WLC_GET_ACI_ARGS 238
1067#define WLC_SET_ACI_ARGS 239
1068#define WLC_UNSET_CALLBACK 240
1069#define WLC_SET_CALLBACK 241
1070#define WLC_GET_RADAR 242
1071#define WLC_SET_RADAR 243
1072#define WLC_SET_SPECT_MANAGMENT 244
1073#define WLC_GET_SPECT_MANAGMENT 245
1074#define WLC_WDS_GET_REMOTE_HWADDR 246
1075#define WLC_WDS_GET_WPA_SUP 247
1076#define WLC_SET_CS_SCAN_TIMER 248
1077#define WLC_GET_CS_SCAN_TIMER 249
1078#define WLC_MEASURE_REQUEST 250
1079#define WLC_INIT 251
1080#define WLC_SEND_QUIET 252
1081#define WLC_KEEPALIVE 253
1082#define WLC_SEND_PWR_CONSTRAINT 254
1083#define WLC_UPGRADE_STATUS 255
1084#define WLC_CURRENT_PWR 256
1085#define WLC_GET_SCAN_PASSIVE_TIME 257
1086#define WLC_SET_SCAN_PASSIVE_TIME 258
1087#define WLC_LEGACY_LINK_BEHAVIOR 259
1088#define WLC_GET_CHANNELS_IN_COUNTRY 260
1089#define WLC_GET_COUNTRY_LIST 261
1090#define WLC_GET_VAR 262
1091#define WLC_SET_VAR 263
1092#define WLC_NVRAM_GET 264
1093#define WLC_NVRAM_SET 265
1094#define WLC_NVRAM_DUMP 266
1095#define WLC_REBOOT 267
1096#define WLC_SET_WSEC_PMK 268
1097#define WLC_GET_AUTH_MODE 269
1098#define WLC_SET_AUTH_MODE 270
1099#define WLC_GET_WAKEENTRY 271
1100#define WLC_SET_WAKEENTRY 272
1101#define WLC_NDCONFIG_ITEM 273
1102#define WLC_NVOTPW 274
1103#define WLC_OTPW 275
1104#define WLC_IOV_BLOCK_GET 276
1105#define WLC_IOV_MODULES_GET 277
1106#define WLC_SOFT_RESET 278
1107#define WLC_GET_ALLOW_MODE 279
1108#define WLC_SET_ALLOW_MODE 280
1109#define WLC_GET_DESIRED_BSSID 281
1110#define WLC_SET_DESIRED_BSSID 282
1111#define WLC_DISASSOC_MYAP 283
1112#define WLC_GET_NBANDS 284
1113#define WLC_GET_BANDSTATES 285
1114#define WLC_GET_WLC_BSS_INFO 286
1115#define WLC_GET_ASSOC_INFO 287
1116#define WLC_GET_OID_PHY 288
1117#define WLC_SET_OID_PHY 289
1118#define WLC_SET_ASSOC_TIME 290
1119#define WLC_GET_DESIRED_SSID 291
1120#define WLC_GET_CHANSPEC 292
1121#define WLC_GET_ASSOC_STATE 293
1122#define WLC_SET_PHY_STATE 294
1123#define WLC_GET_SCAN_PENDING 295
1124#define WLC_GET_SCANREQ_PENDING 296
1125#define WLC_GET_PREV_ROAM_REASON 297
1126#define WLC_SET_PREV_ROAM_REASON 298
1127#define WLC_GET_BANDSTATES_PI 299
1128#define WLC_GET_PHY_STATE 300
1129#define WLC_GET_BSS_WPA_RSN 301
1130#define WLC_GET_BSS_WPA2_RSN 302
1131#define WLC_GET_BSS_BCN_TS 303
1132#define WLC_GET_INT_DISASSOC 304
1133#define WLC_SET_NUM_PEERS 305
1134#define WLC_GET_NUM_BSS 306
1135#define WLC_NPHY_SAMPLE_COLLECT 307
1136#define WLC_UM_PRIV 308
1137#define WLC_GET_CMD 309
1138
1139#define WLC_SET_INTERFERENCE_OVERRIDE_MODE 311
1140#define WLC_GET_INTERFERENCE_OVERRIDE_MODE 312
1141#define WLC_GET_WAI_RESTRICT 313
1142#define WLC_SET_WAI_RESTRICT 314
1143#define WLC_SET_WAI_REKEY 315
1144#define WLC_SET_PEAKRATE 316
1145#define WLC_GET_PEAKRATE 317
1146#define WLC_LAST 318
1147
1148#ifndef EPICTRL_COOKIE
1149#define EPICTRL_COOKIE 0xABADCEDE
1150#endif
1151
1152
1153#define CMN_IOCTL_OFF 0x180
1154
1155
1156
1157
1158#define WL_OID_BASE 0xFFE41420
1159
1160
1161#define OID_WL_GETINSTANCE (WL_OID_BASE + WLC_GET_INSTANCE)
1162#define OID_WL_GET_FORCELINK (WL_OID_BASE + WLC_GET_FORCELINK)
1163#define OID_WL_SET_FORCELINK (WL_OID_BASE + WLC_SET_FORCELINK)
1164#define OID_WL_ENCRYPT_STRENGTH (WL_OID_BASE + WLC_ENCRYPT_STRENGTH)
1165#define OID_WL_DECRYPT_STATUS (WL_OID_BASE + WLC_DECRYPT_STATUS)
1166#define OID_LEGACY_LINK_BEHAVIOR (WL_OID_BASE + WLC_LEGACY_LINK_BEHAVIOR)
1167#define OID_WL_NDCONFIG_ITEM (WL_OID_BASE + WLC_NDCONFIG_ITEM)
1168
1169
1170#define OID_STA_CHANSPEC (WL_OID_BASE + WLC_GET_CHANSPEC)
1171#define OID_STA_NBANDS (WL_OID_BASE + WLC_GET_NBANDS)
1172#define OID_STA_GET_PHY (WL_OID_BASE + WLC_GET_OID_PHY)
1173#define OID_STA_SET_PHY (WL_OID_BASE + WLC_SET_OID_PHY)
1174#define OID_STA_ASSOC_TIME (WL_OID_BASE + WLC_SET_ASSOC_TIME)
1175#define OID_STA_DESIRED_SSID (WL_OID_BASE + WLC_GET_DESIRED_SSID)
1176#define OID_STA_SET_PHY_STATE (WL_OID_BASE + WLC_SET_PHY_STATE)
1177#define OID_STA_SCAN_PENDING (WL_OID_BASE + WLC_GET_SCAN_PENDING)
1178#define OID_STA_SCANREQ_PENDING (WL_OID_BASE + WLC_GET_SCANREQ_PENDING)
1179#define OID_STA_GET_ROAM_REASON (WL_OID_BASE + WLC_GET_PREV_ROAM_REASON)
1180#define OID_STA_SET_ROAM_REASON (WL_OID_BASE + WLC_SET_PREV_ROAM_REASON)
1181#define OID_STA_GET_PHY_STATE (WL_OID_BASE + WLC_GET_PHY_STATE)
1182#define OID_STA_INT_DISASSOC (WL_OID_BASE + WLC_GET_INT_DISASSOC)
1183#define OID_STA_SET_NUM_PEERS (WL_OID_BASE + WLC_SET_NUM_PEERS)
1184#define OID_STA_GET_NUM_BSS (WL_OID_BASE + WLC_GET_NUM_BSS)
1185
1186#define WL_DECRYPT_STATUS_SUCCESS 1
1187#define WL_DECRYPT_STATUS_FAILURE 2
1188#define WL_DECRYPT_STATUS_UNKNOWN 3
1189
1190
1191#define WLC_UPGRADE_SUCCESS 0
1192#define WLC_UPGRADE_PENDING 1
1193
1194#ifdef CONFIG_USBRNDIS_RETAIL
1195
1196typedef struct {
1197 char *name;
1198 void *param;
1199} ndconfig_item_t;
1200#endif
1201
1202
1203
1204#define WL_AUTH_OPEN_SYSTEM 0
1205#define WL_AUTH_SHARED_KEY 1
1206#define WL_AUTH_OPEN_SHARED 2
1207
1208
1209#define WL_RADIO_SW_DISABLE (1<<0)
1210#define WL_RADIO_HW_DISABLE (1<<1)
1211#define WL_RADIO_MPC_DISABLE (1<<2)
1212#define WL_RADIO_COUNTRY_DISABLE (1<<3)
1213
1214#define WL_SPURAVOID_OFF 0
1215#define WL_SPURAVOID_ON1 1
1216#define WL_SPURAVOID_ON2 2
1217
1218
1219#define WL_TXPWR_OVERRIDE (1U<<31)
1220#define WL_TXPWR_NEG (1U<<30)
1221
1222#define WL_PHY_PAVARS_LEN 6
1223
1224#define WL_PHY_PAVARS2_NUM 3
1225#define WL_PHY_PAVAR_VER 1
1226typedef struct wl_pavars2 {
1227 uint16 ver;
1228 uint16 len;
1229 uint16 inuse;
1230 uint16 phy_type;
1231 uint16 bandrange;
1232 uint16 chain;
1233 uint16 inpa[WL_PHY_PAVARS2_NUM];
1234} wl_pavars2_t;
1235
1236typedef struct wl_po {
1237 uint16 phy_type;
1238 uint16 band;
1239 uint16 cckpo;
1240 uint32 ofdmpo;
1241 uint16 mcspo[8];
1242} wl_po_t;
1243
1244
1245#define WLC_TXPWR_MAX (127)
1246
1247
1248#define WL_DIAG_INTERRUPT 1
1249#define WL_DIAG_LOOPBACK 2
1250#define WL_DIAG_MEMORY 3
1251#define WL_DIAG_LED 4
1252#define WL_DIAG_REG 5
1253#define WL_DIAG_SROM 6
1254#define WL_DIAG_DMA 7
1255
1256#define WL_DIAGERR_SUCCESS 0
1257#define WL_DIAGERR_FAIL_TO_RUN 1
1258#define WL_DIAGERR_NOT_SUPPORTED 2
1259#define WL_DIAGERR_INTERRUPT_FAIL 3
1260#define WL_DIAGERR_LOOPBACK_FAIL 4
1261#define WL_DIAGERR_SROM_FAIL 5
1262#define WL_DIAGERR_SROM_BADCRC 6
1263#define WL_DIAGERR_REG_FAIL 7
1264#define WL_DIAGERR_MEMORY_FAIL 8
1265#define WL_DIAGERR_NOMEM 9
1266#define WL_DIAGERR_DMA_FAIL 10
1267
1268#define WL_DIAGERR_MEMORY_TIMEOUT 11
1269#define WL_DIAGERR_MEMORY_BADPATTERN 12
1270
1271
1272#define WLC_BAND_AUTO 0
1273#define WLC_BAND_5G 1
1274#define WLC_BAND_2G 2
1275#define WLC_BAND_ALL 3
1276
1277
1278#define WL_CHAN_FREQ_RANGE_2G 0
1279#define WL_CHAN_FREQ_RANGE_5GL 1
1280#define WL_CHAN_FREQ_RANGE_5GM 2
1281#define WL_CHAN_FREQ_RANGE_5GH 3
1282
1283#define WL_CHAN_FREQ_RANGE_5GLL_VER2 4
1284#define WL_CHAN_FREQ_RANGE_5GLH_VER2 5
1285#define WL_CHAN_FREQ_RANGE_5GML_VER2 6
1286#define WL_CHAN_FREQ_RANGE_5GMH_VER2 7
1287#define WL_CHAN_FREQ_RANGE_5GH_VER2 8
1288
1289#define WL_CHAN_FREQ_RANGE_5GLL_5BAND 4
1290#define WL_CHAN_FREQ_RANGE_5GLH_5BAND 5
1291#define WL_CHAN_FREQ_RANGE_5GML_5BAND 6
1292#define WL_CHAN_FREQ_RANGE_5GMH_5BAND 7
1293#define WL_CHAN_FREQ_RANGE_5GH_5BAND 8
1294
1295
1296#define WLC_PHY_TYPE_A 0
1297#define WLC_PHY_TYPE_B 1
1298#define WLC_PHY_TYPE_G 2
1299#define WLC_PHY_TYPE_N 4
1300#define WLC_PHY_TYPE_LP 5
1301#define WLC_PHY_TYPE_SSN 6
1302#define WLC_PHY_TYPE_HT 7
1303#define WLC_PHY_TYPE_LCN 8
1304#define WLC_PHY_TYPE_NULL 0xf
1305
1306
1307#define WLC_MACMODE_DISABLED 0
1308#define WLC_MACMODE_DENY 1
1309#define WLC_MACMODE_ALLOW 2
1310
1311
1312#define GMODE_LEGACY_B 0
1313#define GMODE_AUTO 1
1314#define GMODE_ONLY 2
1315#define GMODE_B_DEFERRED 3
1316#define GMODE_PERFORMANCE 4
1317#define GMODE_LRS 5
1318#define GMODE_MAX 6
1319
1320
1321#define WLC_PLCP_AUTO -1
1322#define WLC_PLCP_SHORT 0
1323#define WLC_PLCP_LONG 1
1324
1325
1326#define WLC_PROTECTION_AUTO -1
1327#define WLC_PROTECTION_OFF 0
1328#define WLC_PROTECTION_ON 1
1329#define WLC_PROTECTION_MMHDR_ONLY 2
1330#define WLC_PROTECTION_CTS_ONLY 3
1331
1332
1333#define WLC_PROTECTION_CTL_OFF 0
1334#define WLC_PROTECTION_CTL_LOCAL 1
1335#define WLC_PROTECTION_CTL_OVERLAP 2
1336
1337
1338#define WLC_N_PROTECTION_OFF 0
1339#define WLC_N_PROTECTION_OPTIONAL 1
1340#define WLC_N_PROTECTION_20IN40 2
1341#define WLC_N_PROTECTION_MIXEDMODE 3
1342
1343
1344#define WLC_N_PREAMBLE_MIXEDMODE 0
1345#define WLC_N_PREAMBLE_GF 1
1346#define WLC_N_PREAMBLE_GF_BRCM 2
1347
1348
1349#define WLC_N_BW_20ALL 0
1350#define WLC_N_BW_40ALL 1
1351#define WLC_N_BW_20IN2G_40IN5G 2
1352
1353
1354#define WLC_N_TXRX_CHAIN0 0
1355#define WLC_N_TXRX_CHAIN1 1
1356
1357
1358#define WLC_N_SGI_20 0x01
1359#define WLC_N_SGI_40 0x02
1360
1361
1362#define PM_OFF 0
1363#define PM_MAX 1
1364#define PM_FAST 2
1365
1366#define LISTEN_INTERVAL 10
1367
1368#define INTERFERE_OVRRIDE_OFF -1
1369#define INTERFERE_NONE 0
1370#define NON_WLAN 1
1371#define WLAN_MANUAL 2
1372#define WLAN_AUTO 3
1373#define WLAN_AUTO_W_NOISE 4
1374#define AUTO_ACTIVE (1 << 7)
1375
1376typedef struct wl_aci_args {
1377 int enter_aci_thresh;
1378 int exit_aci_thresh;
1379 int usec_spin;
1380 int glitch_delay;
1381 uint16 nphy_adcpwr_enter_thresh;
1382 uint16 nphy_adcpwr_exit_thresh;
1383 uint16 nphy_repeat_ctr;
1384 uint16 nphy_num_samples;
1385 uint16 nphy_undetect_window_sz;
1386 uint16 nphy_b_energy_lo_aci;
1387 uint16 nphy_b_energy_md_aci;
1388 uint16 nphy_b_energy_hi_aci;
1389 uint16 nphy_noise_noassoc_glitch_th_up;
1390 uint16 nphy_noise_noassoc_glitch_th_dn;
1391 uint16 nphy_noise_assoc_glitch_th_up;
1392 uint16 nphy_noise_assoc_glitch_th_dn;
1393 uint16 nphy_noise_assoc_aci_glitch_th_up;
1394 uint16 nphy_noise_assoc_aci_glitch_th_dn;
1395 uint16 nphy_noise_assoc_enter_th;
1396 uint16 nphy_noise_noassoc_enter_th;
1397 uint16 nphy_noise_assoc_rx_glitch_badplcp_enter_th;
1398 uint16 nphy_noise_noassoc_crsidx_incr;
1399 uint16 nphy_noise_assoc_crsidx_incr;
1400 uint16 nphy_noise_crsidx_decr;
1401} wl_aci_args_t;
1402
1403#define TRIGGER_NOW 0
1404#define TRIGGER_CRS 0x01
1405#define TRIGGER_CRSDEASSERT 0x02
1406#define TRIGGER_GOODFCS 0x04
1407#define TRIGGER_BADFCS 0x08
1408#define TRIGGER_BADPLCP 0x10
1409#define TRIGGER_CRSGLITCH 0x20
1410#define WL_ACI_ARGS_LEGACY_LENGTH 16
1411#define WL_SAMPLECOLLECT_T_VERSION 1
1412typedef struct wl_samplecollect_args {
1413
1414 uint8 coll_us;
1415 int cores;
1416
1417 uint16 version;
1418 uint16 length;
1419 uint8 trigger;
1420 uint16 timeout;
1421 uint16 mode;
1422 uint32 pre_dur;
1423 uint32 post_dur;
1424 uint8 gpio_sel;
1425 bool downsamp;
1426 bool be_deaf;
1427 bool agc;
1428 bool filter;
1429} wl_samplecollect_args_t;
1430
1431#define WL_SAMPLEDATA_HEADER_TYPE 1
1432#define WL_SAMPLEDATA_HEADER_SIZE 80
1433#define WL_SAMPLEDATA_TYPE 2
1434#define WL_SAMPLEDATA_SEQ 0xff
1435#define WL_SAMPLEDATA_MORE_DATA 0x100
1436#define WL_SAMPLEDATA_T_VERSION 1
1437
1438#define WL_SAMPLEDATA_T_VERSION_SPEC_AN 2
1439
1440typedef struct wl_sampledata {
1441 uint16 version;
1442 uint16 size;
1443 uint16 tag;
1444 uint16 length;
1445 uint32 flag;
1446} wl_sampledata_t;
1447
1448
1449
1450#define WL_ERROR_VAL 0x00000001
1451#define WL_TRACE_VAL 0x00000002
1452#define WL_PRHDRS_VAL 0x00000004
1453#define WL_PRPKT_VAL 0x00000008
1454#define WL_INFORM_VAL 0x00000010
1455#define WL_TMP_VAL 0x00000020
1456#define WL_OID_VAL 0x00000040
1457#define WL_RATE_VAL 0x00000080
1458#define WL_ASSOC_VAL 0x00000100
1459#define WL_PRUSR_VAL 0x00000200
1460#define WL_PS_VAL 0x00000400
1461#define WL_TXPWR_VAL 0x00000800
1462#define WL_PORT_VAL 0x00001000
1463#define WL_DUAL_VAL 0x00002000
1464#define WL_WSEC_VAL 0x00004000
1465#define WL_WSEC_DUMP_VAL 0x00008000
1466#define WL_LOG_VAL 0x00010000
1467#define WL_NRSSI_VAL 0x00020000
1468#define WL_LOFT_VAL 0x00040000
1469#define WL_REGULATORY_VAL 0x00080000
1470#define WL_PHYCAL_VAL 0x00100000
1471#define WL_RADAR_VAL 0x00200000
1472#define WL_MPC_VAL 0x00400000
1473#define WL_APSTA_VAL 0x00800000
1474#define WL_DFS_VAL 0x01000000
1475#define WL_BA_VAL 0x02000000
1476#define WL_ACI_VAL 0x04000000
1477#define WL_MBSS_VAL 0x04000000
1478#define WL_CAC_VAL 0x08000000
1479#define WL_AMSDU_VAL 0x10000000
1480#define WL_AMPDU_VAL 0x20000000
1481#define WL_FFPLD_VAL 0x40000000
1482
1483
1484#define WL_DPT_VAL 0x00000001
1485#define WL_SCAN_VAL 0x00000002
1486#define WL_WOWL_VAL 0x00000004
1487#define WL_COEX_VAL 0x00000008
1488#define WL_RTDC_VAL 0x00000010
1489#define WL_PROTO_VAL 0x00000020
1490#define WL_BTA_VAL 0x00000040
1491#define WL_CHANINT_VAL 0x00000080
1492#define WL_THERMAL_VAL 0x00000100
1493#define WL_P2P_VAL 0x00000200
1494#define WL_TXRX_VAL 0x00000400
1495#define WL_MCHAN_VAL 0x00000800
1496
1497
1498#define WL_LED_NUMGPIO 16
1499
1500
1501#define WL_LED_OFF 0
1502#define WL_LED_ON 1
1503#define WL_LED_ACTIVITY 2
1504#define WL_LED_RADIO 3
1505#define WL_LED_ARADIO 4
1506#define WL_LED_BRADIO 5
1507#define WL_LED_BGMODE 6
1508#define WL_LED_WI1 7
1509#define WL_LED_WI2 8
1510#define WL_LED_WI3 9
1511#define WL_LED_ASSOC 10
1512#define WL_LED_INACTIVE 11
1513#define WL_LED_ASSOCACT 12
1514#define WL_LED_WI4 13
1515#define WL_LED_WI5 14
1516#define WL_LED_BLINKSLOW 15
1517#define WL_LED_BLINKMED 16
1518#define WL_LED_BLINKFAST 17
1519#define WL_LED_BLINKCUSTOM 18
1520#define WL_LED_BLINKPERIODIC 19
1521#define WL_LED_ASSOC_WITH_SEC 20
1522
1523#define WL_LED_START_OFF 21
1524#define WL_LED_NUMBEHAVIOR 22
1525
1526
1527#define WL_LED_BEH_MASK 0x7f
1528#define WL_LED_AL_MASK 0x80
1529
1530
1531#define WL_NUMCHANNELS 64
1532#define WL_NUMCHANSPECS 100
1533
1534
1535#define WL_WDS_WPA_ROLE_AUTH 0
1536#define WL_WDS_WPA_ROLE_SUP 1
1537#define WL_WDS_WPA_ROLE_AUTO 255
1538
1539
1540#define WL_EVENTING_MASK_LEN 16
1541
1542
1543
1544
1545#define WL_JOIN_PREF_RSSI 1
1546#define WL_JOIN_PREF_WPA 2
1547#define WL_JOIN_PREF_BAND 3
1548#define WL_JOIN_PREF_RSSI_DELTA 4
1549#define WL_JOIN_PREF_TRANS_PREF 5
1550
1551
1552#define WLJP_BAND_ASSOC_PREF 255
1553
1554
1555#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00"
1556
1557struct tsinfo_arg {
1558 uint8 octets[3];
1559};
1560
1561#define NFIFO 6
1562
1563#define WL_CNT_T_VERSION 6
1564
1565typedef struct {
1566 uint16 version;
1567 uint16 length;
1568
1569
1570 uint32 txframe;
1571 uint32 txbyte;
1572 uint32 txretrans;
1573 uint32 txerror;
1574 uint32 txctl;
1575 uint32 txprshort;
1576 uint32 txserr;
1577 uint32 txnobuf;
1578 uint32 txnoassoc;
1579 uint32 txrunt;
1580 uint32 txchit;
1581 uint32 txcmiss;
1582
1583
1584 uint32 txuflo;
1585 uint32 txphyerr;
1586 uint32 txphycrs;
1587
1588
1589 uint32 rxframe;
1590 uint32 rxbyte;
1591 uint32 rxerror;
1592 uint32 rxctl;
1593 uint32 rxnobuf;
1594 uint32 rxnondata;
1595 uint32 rxbadds;
1596 uint32 rxbadcm;
1597 uint32 rxfragerr;
1598 uint32 rxrunt;
1599 uint32 rxgiant;
1600 uint32 rxnoscb;
1601 uint32 rxbadproto;
1602 uint32 rxbadsrcmac;
1603 uint32 rxbadda;
1604 uint32 rxfilter;
1605
1606
1607 uint32 rxoflo;
1608 uint32 rxuflo[NFIFO];
1609
1610 uint32 d11cnt_txrts_off;
1611 uint32 d11cnt_rxcrc_off;
1612 uint32 d11cnt_txnocts_off;
1613
1614
1615 uint32 dmade;
1616 uint32 dmada;
1617 uint32 dmape;
1618 uint32 reset;
1619 uint32 tbtt;
1620 uint32 txdmawar;
1621 uint32 pkt_callback_reg_fail;
1622
1623
1624 uint32 txallfrm;
1625 uint32 txrtsfrm;
1626 uint32 txctsfrm;
1627 uint32 txackfrm;
1628 uint32 txdnlfrm;
1629 uint32 txbcnfrm;
1630 uint32 txfunfl[8];
1631 uint32 txtplunfl;
1632 uint32 txphyerror;
1633 uint32 rxfrmtoolong;
1634 uint32 rxfrmtooshrt;
1635 uint32 rxinvmachdr;
1636 uint32 rxbadfcs;
1637 uint32 rxbadplcp;
1638 uint32 rxcrsglitch;
1639 uint32 rxstrt;
1640 uint32 rxdfrmucastmbss;
1641 uint32 rxmfrmucastmbss;
1642 uint32 rxcfrmucast;
1643 uint32 rxrtsucast;
1644 uint32 rxctsucast;
1645 uint32 rxackucast;
1646 uint32 rxdfrmocast;
1647 uint32 rxmfrmocast;
1648 uint32 rxcfrmocast;
1649 uint32 rxrtsocast;
1650 uint32 rxctsocast;
1651 uint32 rxdfrmmcast;
1652 uint32 rxmfrmmcast;
1653 uint32 rxcfrmmcast;
1654 uint32 rxbeaconmbss;
1655 uint32 rxdfrmucastobss;
1656 uint32 rxbeaconobss;
1657 uint32 rxrsptmout;
1658 uint32 bcntxcancl;
1659 uint32 rxf0ovfl;
1660 uint32 rxf1ovfl;
1661 uint32 rxf2ovfl;
1662 uint32 txsfovfl;
1663 uint32 pmqovfl;
1664 uint32 rxcgprqfrm;
1665 uint32 rxcgprsqovfl;
1666 uint32 txcgprsfail;
1667 uint32 txcgprssuc;
1668 uint32 prs_timeout;
1669 uint32 rxnack;
1670 uint32 frmscons;
1671 uint32 txnack;
1672 uint32 txglitch_nack;
1673 uint32 txburst;
1674
1675
1676 uint32 txfrag;
1677 uint32 txmulti;
1678 uint32 txfail;
1679 uint32 txretry;
1680 uint32 txretrie;
1681 uint32 rxdup;
1682 uint32 txrts;
1683 uint32 txnocts;
1684 uint32 txnoack;
1685 uint32 rxfrag;
1686 uint32 rxmulti;
1687 uint32 rxcrc;
1688 uint32 txfrmsnt;
1689 uint32 rxundec;
1690
1691
1692 uint32 tkipmicfaill;
1693 uint32 tkipcntrmsr;
1694 uint32 tkipreplay;
1695 uint32 ccmpfmterr;
1696 uint32 ccmpreplay;
1697 uint32 ccmpundec;
1698 uint32 fourwayfail;
1699 uint32 wepundec;
1700 uint32 wepicverr;
1701 uint32 decsuccess;
1702 uint32 tkipicverr;
1703 uint32 wepexcluded;
1704
1705 uint32 rxundec_mcst;
1706
1707
1708 uint32 tkipmicfaill_mcst;
1709 uint32 tkipcntrmsr_mcst;
1710 uint32 tkipreplay_mcst;
1711 uint32 ccmpfmterr_mcst;
1712 uint32 ccmpreplay_mcst;
1713 uint32 ccmpundec_mcst;
1714 uint32 fourwayfail_mcst;
1715 uint32 wepundec_mcst;
1716 uint32 wepicverr_mcst;
1717 uint32 decsuccess_mcst;
1718 uint32 tkipicverr_mcst;
1719 uint32 wepexcluded_mcst;
1720
1721 uint32 txchanrej;
1722 uint32 txexptime;
1723 uint32 psmwds;
1724 uint32 phywatchdog;
1725
1726
1727 uint32 prq_entries_handled;
1728 uint32 prq_undirected_entries;
1729 uint32 prq_bad_entries;
1730 uint32 atim_suppress_count;
1731 uint32 bcn_template_not_ready;
1732 uint32 bcn_template_not_ready_done;
1733 uint32 late_tbtt_dpc;
1734
1735
1736 uint32 rx1mbps;
1737 uint32 rx2mbps;
1738 uint32 rx5mbps5;
1739 uint32 rx6mbps;
1740 uint32 rx9mbps;
1741 uint32 rx11mbps;
1742 uint32 rx12mbps;
1743 uint32 rx18mbps;
1744 uint32 rx24mbps;
1745 uint32 rx36mbps;
1746 uint32 rx48mbps;
1747 uint32 rx54mbps;
1748 uint32 rx108mbps;
1749 uint32 rx162mbps;
1750 uint32 rx216mbps;
1751 uint32 rx270mbps;
1752 uint32 rx324mbps;
1753 uint32 rx378mbps;
1754 uint32 rx432mbps;
1755 uint32 rx486mbps;
1756 uint32 rx540mbps;
1757
1758
1759 uint32 pktengrxducast;
1760 uint32 pktengrxdmcast;
1761
1762 uint32 rfdisable;
1763 uint32 bphy_rxcrsglitch;
1764
1765 uint32 txmpdu_sgi;
1766 uint32 rxmpdu_sgi;
1767 uint32 txmpdu_stbc;
1768 uint32 rxmpdu_stbc;
1769} wl_cnt_t;
1770
1771
1772#define WL_WME_CNT_VERSION 1
1773
1774typedef struct {
1775 uint32 packets;
1776 uint32 bytes;
1777} wl_traffic_stats_t;
1778
1779typedef struct {
1780 uint16 version;
1781 uint16 length;
1782
1783 wl_traffic_stats_t tx[AC_COUNT];
1784 wl_traffic_stats_t tx_failed[AC_COUNT];
1785 wl_traffic_stats_t rx[AC_COUNT];
1786 wl_traffic_stats_t rx_failed[AC_COUNT];
1787
1788 wl_traffic_stats_t forward[AC_COUNT];
1789
1790 wl_traffic_stats_t tx_expired[AC_COUNT];
1791
1792} wl_wme_cnt_t;
1793
1794struct wl_msglevel2 {
1795 uint32 low;
1796 uint32 high;
1797};
1798
1799typedef struct wl_mkeep_alive_pkt {
1800 uint16 version;
1801 uint16 length;
1802 uint32 period_msec;
1803 uint16 len_bytes;
1804 uint8 keep_alive_id;
1805 uint8 data[1];
1806} wl_mkeep_alive_pkt_t;
1807
1808#define WL_MKEEP_ALIVE_VERSION 1
1809#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data)
1810#define WL_MKEEP_ALIVE_PRECISION 500
1811
1812#define WLC_ROAM_TRIGGER_DEFAULT 0
1813#define WLC_ROAM_TRIGGER_BANDWIDTH 1
1814#define WLC_ROAM_TRIGGER_DISTANCE 2
1815#define WLC_ROAM_TRIGGER_AUTO 3
1816#define WLC_ROAM_TRIGGER_MAX_VALUE 3
1817
1818
1819#define WPA_AUTH_PFN_ANY 0xffffffff
1820
1821enum {
1822 PFN_LIST_ORDER,
1823 PFN_RSSI
1824};
1825
1826enum {
1827 DISABLE,
1828 ENABLE
1829};
1830
1831enum {
1832 OFF_ADAPT,
1833 SMART_ADAPT,
1834 STRICT_ADAPT,
1835 SLOW_ADAPT
1836};
1837
1838#define SORT_CRITERIA_BIT 0
1839#define AUTO_NET_SWITCH_BIT 1
1840#define ENABLE_BKGRD_SCAN_BIT 2
1841#define IMMEDIATE_SCAN_BIT 3
1842#define AUTO_CONNECT_BIT 4
1843#define ENABLE_BD_SCAN_BIT 5
1844#define ENABLE_ADAPTSCAN_BIT 6
1845#define IMMEDIATE_EVENT_BIT 8
1846
1847#define SORT_CRITERIA_MASK 0x0001
1848#define AUTO_NET_SWITCH_MASK 0x0002
1849#define ENABLE_BKGRD_SCAN_MASK 0x0004
1850#define IMMEDIATE_SCAN_MASK 0x0008
1851#define AUTO_CONNECT_MASK 0x0010
1852#define ENABLE_BD_SCAN_MASK 0x0020
1853#define ENABLE_ADAPTSCAN_MASK 0x00c0
1854#define IMMEDIATE_EVENT_MASK 0x0100
1855
1856#define PFN_VERSION 2
1857#define PFN_SCANRESULT_VERSION 1
1858#define MAX_PFN_LIST_COUNT 16
1859
1860#define PFN_COMPLETE 1
1861#define PFN_INCOMPLETE 0
1862
1863#define DEFAULT_BESTN 2
1864#define DEFAULT_MSCAN 0
1865#define DEFAULT_REPEAT 10
1866#define DEFAULT_EXP 2
1867
1868
1869typedef struct wl_pfn_subnet_info {
1870 struct ether_addr BSSID;
1871 uint8 channel;
1872 uint8 SSID_len;
1873 uint8 SSID[32];
1874} wl_pfn_subnet_info_t;
1875
1876typedef struct wl_pfn_net_info {
1877 wl_pfn_subnet_info_t pfnsubnet;
1878 int16 RSSI;
1879 uint16 timestamp;
1880} wl_pfn_net_info_t;
1881
1882typedef struct wl_pfn_scanresults {
1883 uint32 version;
1884 uint32 status;
1885 uint32 count;
1886 wl_pfn_net_info_t netinfo[1];
1887} wl_pfn_scanresults_t;
1888
1889
1890typedef struct wl_pfn_param {
1891 int32 version;
1892 int32 scan_freq;
1893 int32 lost_network_timeout;
1894 int16 flags;
1895 int16 rssi_margin;
1896 uint8 bestn;
1897 uint8 mscan;
1898 uint8 repeat;
1899 uint8 exp;
1900 int32 slow_freq;
1901} wl_pfn_param_t;
1902
1903typedef struct wl_pfn_bssid {
1904 struct ether_addr macaddr;
1905
1906 uint16 flags;
1907} wl_pfn_bssid_t;
1908#define WL_PFN_SUPPRESSFOUND_MASK 0x08
1909#define WL_PFN_SUPPRESSLOST_MASK 0x10
1910
1911typedef struct wl_pfn_cfg {
1912 uint32 reporttype;
1913 int32 channel_num;
1914 uint16 channel_list[WL_NUMCHANNELS];
1915} wl_pfn_cfg_t;
1916#define WL_PFN_REPORT_ALLNET 0
1917#define WL_PFN_REPORT_SSIDNET 1
1918#define WL_PFN_REPORT_BSSIDNET 2
1919
1920typedef struct wl_pfn {
1921 wlc_ssid_t ssid;
1922 int32 flags;
1923 int32 infra;
1924 int32 auth;
1925 int32 wpa_auth;
1926 int32 wsec;
1927} wl_pfn_t;
1928#define WL_PFN_HIDDEN_BIT 2
1929#define PNO_SCAN_MAX_FW 508*1000
1930#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000
1931#define PNO_SCAN_MIN_FW_SEC 10
1932#define WL_PFN_HIDDEN_MASK 0x4
1933
1934
1935#define TOE_TX_CSUM_OL 0x00000001
1936#define TOE_RX_CSUM_OL 0x00000002
1937
1938
1939#define TOE_ERRTEST_TX_CSUM 0x00000001
1940#define TOE_ERRTEST_RX_CSUM 0x00000002
1941#define TOE_ERRTEST_RX_CSUM2 0x00000004
1942
1943struct toe_ol_stats_t {
1944
1945 uint32 tx_summed;
1946
1947
1948 uint32 tx_iph_fill;
1949 uint32 tx_tcp_fill;
1950 uint32 tx_udp_fill;
1951 uint32 tx_icmp_fill;
1952
1953
1954 uint32 rx_iph_good;
1955 uint32 rx_iph_bad;
1956 uint32 rx_tcp_good;
1957 uint32 rx_tcp_bad;
1958 uint32 rx_udp_good;
1959 uint32 rx_udp_bad;
1960 uint32 rx_icmp_good;
1961 uint32 rx_icmp_bad;
1962
1963
1964 uint32 tx_tcp_errinj;
1965 uint32 tx_udp_errinj;
1966 uint32 tx_icmp_errinj;
1967
1968
1969 uint32 rx_tcp_errinj;
1970 uint32 rx_udp_errinj;
1971 uint32 rx_icmp_errinj;
1972};
1973
1974
1975#define ARP_OL_AGENT 0x00000001
1976#define ARP_OL_SNOOP 0x00000002
1977#define ARP_OL_HOST_AUTO_REPLY 0x00000004
1978#define ARP_OL_PEER_AUTO_REPLY 0x00000008
1979
1980
1981#define ARP_ERRTEST_REPLY_PEER 0x1
1982#define ARP_ERRTEST_REPLY_HOST 0x2
1983
1984#define ARP_MULTIHOMING_MAX 8
1985
1986
1987struct arp_ol_stats_t {
1988 uint32 host_ip_entries;
1989 uint32 host_ip_overflow;
1990
1991 uint32 arp_table_entries;
1992 uint32 arp_table_overflow;
1993
1994 uint32 host_request;
1995 uint32 host_reply;
1996 uint32 host_service;
1997
1998 uint32 peer_request;
1999 uint32 peer_request_drop;
2000 uint32 peer_reply;
2001 uint32 peer_reply_drop;
2002 uint32 peer_service;
2003};
2004
2005
2006
2007
2008typedef struct wl_keep_alive_pkt {
2009 uint32 period_msec;
2010 uint16 len_bytes;
2011 uint8 data[1];
2012} wl_keep_alive_pkt_t;
2013
2014#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data)
2015
2016
2017
2018
2019typedef enum wl_pkt_filter_type {
2020 WL_PKT_FILTER_TYPE_PATTERN_MATCH
2021} wl_pkt_filter_type_t;
2022
2023#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t
2024
2025
2026typedef struct wl_pkt_filter_pattern {
2027 uint32 offset;
2028 uint32 size_bytes;
2029 uint8 mask_and_pattern[1];
2030} wl_pkt_filter_pattern_t;
2031
2032
2033typedef struct wl_pkt_filter {
2034 uint32 id;
2035 uint32 type;
2036 uint32 negate_match;
2037 union {
2038 wl_pkt_filter_pattern_t pattern;
2039 } u;
2040} wl_pkt_filter_t;
2041
2042#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u)
2043#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern)
2044
2045
2046typedef struct wl_pkt_filter_enable {
2047 uint32 id;
2048 uint32 enable;
2049} wl_pkt_filter_enable_t;
2050
2051
2052typedef struct wl_pkt_filter_list {
2053 uint32 num;
2054 wl_pkt_filter_t filter[1];
2055} wl_pkt_filter_list_t;
2056
2057#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter)
2058
2059
2060typedef struct wl_pkt_filter_stats {
2061 uint32 num_pkts_matched;
2062 uint32 num_pkts_forwarded;
2063 uint32 num_pkts_discarded;
2064} wl_pkt_filter_stats_t;
2065
2066
2067typedef struct wl_seq_cmd_ioctl {
2068 uint32 cmd;
2069 uint32 len;
2070} wl_seq_cmd_ioctl_t;
2071
2072#define WL_SEQ_CMD_ALIGN_BYTES 4
2073
2074
2075#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \
2076 (((cmd) == WLC_GET_MAGIC) || \
2077 ((cmd) == WLC_GET_VERSION) || \
2078 ((cmd) == WLC_GET_AP) || \
2079 ((cmd) == WLC_GET_INSTANCE))
2080
2081
2082
2083#define WL_PKTENG_PER_TX_START 0x01
2084#define WL_PKTENG_PER_TX_STOP 0x02
2085#define WL_PKTENG_PER_RX_START 0x04
2086#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05
2087#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06
2088#define WL_PKTENG_PER_RX_STOP 0x08
2089#define WL_PKTENG_PER_MASK 0xff
2090
2091#define WL_PKTENG_SYNCHRONOUS 0x100
2092
2093typedef struct wl_pkteng {
2094 uint32 flags;
2095 uint32 delay;
2096 uint32 nframes;
2097 uint32 length;
2098 uint8 seqno;
2099 struct ether_addr dest;
2100 struct ether_addr src;
2101} wl_pkteng_t;
2102
2103#define NUM_80211b_RATES 4
2104#define NUM_80211ag_RATES 8
2105#define NUM_80211n_RATES 32
2106#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES)
2107typedef struct wl_pkteng_stats {
2108 uint32 lostfrmcnt;
2109 int32 rssi;
2110 int32 snr;
2111 uint16 rxpktcnt[NUM_80211_RATES+1];
2112} wl_pkteng_stats_t;
2113
2114
2115#define WL_WOWL_MAGIC (1 << 0)
2116#define WL_WOWL_NET (1 << 1)
2117#define WL_WOWL_DIS (1 << 2)
2118#define WL_WOWL_RETR (1 << 3)
2119#define WL_WOWL_BCN (1 << 4)
2120#define WL_WOWL_TST (1 << 5)
2121#define WL_WOWL_M1 (1 << 6)
2122#define WL_WOWL_EAPID (1 << 7)
2123#define WL_WOWL_KEYROT (1 << 14)
2124#define WL_WOWL_BCAST (1 << 15)
2125
2126#define MAGIC_PKT_MINLEN 102
2127
2128typedef struct {
2129 uint masksize;
2130 uint offset;
2131 uint patternoffset;
2132 uint patternsize;
2133 ulong id;
2134
2135
2136} wl_wowl_pattern_t;
2137
2138typedef struct {
2139 uint count;
2140 wl_wowl_pattern_t pattern[1];
2141} wl_wowl_pattern_list_t;
2142
2143typedef struct {
2144 uint8 pci_wakeind;
2145 uint16 ucode_wakeind;
2146} wl_wowl_wakeind_t;
2147
2148
2149typedef struct wl_txrate_class {
2150 uint8 init_rate;
2151 uint8 min_rate;
2152 uint8 max_rate;
2153} wl_txrate_class_t;
2154
2155
2156
2157
2158#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 20
2159#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5
2160#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000
2161#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 10
2162#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10
2163#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000
2164#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300
2165#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10
2166#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900
2167#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5
2168#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5
2169#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100
2170#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200
2171#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200
2172#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000
2173#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20
2174#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20
2175#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000
2176#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25
2177#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0
2178#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100
2179
2180
2181typedef struct wl_obss_scan_arg {
2182 int16 passive_dwell;
2183 int16 active_dwell;
2184 int16 bss_widthscan_interval;
2185 int16 passive_total;
2186 int16 active_total;
2187 int16 chanwidth_transition_delay;
2188 int16 activity_threshold;
2189} wl_obss_scan_arg_t;
2190
2191#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t)
2192#define WL_MIN_NUM_OBSS_SCAN_ARG 7
2193
2194#define WL_COEX_INFO_MASK 0x07
2195#define WL_COEX_INFO_REQ 0x01
2196#define WL_COEX_40MHZ_INTOLERANT 0x02
2197#define WL_COEX_WIDTH20 0x04
2198
2199#define WLC_RSSI_INVALID 0
2200
2201#define MAX_RSSI_LEVELS 8
2202
2203
2204typedef struct wl_rssi_event {
2205 uint32 rate_limit_msec;
2206 uint8 num_rssi_levels;
2207 int8 rssi_levels[MAX_RSSI_LEVELS];
2208} wl_rssi_event_t;
2209
2210typedef struct wl_action_obss_coex_req {
2211 uint8 info;
2212 uint8 num;
2213 uint8 ch_list[1];
2214} wl_action_obss_coex_req_t;
2215
2216
2217#define EXTLOG_CUR_VER 0x0100
2218
2219#define MAX_ARGSTR_LEN 18
2220
2221
2222#define LOG_MODULE_COMMON 0x0001
2223#define LOG_MODULE_ASSOC 0x0002
2224#define LOG_MODULE_EVENT 0x0004
2225#define LOG_MODULE_MAX 3
2226
2227
2228#define WL_LOG_LEVEL_DISABLE 0
2229#define WL_LOG_LEVEL_ERR 1
2230#define WL_LOG_LEVEL_WARN 2
2231#define WL_LOG_LEVEL_INFO 3
2232#define WL_LOG_LEVEL_MAX WL_LOG_LEVEL_INFO
2233
2234
2235#define LOG_FLAG_EVENT 1
2236
2237
2238#define LOG_ARGTYPE_NULL 0
2239#define LOG_ARGTYPE_STR 1
2240#define LOG_ARGTYPE_INT 2
2241#define LOG_ARGTYPE_INT_STR 3
2242#define LOG_ARGTYPE_STR_INT 4
2243
2244typedef struct wlc_extlog_cfg {
2245 int max_number;
2246 uint16 module;
2247 uint8 level;
2248 uint8 flag;
2249 uint16 version;
2250} wlc_extlog_cfg_t;
2251
2252typedef struct log_record {
2253 uint32 time;
2254 uint16 module;
2255 uint16 id;
2256 uint8 level;
2257 uint8 sub_unit;
2258 uint8 seq_num;
2259 int32 arg;
2260 char str[MAX_ARGSTR_LEN];
2261} log_record_t;
2262
2263typedef struct wlc_extlog_req {
2264 uint32 from_last;
2265 uint32 num;
2266} wlc_extlog_req_t;
2267
2268typedef struct wlc_extlog_results {
2269 uint16 version;
2270 uint16 record_len;
2271 uint32 num;
2272 log_record_t logs[1];
2273} wlc_extlog_results_t;
2274
2275typedef struct log_idstr {
2276 uint16 id;
2277 uint16 flag;
2278 uint8 arg_type;
2279 const char *fmt_str;
2280} log_idstr_t;
2281
2282#define FMTSTRF_USER 1
2283
2284
2285typedef enum {
2286 FMTSTR_DRIVER_UP_ID = 0,
2287 FMTSTR_DRIVER_DOWN_ID = 1,
2288 FMTSTR_SUSPEND_MAC_FAIL_ID = 2,
2289 FMTSTR_NO_PROGRESS_ID = 3,
2290 FMTSTR_RFDISABLE_ID = 4,
2291 FMTSTR_REG_PRINT_ID = 5,
2292 FMTSTR_EXPTIME_ID = 6,
2293 FMTSTR_JOIN_START_ID = 7,
2294 FMTSTR_JOIN_COMPLETE_ID = 8,
2295 FMTSTR_NO_NETWORKS_ID = 9,
2296 FMTSTR_SECURITY_MISMATCH_ID = 10,
2297 FMTSTR_RATE_MISMATCH_ID = 11,
2298 FMTSTR_AP_PRUNED_ID = 12,
2299 FMTSTR_KEY_INSERTED_ID = 13,
2300 FMTSTR_DEAUTH_ID = 14,
2301 FMTSTR_DISASSOC_ID = 15,
2302 FMTSTR_LINK_UP_ID = 16,
2303 FMTSTR_LINK_DOWN_ID = 17,
2304 FMTSTR_RADIO_HW_OFF_ID = 18,
2305 FMTSTR_RADIO_HW_ON_ID = 19,
2306 FMTSTR_EVENT_DESC_ID = 20,
2307 FMTSTR_PNP_SET_POWER_ID = 21,
2308 FMTSTR_RADIO_SW_OFF_ID = 22,
2309 FMTSTR_RADIO_SW_ON_ID = 23,
2310 FMTSTR_PWD_MISMATCH_ID = 24,
2311 FMTSTR_FATAL_ERROR_ID = 25,
2312 FMTSTR_AUTH_FAIL_ID = 26,
2313 FMTSTR_ASSOC_FAIL_ID = 27,
2314 FMTSTR_IBSS_FAIL_ID = 28,
2315 FMTSTR_EXTAP_FAIL_ID = 29,
2316 FMTSTR_MAX_ID
2317} log_fmtstr_id_t;
2318
2319#ifdef DONGLEOVERLAYS
2320typedef struct {
2321 uint32 flags_idx;
2322 uint32 offset;
2323 uint32 len;
2324
2325} wl_ioctl_overlay_t;
2326
2327#define OVERLAY_IDX_MASK 0x000000ff
2328#define OVERLAY_IDX_SHIFT 0
2329#define OVERLAY_FLAGS_MASK 0xffffff00
2330#define OVERLAY_FLAGS_SHIFT 8
2331
2332#define OVERLAY_FLAG_POSTLOAD 0x100
2333
2334#define OVERLAY_FLAG_DEFER_DL 0x200
2335
2336#define OVERLAY_FLAG_PRESLEEP 0x400
2337
2338#define OVERLAY_DOWNLOAD_CHUNKSIZE 1024
2339#endif
2340
2341
2342#include <packed_section_end.h>
2343
2344
2345#include <packed_section_start.h>
2346
2347#define VNDR_IE_CMD_LEN 4
2348
2349
2350#define VNDR_IE_BEACON_FLAG 0x1
2351#define VNDR_IE_PRBRSP_FLAG 0x2
2352#define VNDR_IE_ASSOCRSP_FLAG 0x4
2353#define VNDR_IE_AUTHRSP_FLAG 0x8
2354#define VNDR_IE_PRBREQ_FLAG 0x10
2355#define VNDR_IE_ASSOCREQ_FLAG 0x20
2356#define VNDR_IE_CUSTOM_FLAG 0x100
2357
2358#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32))
2359
2360typedef BWL_PRE_PACKED_STRUCT struct {
2361 uint32 pktflag;
2362 vndr_ie_t vndr_ie_data;
2363} BWL_POST_PACKED_STRUCT vndr_ie_info_t;
2364
2365typedef BWL_PRE_PACKED_STRUCT struct {
2366 int iecount;
2367 vndr_ie_info_t vndr_ie_list[1];
2368} BWL_POST_PACKED_STRUCT vndr_ie_buf_t;
2369
2370typedef BWL_PRE_PACKED_STRUCT struct {
2371 char cmd[VNDR_IE_CMD_LEN];
2372 vndr_ie_buf_t vndr_ie_buffer;
2373} BWL_POST_PACKED_STRUCT vndr_ie_setbuf_t;
2374
2375
2376
2377typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr {
2378 struct ether_addr staAddr;
2379 uint16 ieLen;
2380} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t;
2381
2382typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data {
2383 sta_prbreq_wps_ie_hdr_t hdr;
2384 uint8 ieData[1];
2385} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t;
2386
2387typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list {
2388 uint32 totLen;
2389 uint8 ieDataList[1];
2390} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t;
2391
2392
2393#ifdef WLMEDIA_TXFAILEVENT
2394typedef BWL_PRE_PACKED_STRUCT struct {
2395 char dest[ETHER_ADDR_LEN];
2396 uint8 prio;
2397 uint8 flags;
2398 uint32 tsf_l;
2399 uint32 tsf_h;
2400 uint16 rates;
2401 uint16 txstatus;
2402} BWL_POST_PACKED_STRUCT txfailinfo_t;
2403#endif
2404
2405#include <packed_section_end.h>
2406
2407
2408#define ASSERTLOG_CUR_VER 0x0100
2409#define MAX_ASSRTSTR_LEN 64
2410
2411typedef struct assert_record {
2412 uint32 time;
2413 uint8 seq_num;
2414 char str[MAX_ASSRTSTR_LEN];
2415} assert_record_t;
2416
2417typedef struct assertlog_results {
2418 uint16 version;
2419 uint16 record_len;
2420 uint32 num;
2421 assert_record_t logs[1];
2422} assertlog_results_t;
2423
2424#define LOGRRC_FIX_LEN 8
2425#define IOBUF_ALLOWED_NUM_OF_LOGREC(type, len) ((len - LOGRRC_FIX_LEN)/sizeof(type))
2426
2427
2428
2429
2430
2431#define CHANIM_DISABLE 0
2432#define CHANIM_DETECT 1
2433#define CHANIM_ACT 2
2434#define CHANIM_MODE_MAX 2
2435
2436
2437#define APCS_IOCTL 1
2438#define APCS_CHANIM 2
2439#define APCS_CSTIMER 3
2440#define APCS_BTA 4
2441
2442
2443#define CHANIM_ACS_RECORD 10
2444
2445
2446typedef struct {
2447 bool valid;
2448 uint8 trigger;
2449 chanspec_t selected_chspc;
2450 uint32 glitch_cnt;
2451 uint8 ccastats;
2452 uint timestamp;
2453} chanim_acs_record_t;
2454
2455typedef struct {
2456 chanim_acs_record_t acs_record[CHANIM_ACS_RECORD];
2457 uint8 count;
2458 uint timestamp;
2459} wl_acs_record_t;
2460
2461
2462
2463#define SMFS_VERSION 1
2464
2465typedef struct wl_smfs_elem {
2466 uint32 count;
2467 uint16 code;
2468} wl_smfs_elem_t;
2469
2470typedef struct wl_smf_stats {
2471 uint32 version;
2472 uint16 length;
2473 uint8 type;
2474 uint8 codetype;
2475 uint32 ignored_cnt;
2476 uint32 malformed_cnt;
2477 uint32 count_total;
2478 wl_smfs_elem_t elem[1];
2479} wl_smf_stats_t;
2480
2481#define WL_SMFSTATS_FIXED_LEN OFFSETOF(wl_smf_stats_t, elem);
2482
2483enum {
2484 SMFS_CODETYPE_SC,
2485 SMFS_CODETYPE_RC
2486};
2487
2488
2489#define SMFS_CODE_MALFORMED 0xFFFE
2490#define SMFS_CODE_IGNORED 0xFFFD
2491
2492typedef enum smfs_type {
2493 SMFS_TYPE_AUTH,
2494 SMFS_TYPE_ASSOC,
2495 SMFS_TYPE_REASSOC,
2496 SMFS_TYPE_DISASSOC_TX,
2497 SMFS_TYPE_DISASSOC_RX,
2498 SMFS_TYPE_DEAUTH_TX,
2499 SMFS_TYPE_DEAUTH_RX,
2500 SMFS_TYPE_MAX
2501} smfs_type_t;
2502
2503#ifdef PHYMON
2504
2505#define PHYMON_VERSION 1
2506
2507typedef struct wl_phycal_core_state {
2508
2509 int16 tx_iqlocal_a;
2510 int16 tx_iqlocal_b;
2511 int8 tx_iqlocal_ci;
2512 int8 tx_iqlocal_cq;
2513 int8 tx_iqlocal_di;
2514 int8 tx_iqlocal_dq;
2515 int8 tx_iqlocal_ei;
2516 int8 tx_iqlocal_eq;
2517 int8 tx_iqlocal_fi;
2518 int8 tx_iqlocal_fq;
2519
2520
2521 int16 rx_iqcal_a;
2522 int16 rx_iqcal_b;
2523
2524 uint8 tx_iqlocal_pwridx;
2525 uint32 papd_epsilon_table[64];
2526 int16 papd_epsilon_offset;
2527 uint8 curr_tx_pwrindex;
2528 int8 idle_tssi;
2529 int8 est_tx_pwr;
2530 int8 est_rx_pwr;
2531 uint16 rx_gaininfo;
2532 uint16 init_gaincode;
2533 int8 estirr_tx;
2534 int8 estirr_rx;
2535
2536} wl_phycal_core_state_t;
2537
2538typedef struct wl_phycal_state {
2539 int version;
2540 int8 num_phy_cores;
2541 int8 curr_temperature;
2542 chanspec_t chspec;
2543 bool aci_state;
2544 uint16 crsminpower;
2545 uint16 crsminpowerl;
2546 uint16 crsminpoweru;
2547 wl_phycal_core_state_t phycal_core[1];
2548} wl_phycal_state_t;
2549
2550#define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core)
2551#endif
2552
2553#ifdef WLP2P
2554
2555typedef struct wl_p2p_disc_st {
2556 uint8 state;
2557 chanspec_t chspec;
2558 uint16 dwell;
2559} wl_p2p_disc_st_t;
2560
2561
2562#define WL_P2P_DISC_ST_SCAN 0
2563#define WL_P2P_DISC_ST_LISTEN 1
2564#define WL_P2P_DISC_ST_SEARCH 2
2565
2566
2567typedef struct wl_p2p_scan {
2568 uint8 type;
2569 uint8 reserved[3];
2570
2571} wl_p2p_scan_t;
2572
2573
2574typedef struct wl_p2p_if {
2575 struct ether_addr addr;
2576 uint8 type;
2577 chanspec_t chspec;
2578} wl_p2p_if_t;
2579
2580
2581#define WL_P2P_IF_CLIENT 0
2582#define WL_P2P_IF_GO 1
2583#define WL_P2P_IF_DYNBCN_GO 2
2584#define WL_P2P_IF_DEV 3
2585
2586
2587typedef struct wl_p2p_ifq {
2588 uint bsscfgidx;
2589 char ifname[BCM_MSG_IFNAME_MAX];
2590} wl_p2p_ifq_t;
2591
2592
2593typedef struct wl_p2p_ops {
2594 uint8 ops;
2595 uint8 ctw;
2596} wl_p2p_ops_t;
2597
2598
2599typedef struct wl_p2p_sched_desc {
2600 uint32 start;
2601 uint32 interval;
2602 uint32 duration;
2603 uint32 count;
2604} wl_p2p_sched_desc_t;
2605
2606
2607#define WL_P2P_SCHED_RSVD 0
2608#define WL_P2P_SCHED_REPEAT 255
2609
2610typedef struct wl_p2p_sched {
2611 uint8 type;
2612 uint8 action;
2613 uint8 option;
2614 wl_p2p_sched_desc_t desc[1];
2615} wl_p2p_sched_t;
2616#define WL_P2P_SCHED_FIXED_LEN 3
2617
2618
2619#define WL_P2P_SCHED_TYPE_ABS 0
2620#define WL_P2P_SCHED_TYPE_REQ_ABS 1
2621
2622
2623#define WL_P2P_SCHED_ACTION_NONE 0
2624#define WL_P2P_SCHED_ACTION_DOZE 1
2625
2626#define WL_P2P_SCHED_ACTION_GOOFF 2
2627
2628#define WL_P2P_SCHED_ACTION_RESET 255
2629
2630
2631#define WL_P2P_SCHED_OPTION_NORMAL 0
2632#define WL_P2P_SCHED_OPTION_BCNPCT 1
2633
2634#define WL_P2P_SCHED_OPTION_TSFOFS 2
2635
2636
2637#define WL_P2P_FEAT_GO_CSA (1 << 0)
2638#define WL_P2P_FEAT_GO_NOLEGACY (1 << 1)
2639#define WL_P2P_FEAT_RESTRICT_DEV_RESP (1 << 2)
2640#endif
2641
2642
2643#define BCM_ACTION_RFAWARE 0x77
2644#define BCM_ACTION_RFAWARE_DCS 0x01
2645
2646
2647
2648#define WL_11N_2x2 1
2649#define WL_11N_3x3 3
2650#define WL_11N_4x4 4
2651
2652
2653#define WLFEATURE_DISABLE_11N 0x00000001
2654#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002
2655#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004
2656#define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008
2657#define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010
2658#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020
2659#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040
2660#define WLFEATURE_DISABLE_11N_GF 0x00000080
2661
2662
2663#define LQ_IDX_LAST 3
2664#define MCS_INDEX_SIZE 33
2665
2666#define LQ_IDX_MIN 0
2667#define LQ_IDX_MAX 1
2668#define LQ_IDX_AVG 2
2669#define LQ_IDX_SUM 2
2670#define LQ_IDX_LAST 3
2671#define LQ_STOP_MONITOR 0
2672#define LQ_START_MONITOR 1
2673
2674#define LINKQUAL_V1 0x01
2675
2676struct wl_lq {
2677 int32 enable;
2678 int32 rssi[LQ_IDX_LAST];
2679 int32 rssicnt;
2680 int32 snr[LQ_IDX_LAST];
2681 uint32 nsamples;
2682 uint8 isvalid;
2683 uint8 version;
2684};
2685
2686typedef struct wl_lq wl_lq_t;
2687typedef struct wl_lq wl_lq_stats_t;
2688
2689typedef struct {
2690 struct ether_addr ea;
2691 uint8 ac_cat;
2692 uint8 num_pkts;
2693} wl_mac_ratehisto_cmd_t;
2694
2695
2696typedef struct {
2697 uint32 rate[WLC_MAXRATE + 1];
2698 uint32 mcs_index[MCS_INDEX_SIZE];
2699 uint32 tsf_timer[2][2];
2700} wl_mac_ratehisto_res_t;
2701
2702#ifdef PROP_TXSTATUS
2703
2704
2705#define WLFC_FLAGS_RSSI_SIGNALS 1
2706
2707
2708#define WLFC_FLAGS_XONXOFF_SIGNALS 2
2709
2710
2711#define WLFC_FLAGS_CREDIT_STATUS_SIGNALS 4
2712
2713#define WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE 8
2714#define WLFC_FLAGS_PSQ_GENERATIONFSM_ENABLE 16
2715#define WLFC_FLAGS_PSQ_ZERO_BUFFER_ENABLE 32
2716#endif
2717
2718#define BTA_STATE_LOG_SZ 64
2719
2720
2721enum {
2722 HCIReset = 1,
2723 HCIReadLocalAMPInfo,
2724 HCIReadLocalAMPASSOC,
2725 HCIWriteRemoteAMPASSOC,
2726 HCICreatePhysicalLink,
2727 HCIAcceptPhysicalLinkRequest,
2728 HCIDisconnectPhysicalLink,
2729 HCICreateLogicalLink,
2730 HCIAcceptLogicalLink,
2731 HCIDisconnectLogicalLink,
2732 HCILogicalLinkCancel,
2733 HCIAmpStateChange,
2734 HCIWriteLogicalLinkAcceptTimeout
2735};
2736
2737typedef struct flush_txfifo {
2738 uint32 txfifobmp;
2739 uint32 hwtxfifoflush;
2740 struct ether_addr ea;
2741} flush_txfifo_t;
2742
2743#define CHANNEL_5G_LOW_START 36
2744#define CHANNEL_5G_MID_START 52
2745#define CHANNEL_5G_HIGH_START 100
2746#define CHANNEL_5G_UPPER_START 149
2747
2748enum {
2749 SPATIAL_MODE_2G_IDX = 0,
2750 SPATIAL_MODE_5G_LOW_IDX,
2751 SPATIAL_MODE_5G_MID_IDX,
2752 SPATIAL_MODE_5G_HIGH_IDX,
2753 SPATIAL_MODE_5G_UPPER_IDX,
2754 SPATIAL_MODE_MAX_IDX
2755};
2756
2757#endif
diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c
new file mode 100644
index 00000000000..1a544378c1e
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/linux_osl.c
@@ -0,0 +1,919 @@
1/*
2 * Linux OS Independent Layer
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: linux_osl.c,v 1.168.2.7 2011-01-27 17:01:13 Exp $
25 */
26
27
28#define LINUX_PORT
29
30#include <typedefs.h>
31#include <bcmendian.h>
32#include <linuxver.h>
33#include <bcmdefs.h>
34#include <osl.h>
35#include <bcmutils.h>
36#include <linux/delay.h>
37#include <pcicfg.h>
38
39#ifdef BCMASSERT_LOG
40#include <bcm_assert_log.h>
41#endif
42
43#include <linux/fs.h>
44
45#define PCI_CFG_RETRY 10
46
47#define OS_HANDLE_MAGIC 0x1234abcd
48#define BCM_MEM_FILENAME_LEN 24
49
50#ifdef DHD_USE_STATIC_BUF
51#define STATIC_BUF_MAX_NUM 16
52#define STATIC_BUF_SIZE (PAGE_SIZE * 2)
53#define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE)
54
55typedef struct bcm_static_buf {
56 struct semaphore static_sem;
57 unsigned char *buf_ptr;
58 unsigned char buf_use[STATIC_BUF_MAX_NUM];
59} bcm_static_buf_t;
60
61static bcm_static_buf_t *bcm_static_buf = 0;
62
63#define STATIC_PKT_MAX_NUM 8
64
65typedef struct bcm_static_pkt {
66 struct sk_buff *skb_4k[STATIC_PKT_MAX_NUM];
67 struct sk_buff *skb_8k[STATIC_PKT_MAX_NUM];
68 struct semaphore osl_pkt_sem;
69 unsigned char pkt_use[STATIC_PKT_MAX_NUM * 2];
70} bcm_static_pkt_t;
71
72static bcm_static_pkt_t *bcm_static_skb = 0;
73#endif
74
75typedef struct bcm_mem_link {
76 struct bcm_mem_link *prev;
77 struct bcm_mem_link *next;
78 uint size;
79 int line;
80 char file[BCM_MEM_FILENAME_LEN];
81} bcm_mem_link_t;
82
83struct osl_info {
84 osl_pubinfo_t pub;
85#ifdef CTFPOOL
86 ctfpool_t *ctfpool;
87#endif
88 uint magic;
89 void *pdev;
90 atomic_t malloced;
91 uint failed;
92 uint bustype;
93 bcm_mem_link_t *dbgmem_list;
94};
95
96
97
98
99uint32 g_assert_type = FALSE;
100
101static int16 linuxbcmerrormap[] =
102{ 0,
103 -EINVAL,
104 -EINVAL,
105 -EINVAL,
106 -EINVAL,
107 -EINVAL,
108 -EINVAL,
109 -EINVAL,
110 -EINVAL,
111 -EINVAL,
112 -EINVAL,
113 -EINVAL,
114 -EINVAL,
115 -EINVAL,
116 -E2BIG,
117 -E2BIG,
118 -EBUSY,
119 -EINVAL,
120 -EINVAL,
121 -EINVAL,
122 -EINVAL,
123 -EFAULT,
124 -ENOMEM,
125 -EOPNOTSUPP,
126 -EMSGSIZE,
127 -EINVAL,
128 -EPERM,
129 -ENOMEM,
130 -EINVAL,
131 -ERANGE,
132 -EINVAL,
133 -EINVAL,
134 -EINVAL,
135 -EINVAL,
136 -EINVAL,
137 -EIO,
138 -ENODEV,
139 -EINVAL,
140 -EIO,
141 -EIO,
142 -ENODEV,
143 -EINVAL,
144 -ENODATA,
145
146
147
148#if BCME_LAST != -42
149#error "You need to add a OS error translation in the linuxbcmerrormap \
150 for new error code defined in bcmutils.h"
151#endif
152};
153
154
155int
156osl_error(int bcmerror)
157{
158 if (bcmerror > 0)
159 bcmerror = 0;
160 else if (bcmerror < BCME_LAST)
161 bcmerror = BCME_ERROR;
162
163
164 return linuxbcmerrormap[-bcmerror];
165}
166
167extern uint8* dhd_os_prealloc(void *osh, int section, int size);
168
169osl_t *
170osl_attach(void *pdev, uint bustype, bool pkttag)
171{
172 osl_t *osh;
173#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
174 gfp_t flags;
175
176 flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
177 osh = kmalloc(sizeof(osl_t), flags);
178#else
179 osh = kmalloc(sizeof(osl_t), GFP_ATOMIC);
180#endif
181 ASSERT(osh);
182
183 bzero(osh, sizeof(osl_t));
184
185
186 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1));
187
188 osh->magic = OS_HANDLE_MAGIC;
189 atomic_set(&osh->malloced, 0);
190 osh->failed = 0;
191 osh->dbgmem_list = NULL;
192 osh->pdev = pdev;
193 osh->pub.pkttag = pkttag;
194 osh->bustype = bustype;
195
196 switch (bustype) {
197 case PCI_BUS:
198 case SI_BUS:
199 case PCMCIA_BUS:
200 osh->pub.mmbus = TRUE;
201 break;
202 case JTAG_BUS:
203 case SDIO_BUS:
204 case USB_BUS:
205 case SPI_BUS:
206 case RPC_BUS:
207 osh->pub.mmbus = FALSE;
208 break;
209 default:
210 ASSERT(FALSE);
211 break;
212 }
213
214#if defined(DHD_USE_STATIC_BUF)
215 if (!bcm_static_buf) {
216 if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(osh, 3, STATIC_BUF_SIZE+
217 STATIC_BUF_TOTAL_LEN))) {
218 printk("can not alloc static buf!\n");
219 }
220 else
221 printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf);
222
223
224 sema_init(&bcm_static_buf->static_sem, 1);
225
226 bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
227 }
228
229 if (!bcm_static_skb) {
230 int i;
231 void *skb_buff_ptr = 0;
232 bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048);
233 skb_buff_ptr = dhd_os_prealloc(osh, 4, 0);
234
235 bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * 16);
236 for (i = 0; i < STATIC_PKT_MAX_NUM * 2; i++)
237 bcm_static_skb->pkt_use[i] = 0;
238
239 sema_init(&bcm_static_skb->osl_pkt_sem, 1);
240 }
241#endif
242
243 return osh;
244}
245
246void
247osl_detach(osl_t *osh)
248{
249 if (osh == NULL)
250 return;
251
252 ASSERT(osh->magic == OS_HANDLE_MAGIC);
253 kfree(osh);
254}
255
256static struct sk_buff *osl_alloc_skb(unsigned int len)
257{
258#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
259 gfp_t flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
260
261 return __dev_alloc_skb(len, flags);
262#else
263 return dev_alloc_skb(len);
264#endif
265}
266
267#ifdef CTFPOOL
268
269void *
270osl_ctfpool_add(osl_t *osh)
271{
272 struct sk_buff *skb;
273
274 if ((osh == NULL) || (osh->ctfpool == NULL))
275 return NULL;
276
277 spin_lock_bh(&osh->ctfpool->lock);
278 ASSERT(osh->ctfpool->curr_obj <= osh->ctfpool->max_obj);
279
280
281 if (osh->ctfpool->curr_obj == osh->ctfpool->max_obj) {
282 spin_unlock_bh(&osh->ctfpool->lock);
283 return NULL;
284 }
285
286
287 skb = osl_alloc_skb(osh->ctfpool->obj_size);
288 if (skb == NULL) {
289 printf("%s: skb alloc of len %d failed\n", __FUNCTION__,
290 osh->ctfpool->obj_size);
291 spin_unlock_bh(&osh->ctfpool->lock);
292 return NULL;
293 }
294
295
296 skb->next = (struct sk_buff *)osh->ctfpool->head;
297 osh->ctfpool->head = skb;
298 osh->ctfpool->fast_frees++;
299 osh->ctfpool->curr_obj++;
300
301
302 CTFPOOLPTR(osh, skb) = (void *)osh->ctfpool;
303
304
305 PKTFAST(osh, skb) = FASTBUF;
306
307 spin_unlock_bh(&osh->ctfpool->lock);
308
309 return skb;
310}
311
312
313void
314osl_ctfpool_replenish(osl_t *osh, uint thresh)
315{
316 if ((osh == NULL) || (osh->ctfpool == NULL))
317 return;
318
319
320 while ((osh->ctfpool->refills > 0) && (thresh--)) {
321 osl_ctfpool_add(osh);
322 osh->ctfpool->refills--;
323 }
324}
325
326
327int32
328osl_ctfpool_init(osl_t *osh, uint numobj, uint size)
329{
330#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
331 gfp_t flags;
332
333 flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
334 osh->ctfpool = kmalloc(sizeof(ctfpool_t), flags);
335#else
336 osh->ctfpool = kmalloc(sizeof(ctfpool_t), GFP_ATOMIC);
337#endif
338 ASSERT(osh->ctfpool);
339 bzero(osh->ctfpool, sizeof(ctfpool_t));
340
341 osh->ctfpool->max_obj = numobj;
342 osh->ctfpool->obj_size = size;
343
344 spin_lock_init(&osh->ctfpool->lock);
345
346 while (numobj--) {
347 if (!osl_ctfpool_add(osh))
348 return -1;
349 osh->ctfpool->fast_frees--;
350 }
351
352 return 0;
353}
354
355
356void
357osl_ctfpool_cleanup(osl_t *osh)
358{
359 struct sk_buff *skb, *nskb;
360
361 if ((osh == NULL) || (osh->ctfpool == NULL))
362 return;
363
364 spin_lock_bh(&osh->ctfpool->lock);
365
366 skb = osh->ctfpool->head;
367
368 while (skb != NULL) {
369 nskb = skb->next;
370 dev_kfree_skb(skb);
371 skb = nskb;
372 osh->ctfpool->curr_obj--;
373 }
374
375 ASSERT(osh->ctfpool->curr_obj == 0);
376 osh->ctfpool->head = NULL;
377 spin_unlock_bh(&osh->ctfpool->lock);
378
379 kfree(osh->ctfpool);
380 osh->ctfpool = NULL;
381}
382
383void
384osl_ctfpool_stats(osl_t *osh, void *b)
385{
386 struct bcmstrbuf *bb;
387
388 if ((osh == NULL) || (osh->ctfpool == NULL))
389 return;
390
391#ifdef DHD_USE_STATIC_BUF
392 if (bcm_static_buf) {
393 bcm_static_buf = 0;
394 }
395 if (bcm_static_skb) {
396 bcm_static_skb = 0;
397 }
398#endif
399
400 bb = b;
401
402 ASSERT((osh != NULL) && (bb != NULL));
403
404 bcm_bprintf(bb, "max_obj %d obj_size %d curr_obj %d refills %d\n",
405 osh->ctfpool->max_obj, osh->ctfpool->obj_size,
406 osh->ctfpool->curr_obj, osh->ctfpool->refills);
407 bcm_bprintf(bb, "fast_allocs %d fast_frees %d slow_allocs %d\n",
408 osh->ctfpool->fast_allocs, osh->ctfpool->fast_frees,
409 osh->ctfpool->slow_allocs);
410}
411
412static inline struct sk_buff *
413osl_pktfastget(osl_t *osh, uint len)
414{
415 struct sk_buff *skb;
416
417
418 if (osh->ctfpool == NULL)
419 return NULL;
420
421 spin_lock_bh(&osh->ctfpool->lock);
422 if (osh->ctfpool->head == NULL) {
423 ASSERT(osh->ctfpool->curr_obj == 0);
424 osh->ctfpool->slow_allocs++;
425 spin_unlock_bh(&osh->ctfpool->lock);
426 return NULL;
427 }
428
429 ASSERT(len <= osh->ctfpool->obj_size);
430
431
432 skb = (struct sk_buff *)osh->ctfpool->head;
433 osh->ctfpool->head = (void *)skb->next;
434
435 osh->ctfpool->fast_allocs++;
436 osh->ctfpool->curr_obj--;
437 ASSERT(CTFPOOLHEAD(osh, skb) == (struct sock *)osh->ctfpool->head);
438 spin_unlock_bh(&osh->ctfpool->lock);
439
440
441 skb->next = skb->prev = NULL;
442 skb->data = skb->head + 16;
443 skb->tail = skb->head + 16;
444
445 skb->len = 0;
446 skb->cloned = 0;
447#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14)
448 skb->list = NULL;
449#endif
450 atomic_set(&skb->users, 1);
451
452 return skb;
453}
454#endif
455
456
457void * BCMFASTPATH
458osl_pktget(osl_t *osh, uint len)
459{
460 struct sk_buff *skb;
461
462#ifdef CTFPOOL
463 skb = osl_pktfastget(osh, len);
464 if ((skb != NULL) || ((skb = osl_alloc_skb(len)) != NULL)) {
465#else
466 if ((skb = osl_alloc_skb(len))) {
467#endif
468 skb_put(skb, len);
469 skb->priority = 0;
470
471 osh->pub.pktalloced++;
472 }
473
474 return ((void*) skb);
475}
476
477#ifdef CTFPOOL
478static inline void
479osl_pktfastfree(osl_t *osh, struct sk_buff *skb)
480{
481 ctfpool_t *ctfpool;
482
483 ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb);
484 ASSERT(ctfpool != NULL);
485
486
487 spin_lock_bh(&ctfpool->lock);
488 skb->next = (struct sk_buff *)ctfpool->head;
489 ctfpool->head = (void *)skb;
490
491 ctfpool->fast_frees++;
492 ctfpool->curr_obj++;
493
494 ASSERT(ctfpool->curr_obj <= ctfpool->max_obj);
495 spin_unlock_bh(&ctfpool->lock);
496
497#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
498 skb->tstamp.tv.sec = 0;
499#else
500 skb->stamp.tv_sec = 0;
501#endif
502
503
504 skb->dev = NULL;
505 skb->dst = NULL;
506 memset(skb->cb, 0, sizeof(skb->cb));
507 skb->ip_summed = 0;
508 skb->destructor = NULL;
509}
510#endif
511
512
513void BCMFASTPATH
514osl_pktfree(osl_t *osh, void *p, bool send)
515{
516 struct sk_buff *skb, *nskb;
517
518 skb = (struct sk_buff*) p;
519
520 if (send && osh->pub.tx_fn)
521 osh->pub.tx_fn(osh->pub.tx_ctx, p, 0);
522
523
524 while (skb) {
525 nskb = skb->next;
526 skb->next = NULL;
527
528
529#ifdef CTFPOOL
530 if (PKTISFAST(osh, skb))
531 osl_pktfastfree(osh, skb);
532 else {
533#else
534 {
535#endif
536
537 if (skb->destructor)
538
539 dev_kfree_skb_any(skb);
540 else
541
542 dev_kfree_skb(skb);
543 }
544
545 osh->pub.pktalloced--;
546
547 skb = nskb;
548 }
549}
550
551#ifdef DHD_USE_STATIC_BUF
552void *
553osl_pktget_static(osl_t *osh, uint len)
554{
555 int i;
556 struct sk_buff *skb;
557
558 if (len > (PAGE_SIZE * 2)) {
559 printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len);
560 return osl_pktget(osh, len);
561 }
562
563 down(&bcm_static_skb->osl_pkt_sem);
564
565 if (len <= PAGE_SIZE) {
566 for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
567 if (bcm_static_skb->pkt_use[i] == 0)
568 break;
569 }
570
571 if (i != STATIC_PKT_MAX_NUM) {
572 bcm_static_skb->pkt_use[i] = 1;
573 up(&bcm_static_skb->osl_pkt_sem);
574 skb = bcm_static_skb->skb_4k[i];
575 skb->tail = skb->data + len;
576 skb->len = len;
577 return skb;
578 }
579 }
580
581
582 for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
583 if (bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] == 0)
584 break;
585 }
586
587 if (i != STATIC_PKT_MAX_NUM) {
588 bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] = 1;
589 up(&bcm_static_skb->osl_pkt_sem);
590 skb = bcm_static_skb->skb_8k[i];
591 skb->tail = skb->data + len;
592 skb->len = len;
593 return skb;
594 }
595
596 up(&bcm_static_skb->osl_pkt_sem);
597 printk("%s: all static pkt in use!\n", __FUNCTION__);
598 return osl_pktget(osh, len);
599}
600
601void
602osl_pktfree_static(osl_t *osh, void *p, bool send)
603{
604 int i;
605
606 for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
607 if (p == bcm_static_skb->skb_4k[i]) {
608 down(&bcm_static_skb->osl_pkt_sem);
609 bcm_static_skb->pkt_use[i] = 0;
610 up(&bcm_static_skb->osl_pkt_sem);
611 return;
612 }
613 }
614
615 for (i = 0; i < STATIC_PKT_MAX_NUM; i++) {
616 if (p == bcm_static_skb->skb_8k[i]) {
617 down(&bcm_static_skb->osl_pkt_sem);
618 bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0;
619 up(&bcm_static_skb->osl_pkt_sem);
620 return;
621 }
622 }
623
624 return osl_pktfree(osh, p, send);
625}
626#endif
627
628uint32
629osl_pci_read_config(osl_t *osh, uint offset, uint size)
630{
631 uint val = 0;
632 uint retry = PCI_CFG_RETRY;
633
634 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
635
636
637 ASSERT(size == 4);
638
639 do {
640 pci_read_config_dword(osh->pdev, offset, &val);
641 if (val != 0xffffffff)
642 break;
643 } while (retry--);
644
645
646 return (val);
647}
648
649void
650osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
651{
652 uint retry = PCI_CFG_RETRY;
653
654 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
655
656
657 ASSERT(size == 4);
658
659 do {
660 pci_write_config_dword(osh->pdev, offset, val);
661 if (offset != PCI_BAR0_WIN)
662 break;
663 if (osl_pci_read_config(osh, offset, size) == val)
664 break;
665 } while (retry--);
666
667}
668
669
670uint
671osl_pci_bus(osl_t *osh)
672{
673 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
674
675 return ((struct pci_dev *)osh->pdev)->bus->number;
676}
677
678
679uint
680osl_pci_slot(osl_t *osh)
681{
682 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
683
684 return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
685}
686
687static void
688osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write)
689{
690}
691
692void
693osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size)
694{
695 osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE);
696}
697
698void
699osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size)
700{
701 osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE);
702}
703
704void *
705osl_malloc(osl_t *osh, uint size)
706{
707 void *addr;
708#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
709 gfp_t flags;
710
711
712 if (osh)
713 ASSERT(osh->magic == OS_HANDLE_MAGIC);
714
715 flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
716 if ((addr = kmalloc(size, flags)) == NULL) {
717#else
718 if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) {
719#endif
720 if (osh)
721 osh->failed++;
722 return (NULL);
723 }
724 if (osh)
725 atomic_add(size, &osh->malloced);
726
727 return (addr);
728}
729
730void
731osl_mfree(osl_t *osh, void *addr, uint size)
732{
733 if (osh) {
734 ASSERT(osh->magic == OS_HANDLE_MAGIC);
735 atomic_sub(size, &osh->malloced);
736 }
737 kfree(addr);
738}
739
740uint
741osl_malloced(osl_t *osh)
742{
743 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
744 return (atomic_read(&osh->malloced));
745}
746
747uint
748osl_malloc_failed(osl_t *osh)
749{
750 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
751 return (osh->failed);
752}
753
754
755
756uint
757osl_dma_consistent_align(void)
758{
759 return (PAGE_SIZE);
760}
761
762void*
763osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align_bits, uint *alloced, ulong *pap)
764{
765 uint16 align = (1 << align_bits);
766 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
767
768 if (!ISALIGNED(DMA_CONSISTENT_ALIGN, align))
769 size += align;
770 *alloced = size;
771
772 return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap));
773}
774
775void
776osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa)
777{
778 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
779
780 pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa);
781}
782
783uint BCMFASTPATH
784osl_dma_map(osl_t *osh, void *va, uint size, int direction)
785{
786 int dir;
787
788 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
789 dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
790 return (pci_map_single(osh->pdev, va, size, dir));
791}
792
793void BCMFASTPATH
794osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
795{
796 int dir;
797
798 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
799 dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
800 pci_unmap_single(osh->pdev, (uint32)pa, size, dir);
801}
802
803#if defined(BCMASSERT_LOG)
804void
805osl_assert(char *exp, char *file, int line)
806{
807 char tempbuf[256];
808 char *basename;
809
810 basename = strrchr(file, '/');
811
812 if (basename)
813 basename++;
814
815 if (!basename)
816 basename = file;
817
818#ifdef BCMASSERT_LOG
819 snprintf(tempbuf, 64, "\"%s\": file \"%s\", line %d\n",
820 exp, basename, line);
821
822 bcm_assert_log(tempbuf);
823#endif
824
825
826}
827#endif
828
829void
830osl_delay(uint usec)
831{
832 uint d;
833
834 while (usec > 0) {
835 d = MIN(usec, 1000);
836 udelay(d);
837 usec -= d;
838 }
839}
840
841
842
843void *
844osl_pktdup(osl_t *osh, void *skb)
845{
846 void * p;
847#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
848 gfp_t flags;
849
850 flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
851 if ((p = skb_clone((struct sk_buff *)skb, flags)) == NULL)
852#else
853 if ((p = skb_clone((struct sk_buff*)skb, GFP_ATOMIC)) == NULL)
854#endif
855 return NULL;
856
857#ifdef CTFPOOL
858 if (PKTISFAST(osh, skb)) {
859 ctfpool_t *ctfpool;
860
861
862 ctfpool = (ctfpool_t *)CTFPOOLPTR(osh, skb);
863 ASSERT(ctfpool != NULL);
864 PKTCLRFAST(osh, p);
865 PKTCLRFAST(osh, skb);
866 ctfpool->refills++;
867 }
868#endif
869
870
871 if (osh->pub.pkttag)
872 bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ);
873
874
875 osh->pub.pktalloced++;
876 return (p);
877}
878
879
880
881
882
883
884
885void *
886osl_os_open_image(char *filename)
887{
888 struct file *fp;
889
890 fp = filp_open(filename, O_RDONLY, 0);
891
892 if (IS_ERR(fp))
893 fp = NULL;
894
895 return fp;
896}
897
898int
899osl_os_get_image_block(char *buf, int len, void *image)
900{
901 struct file *fp = (struct file *)image;
902 int rdlen;
903
904 if (!image)
905 return 0;
906
907 rdlen = kernel_read(fp, fp->f_pos, buf, len);
908 if (rdlen > 0)
909 fp->f_pos += rdlen;
910
911 return rdlen;
912}
913
914void
915osl_os_close_image(void *image)
916{
917 if (image)
918 filp_close((struct file *)image, NULL);
919}
diff --git a/drivers/net/wireless/bcmdhd/sbutils.c b/drivers/net/wireless/bcmdhd/sbutils.c
new file mode 100644
index 00000000000..02d1bc0a79d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/sbutils.c
@@ -0,0 +1,992 @@
1/*
2 * Misc utility routines for accessing chip-specific features
3 * of the SiliconBackplane-based Broadcom chips.
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: sbutils.c,v 1.687.2.1 2010-11-29 20:21:56 Exp $
26 */
27
28#include <typedefs.h>
29#include <bcmdefs.h>
30#include <osl.h>
31#include <bcmutils.h>
32#include <siutils.h>
33#include <bcmdevs.h>
34#include <hndsoc.h>
35#include <sbchipc.h>
36#include <pcicfg.h>
37#include <sbpcmcia.h>
38
39#include "siutils_priv.h"
40
41
42/* local prototypes */
43static uint _sb_coreidx(si_info_t *sii, uint32 sba);
44static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba,
45 uint ncores);
46static uint32 _sb_coresba(si_info_t *sii);
47static void *_sb_setcoreidx(si_info_t *sii, uint coreidx);
48
49#define SET_SBREG(sii, r, mask, val) \
50 W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val)))
51#define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF)
52
53/* sonicsrev */
54#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT)
55#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT)
56
57#define R_SBREG(sii, sbr) sb_read_sbreg((sii), (sbr))
58#define W_SBREG(sii, sbr, v) sb_write_sbreg((sii), (sbr), (v))
59#define AND_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v)))
60#define OR_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v)))
61
62static uint32
63sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr)
64{
65 uint8 tmp;
66 uint32 val, intr_val = 0;
67
68
69 /*
70 * compact flash only has 11 bits address, while we needs 12 bits address.
71 * MEM_SEG will be OR'd with other 11 bits address in hardware,
72 * so we program MEM_SEG with 12th bit when necessary(access sb regsiters).
73 * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special
74 */
75 if (PCMCIA(sii)) {
76 INTR_OFF(sii, intr_val);
77 tmp = 1;
78 OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1);
79 sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */
80 }
81
82 val = R_REG(sii->osh, sbr);
83
84 if (PCMCIA(sii)) {
85 tmp = 0;
86 OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1);
87 INTR_RESTORE(sii, intr_val);
88 }
89
90 return (val);
91}
92
93static void
94sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v)
95{
96 uint8 tmp;
97 volatile uint32 dummy;
98 uint32 intr_val = 0;
99
100
101 /*
102 * compact flash only has 11 bits address, while we needs 12 bits address.
103 * MEM_SEG will be OR'd with other 11 bits address in hardware,
104 * so we program MEM_SEG with 12th bit when necessary(access sb regsiters).
105 * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special
106 */
107 if (PCMCIA(sii)) {
108 INTR_OFF(sii, intr_val);
109 tmp = 1;
110 OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1);
111 sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */
112 }
113
114 if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) {
115 dummy = R_REG(sii->osh, sbr);
116 W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff));
117 dummy = R_REG(sii->osh, sbr);
118 W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff));
119 } else
120 W_REG(sii->osh, sbr, v);
121
122 if (PCMCIA(sii)) {
123 tmp = 0;
124 OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1);
125 INTR_RESTORE(sii, intr_val);
126 }
127}
128
129uint
130sb_coreid(si_t *sih)
131{
132 si_info_t *sii;
133 sbconfig_t *sb;
134
135 sii = SI_INFO(sih);
136 sb = REGS2SB(sii->curmap);
137
138 return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT);
139}
140
141uint
142sb_intflag(si_t *sih)
143{
144 si_info_t *sii;
145 void *corereg;
146 sbconfig_t *sb;
147 uint origidx, intflag, intr_val = 0;
148
149 sii = SI_INFO(sih);
150
151 INTR_OFF(sii, intr_val);
152 origidx = si_coreidx(sih);
153 corereg = si_setcore(sih, CC_CORE_ID, 0);
154 ASSERT(corereg != NULL);
155 sb = REGS2SB(corereg);
156 intflag = R_SBREG(sii, &sb->sbflagst);
157 sb_setcoreidx(sih, origidx);
158 INTR_RESTORE(sii, intr_val);
159
160 return intflag;
161}
162
163uint
164sb_flag(si_t *sih)
165{
166 si_info_t *sii;
167 sbconfig_t *sb;
168
169 sii = SI_INFO(sih);
170 sb = REGS2SB(sii->curmap);
171
172 return R_SBREG(sii, &sb->sbtpsflag) & SBTPS_NUM0_MASK;
173}
174
175void
176sb_setint(si_t *sih, int siflag)
177{
178 si_info_t *sii;
179 sbconfig_t *sb;
180 uint32 vec;
181
182 sii = SI_INFO(sih);
183 sb = REGS2SB(sii->curmap);
184
185 if (siflag == -1)
186 vec = 0;
187 else
188 vec = 1 << siflag;
189 W_SBREG(sii, &sb->sbintvec, vec);
190}
191
192/* return core index of the core with address 'sba' */
193static uint
194_sb_coreidx(si_info_t *sii, uint32 sba)
195{
196 uint i;
197
198 for (i = 0; i < sii->numcores; i ++)
199 if (sba == sii->coresba[i])
200 return i;
201 return BADIDX;
202}
203
204/* return core address of the current core */
205static uint32
206_sb_coresba(si_info_t *sii)
207{
208 uint32 sbaddr;
209
210
211 switch (BUSTYPE(sii->pub.bustype)) {
212 case SI_BUS: {
213 sbconfig_t *sb = REGS2SB(sii->curmap);
214 sbaddr = sb_base(R_SBREG(sii, &sb->sbadmatch0));
215 break;
216 }
217
218 case PCI_BUS:
219 sbaddr = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32));
220 break;
221
222 case PCMCIA_BUS: {
223 uint8 tmp = 0;
224 OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1);
225 sbaddr = (uint32)tmp << 12;
226 OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1);
227 sbaddr |= (uint32)tmp << 16;
228 OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1);
229 sbaddr |= (uint32)tmp << 24;
230 break;
231 }
232
233 case SPI_BUS:
234 case SDIO_BUS:
235 sbaddr = (uint32)(uintptr)sii->curmap;
236 break;
237
238
239 default:
240 sbaddr = BADCOREADDR;
241 break;
242 }
243
244 return sbaddr;
245}
246
247uint
248sb_corevendor(si_t *sih)
249{
250 si_info_t *sii;
251 sbconfig_t *sb;
252
253 sii = SI_INFO(sih);
254 sb = REGS2SB(sii->curmap);
255
256 return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT);
257}
258
259uint
260sb_corerev(si_t *sih)
261{
262 si_info_t *sii;
263 sbconfig_t *sb;
264 uint sbidh;
265
266 sii = SI_INFO(sih);
267 sb = REGS2SB(sii->curmap);
268 sbidh = R_SBREG(sii, &sb->sbidhigh);
269
270 return (SBCOREREV(sbidh));
271}
272
273/* set core-specific control flags */
274void
275sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
276{
277 si_info_t *sii;
278 sbconfig_t *sb;
279 uint32 w;
280
281 sii = SI_INFO(sih);
282 sb = REGS2SB(sii->curmap);
283
284 ASSERT((val & ~mask) == 0);
285
286 /* mask and set */
287 w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) |
288 (val << SBTML_SICF_SHIFT);
289 W_SBREG(sii, &sb->sbtmstatelow, w);
290}
291
292/* set/clear core-specific control flags */
293uint32
294sb_core_cflags(si_t *sih, uint32 mask, uint32 val)
295{
296 si_info_t *sii;
297 sbconfig_t *sb;
298 uint32 w;
299
300 sii = SI_INFO(sih);
301 sb = REGS2SB(sii->curmap);
302
303 ASSERT((val & ~mask) == 0);
304
305 /* mask and set */
306 if (mask || val) {
307 w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) |
308 (val << SBTML_SICF_SHIFT);
309 W_SBREG(sii, &sb->sbtmstatelow, w);
310 }
311
312 /* return the new value
313 * for write operation, the following readback ensures the completion of write opration.
314 */
315 return (R_SBREG(sii, &sb->sbtmstatelow) >> SBTML_SICF_SHIFT);
316}
317
318/* set/clear core-specific status flags */
319uint32
320sb_core_sflags(si_t *sih, uint32 mask, uint32 val)
321{
322 si_info_t *sii;
323 sbconfig_t *sb;
324 uint32 w;
325
326 sii = SI_INFO(sih);
327 sb = REGS2SB(sii->curmap);
328
329 ASSERT((val & ~mask) == 0);
330 ASSERT((mask & ~SISF_CORE_BITS) == 0);
331
332 /* mask and set */
333 if (mask || val) {
334 w = (R_SBREG(sii, &sb->sbtmstatehigh) & ~(mask << SBTMH_SISF_SHIFT)) |
335 (val << SBTMH_SISF_SHIFT);
336 W_SBREG(sii, &sb->sbtmstatehigh, w);
337 }
338
339 /* return the new value */
340 return (R_SBREG(sii, &sb->sbtmstatehigh) >> SBTMH_SISF_SHIFT);
341}
342
343bool
344sb_iscoreup(si_t *sih)
345{
346 si_info_t *sii;
347 sbconfig_t *sb;
348
349 sii = SI_INFO(sih);
350 sb = REGS2SB(sii->curmap);
351
352 return ((R_SBREG(sii, &sb->sbtmstatelow) &
353 (SBTML_RESET | SBTML_REJ_MASK | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) ==
354 (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
355}
356
357/*
358 * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation,
359 * switch back to the original core, and return the new value.
360 *
361 * When using the silicon backplane, no fidleing with interrupts or core switches are needed.
362 *
363 * Also, when using pci/pcie, we can optimize away the core switching for pci registers
364 * and (on newer pci cores) chipcommon registers.
365 */
366uint
367sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
368{
369 uint origidx = 0;
370 uint32 *r = NULL;
371 uint w;
372 uint intr_val = 0;
373 bool fast = FALSE;
374 si_info_t *sii;
375
376 sii = SI_INFO(sih);
377
378 ASSERT(GOODIDX(coreidx));
379 ASSERT(regoff < SI_CORE_SIZE);
380 ASSERT((val & ~mask) == 0);
381
382 if (coreidx >= SI_MAXCORES)
383 return 0;
384
385 if (BUSTYPE(sii->pub.bustype) == SI_BUS) {
386 /* If internal bus, we can always get at everything */
387 fast = TRUE;
388 /* map if does not exist */
389 if (!sii->regs[coreidx]) {
390 sii->regs[coreidx] = REG_MAP(sii->coresba[coreidx],
391 SI_CORE_SIZE);
392 ASSERT(GOODREGS(sii->regs[coreidx]));
393 }
394 r = (uint32 *)((uchar *)sii->regs[coreidx] + regoff);
395 } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) {
396 /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
397
398 if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
399 /* Chipc registers are mapped at 12KB */
400
401 fast = TRUE;
402 r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff);
403 } else if (sii->pub.buscoreidx == coreidx) {
404 /* pci registers are at either in the last 2KB of an 8KB window
405 * or, in pcie and pci rev 13 at 8KB
406 */
407 fast = TRUE;
408 if (SI_FAST(sii))
409 r = (uint32 *)((char *)sii->curmap +
410 PCI_16KB0_PCIREGS_OFFSET + regoff);
411 else
412 r = (uint32 *)((char *)sii->curmap +
413 ((regoff >= SBCONFIGOFF) ?
414 PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
415 regoff);
416 }
417 }
418
419 if (!fast) {
420 INTR_OFF(sii, intr_val);
421
422 /* save current core index */
423 origidx = si_coreidx(&sii->pub);
424
425 /* switch core */
426 r = (uint32*) ((uchar*)sb_setcoreidx(&sii->pub, coreidx) + regoff);
427 }
428 ASSERT(r != NULL);
429
430 /* mask and set */
431 if (mask || val) {
432 if (regoff >= SBCONFIGOFF) {
433 w = (R_SBREG(sii, r) & ~mask) | val;
434 W_SBREG(sii, r, w);
435 } else {
436 w = (R_REG(sii->osh, r) & ~mask) | val;
437 W_REG(sii->osh, r, w);
438 }
439 }
440
441 /* readback */
442 if (regoff >= SBCONFIGOFF)
443 w = R_SBREG(sii, r);
444 else {
445 if ((CHIPID(sii->pub.chip) == BCM5354_CHIP_ID) &&
446 (coreidx == SI_CC_IDX) &&
447 (regoff == OFFSETOF(chipcregs_t, watchdog))) {
448 w = val;
449 } else
450 w = R_REG(sii->osh, r);
451 }
452
453 if (!fast) {
454 /* restore core index */
455 if (origidx != coreidx)
456 sb_setcoreidx(&sii->pub, origidx);
457
458 INTR_RESTORE(sii, intr_val);
459 }
460
461 return (w);
462}
463
464/* Scan the enumeration space to find all cores starting from the given
465 * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba'
466 * is the default core address at chip POR time and 'regs' is the virtual
467 * address that the default core is mapped at. 'ncores' is the number of
468 * cores expected on bus 'sbba'. It returns the total number of cores
469 * starting from bus 'sbba', inclusive.
470 */
471#define SB_MAXBUSES 2
472static uint
473_sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint numcores)
474{
475 uint next;
476 uint ncc = 0;
477 uint i;
478
479 if (bus >= SB_MAXBUSES) {
480 SI_ERROR(("_sb_scan: bus 0x%08x at level %d is too deep to scan\n", sbba, bus));
481 return 0;
482 }
483 SI_MSG(("_sb_scan: scan bus 0x%08x assume %u cores\n", sbba, numcores));
484
485 /* Scan all cores on the bus starting from core 0.
486 * Core addresses must be contiguous on each bus.
487 */
488 for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) {
489 sii->coresba[next] = sbba + (i * SI_CORE_SIZE);
490
491 /* keep and reuse the initial register mapping */
492 if ((BUSTYPE(sii->pub.bustype) == SI_BUS) && (sii->coresba[next] == sba)) {
493 SI_VMSG(("_sb_scan: reuse mapped regs %p for core %u\n", regs, next));
494 sii->regs[next] = regs;
495 }
496
497 /* change core to 'next' and read its coreid */
498 sii->curmap = _sb_setcoreidx(sii, next);
499 sii->curidx = next;
500
501 sii->coreid[next] = sb_coreid(&sii->pub);
502
503 /* core specific processing... */
504 /* chipc provides # cores */
505 if (sii->coreid[next] == CC_CORE_ID) {
506 chipcregs_t *cc = (chipcregs_t *)sii->curmap;
507 uint32 ccrev = sb_corerev(&sii->pub);
508
509 /* determine numcores - this is the total # cores in the chip */
510 if (((ccrev == 4) || (ccrev >= 6)))
511 numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >>
512 CID_CC_SHIFT;
513 else {
514 /* Older chips */
515 uint chip = CHIPID(sii->pub.chip);
516
517 if (chip == BCM4306_CHIP_ID) /* < 4306c0 */
518 numcores = 6;
519 else if (chip == BCM4704_CHIP_ID)
520 numcores = 9;
521 else if (chip == BCM5365_CHIP_ID)
522 numcores = 7;
523 else {
524 SI_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n",
525 chip));
526 ASSERT(0);
527 numcores = 1;
528 }
529 }
530 SI_VMSG(("_sb_scan: there are %u cores in the chip %s\n", numcores,
531 sii->pub.issim ? "QT" : ""));
532 }
533 /* scan bridged SB(s) and add results to the end of the list */
534 else if (sii->coreid[next] == OCP_CORE_ID) {
535 sbconfig_t *sb = REGS2SB(sii->curmap);
536 uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1);
537 uint nsbcc;
538
539 sii->numcores = next + 1;
540
541 if ((nsbba & 0xfff00000) != SI_ENUM_BASE)
542 continue;
543 nsbba &= 0xfffff000;
544 if (_sb_coreidx(sii, nsbba) != BADIDX)
545 continue;
546
547 nsbcc = (R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >> 16;
548 nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc);
549 if (sbba == SI_ENUM_BASE)
550 numcores -= nsbcc;
551 ncc += nsbcc;
552 }
553 }
554
555 SI_MSG(("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba));
556
557 sii->numcores = i + ncc;
558 return sii->numcores;
559}
560
561/* scan the sb enumerated space to identify all cores */
562void
563sb_scan(si_t *sih, void *regs, uint devid)
564{
565 si_info_t *sii;
566 uint32 origsba;
567 sbconfig_t *sb;
568
569 sii = SI_INFO(sih);
570 sb = REGS2SB(sii->curmap);
571
572 sii->pub.socirev = (R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT;
573
574 /* Save the current core info and validate it later till we know
575 * for sure what is good and what is bad.
576 */
577 origsba = _sb_coresba(sii);
578
579 /* scan all SB(s) starting from SI_ENUM_BASE */
580 sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1);
581}
582
583/*
584 * This function changes logical "focus" to the indicated core;
585 * must be called with interrupts off.
586 * Moreover, callers should keep interrupts off during switching out of and back to d11 core
587 */
588void *
589sb_setcoreidx(si_t *sih, uint coreidx)
590{
591 si_info_t *sii;
592
593 sii = SI_INFO(sih);
594
595 if (coreidx >= sii->numcores)
596 return (NULL);
597
598 /*
599 * If the user has provided an interrupt mask enabled function,
600 * then assert interrupts are disabled before switching the core.
601 */
602 ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg));
603
604 sii->curmap = _sb_setcoreidx(sii, coreidx);
605 sii->curidx = coreidx;
606
607 return (sii->curmap);
608}
609
610/* This function changes the logical "focus" to the indicated core.
611 * Return the current core's virtual address.
612 */
613static void *
614_sb_setcoreidx(si_info_t *sii, uint coreidx)
615{
616 uint32 sbaddr = sii->coresba[coreidx];
617 void *regs;
618
619 switch (BUSTYPE(sii->pub.bustype)) {
620 case SI_BUS:
621 /* map new one */
622 if (!sii->regs[coreidx]) {
623 sii->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE);
624 ASSERT(GOODREGS(sii->regs[coreidx]));
625 }
626 regs = sii->regs[coreidx];
627 break;
628
629 case PCI_BUS:
630 /* point bar0 window */
631 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, sbaddr);
632 regs = sii->curmap;
633 break;
634
635 case PCMCIA_BUS: {
636 uint8 tmp = (sbaddr >> 12) & 0x0f;
637 OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1);
638 tmp = (sbaddr >> 16) & 0xff;
639 OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1);
640 tmp = (sbaddr >> 24) & 0xff;
641 OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1);
642 regs = sii->curmap;
643 break;
644 }
645 case SPI_BUS:
646 case SDIO_BUS:
647 /* map new one */
648 if (!sii->regs[coreidx]) {
649 sii->regs[coreidx] = (void *)(uintptr)sbaddr;
650 ASSERT(GOODREGS(sii->regs[coreidx]));
651 }
652 regs = sii->regs[coreidx];
653 break;
654
655
656 default:
657 ASSERT(0);
658 regs = NULL;
659 break;
660 }
661
662 return regs;
663}
664
665/* Return the address of sbadmatch0/1/2/3 register */
666static volatile uint32 *
667sb_admatch(si_info_t *sii, uint asidx)
668{
669 sbconfig_t *sb;
670 volatile uint32 *addrm;
671
672 sb = REGS2SB(sii->curmap);
673
674 switch (asidx) {
675 case 0:
676 addrm = &sb->sbadmatch0;
677 break;
678
679 case 1:
680 addrm = &sb->sbadmatch1;
681 break;
682
683 case 2:
684 addrm = &sb->sbadmatch2;
685 break;
686
687 case 3:
688 addrm = &sb->sbadmatch3;
689 break;
690
691 default:
692 SI_ERROR(("%s: Address space index (%d) out of range\n", __FUNCTION__, asidx));
693 return 0;
694 }
695
696 return (addrm);
697}
698
699/* Return the number of address spaces in current core */
700int
701sb_numaddrspaces(si_t *sih)
702{
703 si_info_t *sii;
704 sbconfig_t *sb;
705
706 sii = SI_INFO(sih);
707 sb = REGS2SB(sii->curmap);
708
709 /* + 1 because of enumeration space */
710 return ((R_SBREG(sii, &sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT) + 1;
711}
712
713/* Return the address of the nth address space in the current core */
714uint32
715sb_addrspace(si_t *sih, uint asidx)
716{
717 si_info_t *sii;
718
719 sii = SI_INFO(sih);
720
721 return (sb_base(R_SBREG(sii, sb_admatch(sii, asidx))));
722}
723
724/* Return the size of the nth address space in the current core */
725uint32
726sb_addrspacesize(si_t *sih, uint asidx)
727{
728 si_info_t *sii;
729
730 sii = SI_INFO(sih);
731
732 return (sb_size(R_SBREG(sii, sb_admatch(sii, asidx))));
733}
734
735
736/* do buffered registers update */
737void
738sb_commit(si_t *sih)
739{
740 si_info_t *sii;
741 uint origidx;
742 uint intr_val = 0;
743
744 sii = SI_INFO(sih);
745
746 origidx = sii->curidx;
747 ASSERT(GOODIDX(origidx));
748
749 INTR_OFF(sii, intr_val);
750
751 /* switch over to chipcommon core if there is one, else use pci */
752 if (sii->pub.ccrev != NOREV) {
753 chipcregs_t *ccregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
754 ASSERT(ccregs != NULL);
755
756 /* do the buffer registers update */
757 W_REG(sii->osh, &ccregs->broadcastaddress, SB_COMMIT);
758 W_REG(sii->osh, &ccregs->broadcastdata, 0x0);
759 } else
760 ASSERT(0);
761
762 /* restore core index */
763 sb_setcoreidx(sih, origidx);
764 INTR_RESTORE(sii, intr_val);
765}
766
767void
768sb_core_disable(si_t *sih, uint32 bits)
769{
770 si_info_t *sii;
771 volatile uint32 dummy;
772 sbconfig_t *sb;
773
774 sii = SI_INFO(sih);
775
776 ASSERT(GOODREGS(sii->curmap));
777 sb = REGS2SB(sii->curmap);
778
779 /* if core is already in reset, just return */
780 if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET)
781 return;
782
783 /* if clocks are not enabled, put into reset and return */
784 if ((R_SBREG(sii, &sb->sbtmstatelow) & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0)
785 goto disable;
786
787 /* set target reject and spin until busy is clear (preserve core-specific bits) */
788 OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ);
789 dummy = R_SBREG(sii, &sb->sbtmstatelow);
790 OSL_DELAY(1);
791 SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000);
792 if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY)
793 SI_ERROR(("%s: target state still busy\n", __FUNCTION__));
794
795 if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) {
796 OR_SBREG(sii, &sb->sbimstate, SBIM_RJ);
797 dummy = R_SBREG(sii, &sb->sbimstate);
798 OSL_DELAY(1);
799 SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000);
800 }
801
802 /* set reset and reject while enabling the clocks */
803 W_SBREG(sii, &sb->sbtmstatelow,
804 (((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
805 SBTML_REJ | SBTML_RESET));
806 dummy = R_SBREG(sii, &sb->sbtmstatelow);
807 OSL_DELAY(10);
808
809 /* don't forget to clear the initiator reject bit */
810 if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT)
811 AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ);
812
813disable:
814 /* leave reset and reject asserted */
815 W_SBREG(sii, &sb->sbtmstatelow, ((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET));
816 OSL_DELAY(1);
817}
818
819/* reset and re-enable a core
820 * inputs:
821 * bits - core specific bits that are set during and after reset sequence
822 * resetbits - core specific bits that are set only during reset sequence
823 */
824void
825sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
826{
827 si_info_t *sii;
828 sbconfig_t *sb;
829 volatile uint32 dummy;
830
831 sii = SI_INFO(sih);
832 ASSERT(GOODREGS(sii->curmap));
833 sb = REGS2SB(sii->curmap);
834
835 /*
836 * Must do the disable sequence first to work for arbitrary current core state.
837 */
838 sb_core_disable(sih, (bits | resetbits));
839
840 /*
841 * Now do the initialization sequence.
842 */
843
844 /* set reset while enabling the clock and forcing them on throughout the core */
845 W_SBREG(sii, &sb->sbtmstatelow,
846 (((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
847 SBTML_RESET));
848 dummy = R_SBREG(sii, &sb->sbtmstatelow);
849 OSL_DELAY(1);
850
851 if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR) {
852 W_SBREG(sii, &sb->sbtmstatehigh, 0);
853 }
854 if ((dummy = R_SBREG(sii, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) {
855 AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO));
856 }
857
858 /* clear reset and allow it to propagate throughout the core */
859 W_SBREG(sii, &sb->sbtmstatelow,
860 ((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT));
861 dummy = R_SBREG(sii, &sb->sbtmstatelow);
862 OSL_DELAY(1);
863
864 /* leave clock enabled */
865 W_SBREG(sii, &sb->sbtmstatelow, ((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT));
866 dummy = R_SBREG(sii, &sb->sbtmstatelow);
867 OSL_DELAY(1);
868}
869
870/*
871 * Set the initiator timeout for the "master core".
872 * The master core is defined to be the core in control
873 * of the chip and so it issues accesses to non-memory
874 * locations (Because of dma *any* core can access memeory).
875 *
876 * The routine uses the bus to decide who is the master:
877 * SI_BUS => mips
878 * JTAG_BUS => chipc
879 * PCI_BUS => pci or pcie
880 * PCMCIA_BUS => pcmcia
881 * SDIO_BUS => pcmcia
882 *
883 * This routine exists so callers can disable initiator
884 * timeouts so accesses to very slow devices like otp
885 * won't cause an abort. The routine allows arbitrary
886 * settings of the service and request timeouts, though.
887 *
888 * Returns the timeout state before changing it or -1
889 * on error.
890 */
891
892#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK)
893
894uint32
895sb_set_initiator_to(si_t *sih, uint32 to, uint idx)
896{
897 si_info_t *sii;
898 uint origidx;
899 uint intr_val = 0;
900 uint32 tmp, ret = 0xffffffff;
901 sbconfig_t *sb;
902
903 sii = SI_INFO(sih);
904
905 if ((to & ~TO_MASK) != 0)
906 return ret;
907
908 /* Figure out the master core */
909 if (idx == BADIDX) {
910 switch (BUSTYPE(sii->pub.bustype)) {
911 case PCI_BUS:
912 idx = sii->pub.buscoreidx;
913 break;
914 case JTAG_BUS:
915 idx = SI_CC_IDX;
916 break;
917 case PCMCIA_BUS:
918 case SDIO_BUS:
919 idx = si_findcoreidx(sih, PCMCIA_CORE_ID, 0);
920 break;
921 case SI_BUS:
922 idx = si_findcoreidx(sih, MIPS33_CORE_ID, 0);
923 break;
924 default:
925 ASSERT(0);
926 }
927 if (idx == BADIDX)
928 return ret;
929 }
930
931 INTR_OFF(sii, intr_val);
932 origidx = si_coreidx(sih);
933
934 sb = REGS2SB(sb_setcoreidx(sih, idx));
935
936 tmp = R_SBREG(sii, &sb->sbimconfiglow);
937 ret = tmp & TO_MASK;
938 W_SBREG(sii, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to);
939
940 sb_commit(sih);
941 sb_setcoreidx(sih, origidx);
942 INTR_RESTORE(sii, intr_val);
943 return ret;
944}
945
946uint32
947sb_base(uint32 admatch)
948{
949 uint32 base;
950 uint type;
951
952 type = admatch & SBAM_TYPE_MASK;
953 ASSERT(type < 3);
954
955 base = 0;
956
957 if (type == 0) {
958 base = admatch & SBAM_BASE0_MASK;
959 } else if (type == 1) {
960 ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
961 base = admatch & SBAM_BASE1_MASK;
962 } else if (type == 2) {
963 ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
964 base = admatch & SBAM_BASE2_MASK;
965 }
966
967 return (base);
968}
969
970uint32
971sb_size(uint32 admatch)
972{
973 uint32 size;
974 uint type;
975
976 type = admatch & SBAM_TYPE_MASK;
977 ASSERT(type < 3);
978
979 size = 0;
980
981 if (type == 0) {
982 size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1);
983 } else if (type == 1) {
984 ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
985 size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1);
986 } else if (type == 2) {
987 ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
988 size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1);
989 }
990
991 return (size);
992}
diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c
new file mode 100644
index 00000000000..22aa4126576
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/siutils.c
@@ -0,0 +1,1720 @@
1/*
2 * Misc utility routines for accessing chip-specific features
3 * of the SiliconBackplane-based Broadcom chips.
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: siutils.c,v 1.813.2.36 2011-02-10 23:43:55 Exp $
26 */
27
28#include <typedefs.h>
29#include <bcmdefs.h>
30#include <osl.h>
31#include <bcmutils.h>
32#include <siutils.h>
33#include <bcmdevs.h>
34#include <hndsoc.h>
35#include <sbchipc.h>
36#include <pcicfg.h>
37#include <sbpcmcia.h>
38#include <sbsocram.h>
39#include <bcmsdh.h>
40#include <sdio.h>
41#include <sbsdio.h>
42#include <sbhnddma.h>
43#include <sbsdpcmdev.h>
44#include <bcmsdpcm.h>
45#include <hndpmu.h>
46
47#include "siutils_priv.h"
48
49/* local prototypes */
50static si_info_t *si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs,
51 uint bustype, void *sdh, char **vars, uint *varsz);
52static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh);
53static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
54 uint *origidx, void *regs);
55
56
57/* global variable to indicate reservation/release of gpio's */
58static uint32 si_gpioreservation = 0;
59
60/* global flag to prevent shared resources from being initialized multiple times in si_attach() */
61
62/*
63 * Allocate a si handle.
64 * devid - pci device id (used to determine chip#)
65 * osh - opaque OS handle
66 * regs - virtual address of initial core registers
67 * bustype - pci/pcmcia/sb/sdio/etc
68 * vars - pointer to a pointer area for "environment" variables
69 * varsz - pointer to int to return the size of the vars
70 */
71si_t *
72si_attach(uint devid, osl_t *osh, void *regs,
73 uint bustype, void *sdh, char **vars, uint *varsz)
74{
75 si_info_t *sii;
76
77 /* alloc si_info_t */
78 if ((sii = MALLOC(osh, sizeof (si_info_t))) == NULL) {
79 SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh)));
80 return (NULL);
81 }
82
83 if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) {
84 MFREE(osh, sii, sizeof(si_info_t));
85 return (NULL);
86 }
87 sii->vars = vars ? *vars : NULL;
88 sii->varsz = varsz ? *varsz : 0;
89
90 return (si_t *)sii;
91}
92
93/* global kernel resource */
94static si_info_t ksii;
95
96static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */
97
98/* generic kernel variant of si_attach() */
99si_t *
100si_kattach(osl_t *osh)
101{
102 static bool ksii_attached = FALSE;
103
104 if (!ksii_attached) {
105 void *regs;
106 regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE);
107
108 if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs,
109 SI_BUS, NULL,
110 osh != SI_OSH ? &ksii.vars : NULL,
111 osh != SI_OSH ? &ksii.varsz : NULL) == NULL) {
112 SI_ERROR(("si_kattach: si_doattach failed\n"));
113 REG_UNMAP(regs);
114 return NULL;
115 }
116 REG_UNMAP(regs);
117
118 /* save ticks normalized to ms for si_watchdog_ms() */
119 if (PMUCTL_ENAB(&ksii.pub)) {
120 /* based on 32KHz ILP clock */
121 wd_msticks = 32;
122 } else {
123 wd_msticks = ALP_CLOCK / 1000;
124 }
125
126 ksii_attached = TRUE;
127 SI_MSG(("si_kattach done. ccrev = %d, wd_msticks = %d\n",
128 ksii.pub.ccrev, wd_msticks));
129 }
130
131 return &ksii.pub;
132}
133
134
135static bool
136si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh)
137{
138 /* need to set memseg flag for CF card first before any sb registers access */
139 if (BUSTYPE(bustype) == PCMCIA_BUS)
140 sii->memseg = TRUE;
141
142
143 if (BUSTYPE(bustype) == SDIO_BUS) {
144 int err;
145 uint8 clkset;
146
147 /* Try forcing SDIO core to do ALPAvail request only */
148 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
149 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
150 if (!err) {
151 uint8 clkval;
152
153 /* If register supported, wait for ALPAvail and then force ALP */
154 clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL);
155 if ((clkval & ~SBSDIO_AVBITS) == clkset) {
156 SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
157 SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)),
158 PMU_MAX_TRANSITION_DLY);
159 if (!SBSDIO_ALPAV(clkval)) {
160 SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n",
161 clkval));
162 return FALSE;
163 }
164 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
165 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
166 clkset, &err);
167 OSL_DELAY(65);
168 }
169 }
170
171 /* Also, disable the extra SDIO pull-ups */
172 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
173 }
174
175
176 return TRUE;
177}
178
179static bool
180si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
181 uint *origidx, void *regs)
182{
183 bool pci, pcie;
184 uint i;
185 uint pciidx, pcieidx, pcirev, pcierev;
186
187 cc = si_setcoreidx(&sii->pub, SI_CC_IDX);
188 ASSERT((uintptr)cc);
189
190 /* get chipcommon rev */
191 sii->pub.ccrev = (int)si_corerev(&sii->pub);
192
193 /* get chipcommon chipstatus */
194 if (sii->pub.ccrev >= 11)
195 sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus);
196
197 /* get chipcommon capabilites */
198 sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities);
199 /* get chipcommon extended capabilities */
200
201 if (sii->pub.ccrev >= 35)
202 sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext);
203
204 /* get pmu rev and caps */
205 if (sii->pub.cccaps & CC_CAP_PMU) {
206 sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities);
207 sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK;
208 }
209
210 SI_MSG(("Chipc: rev %d, caps 0x%x, chipst 0x%x pmurev %d, pmucaps 0x%x\n",
211 sii->pub.ccrev, sii->pub.cccaps, sii->pub.chipst, sii->pub.pmurev,
212 sii->pub.pmucaps));
213
214 /* figure out bus/orignal core idx */
215 sii->pub.buscoretype = NODEV_CORE_ID;
216 sii->pub.buscorerev = NOREV;
217 sii->pub.buscoreidx = BADIDX;
218
219 pci = pcie = FALSE;
220 pcirev = pcierev = NOREV;
221 pciidx = pcieidx = BADIDX;
222
223 for (i = 0; i < sii->numcores; i++) {
224 uint cid, crev;
225
226 si_setcoreidx(&sii->pub, i);
227 cid = si_coreid(&sii->pub);
228 crev = si_corerev(&sii->pub);
229
230 /* Display cores found */
231 SI_VMSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n",
232 i, cid, crev, sii->coresba[i], sii->regs[i]));
233
234 if (BUSTYPE(bustype) == PCI_BUS) {
235 if (cid == PCI_CORE_ID) {
236 pciidx = i;
237 pcirev = crev;
238 pci = TRUE;
239 } else if (cid == PCIE_CORE_ID) {
240 pcieidx = i;
241 pcierev = crev;
242 pcie = TRUE;
243 }
244 } else if ((BUSTYPE(bustype) == PCMCIA_BUS) &&
245 (cid == PCMCIA_CORE_ID)) {
246 sii->pub.buscorerev = crev;
247 sii->pub.buscoretype = cid;
248 sii->pub.buscoreidx = i;
249 }
250 else if (((BUSTYPE(bustype) == SDIO_BUS) ||
251 (BUSTYPE(bustype) == SPI_BUS)) &&
252 ((cid == PCMCIA_CORE_ID) ||
253 (cid == SDIOD_CORE_ID))) {
254 sii->pub.buscorerev = crev;
255 sii->pub.buscoretype = cid;
256 sii->pub.buscoreidx = i;
257 }
258
259 /* find the core idx before entering this func. */
260 if ((savewin && (savewin == sii->coresba[i])) ||
261 (regs == sii->regs[i]))
262 *origidx = i;
263 }
264
265 if (pci) {
266 sii->pub.buscoretype = PCI_CORE_ID;
267 sii->pub.buscorerev = pcirev;
268 sii->pub.buscoreidx = pciidx;
269 } else if (pcie) {
270 sii->pub.buscoretype = PCIE_CORE_ID;
271 sii->pub.buscorerev = pcierev;
272 sii->pub.buscoreidx = pcieidx;
273 }
274
275 SI_VMSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype,
276 sii->pub.buscorerev));
277
278 if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) &&
279 (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (CHIPREV(sii->pub.chiprev) <= 3))
280 OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL);
281
282
283 /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was
284 * already running.
285 */
286 if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) {
287 if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) ||
288 si_setcore(&sii->pub, ARMCM3_CORE_ID, 0))
289 si_core_disable(&sii->pub, 0);
290 }
291
292 /* return to the original core */
293 si_setcoreidx(&sii->pub, *origidx);
294
295 return TRUE;
296}
297
298
299
300static si_info_t *
301si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs,
302 uint bustype, void *sdh, char **vars, uint *varsz)
303{
304 struct si_pub *sih = &sii->pub;
305 uint32 w, savewin;
306 chipcregs_t *cc;
307 char *pvars = NULL;
308 uint origidx;
309
310 ASSERT(GOODREGS(regs));
311
312 bzero((uchar*)sii, sizeof(si_info_t));
313
314 savewin = 0;
315
316 sih->buscoreidx = BADIDX;
317
318 sii->curmap = regs;
319 sii->sdh = sdh;
320 sii->osh = osh;
321
322
323
324 /* find Chipcommon address */
325 if (bustype == PCI_BUS) {
326 savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32));
327 if (!GOODCOREADDR(savewin, SI_ENUM_BASE))
328 savewin = SI_ENUM_BASE;
329 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE);
330 cc = (chipcregs_t *)regs;
331 } else if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) {
332 cc = (chipcregs_t *)sii->curmap;
333 } else {
334 cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE);
335 }
336
337 sih->bustype = bustype;
338 if (bustype != BUSTYPE(bustype)) {
339 SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n",
340 bustype, BUSTYPE(bustype)));
341 return NULL;
342 }
343
344 /* bus/core/clk setup for register access */
345 if (!si_buscore_prep(sii, bustype, devid, sdh)) {
346 SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype));
347 return NULL;
348 }
349
350 /* ChipID recognition.
351 * We assume we can read chipid at offset 0 from the regs arg.
352 * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon),
353 * some way of recognizing them needs to be added here.
354 */
355 w = R_REG(osh, &cc->chipid);
356 sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
357 /* Might as wll fill in chip id rev & pkg */
358 sih->chip = w & CID_ID_MASK;
359 sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
360 sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
361 if (CHIPID(sih->chip) == BCM4322_CHIP_ID && (((sih->chipst & CST4322_SPROM_OTP_SEL_MASK)
362 >> CST4322_SPROM_OTP_SEL_SHIFT) == (CST4322_OTP_PRESENT |
363 CST4322_SPROM_PRESENT))) {
364 SI_ERROR(("%s: Invalid setting: both SPROM and OTP strapped.\n", __FUNCTION__));
365 return NULL;
366 }
367
368 if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) &&
369 (sih->chippkg != BCM4329_289PIN_PKG_ID)) {
370 sih->chippkg = BCM4329_182PIN_PKG_ID;
371 }
372
373 sih->issim = IS_SIM(sih->chippkg);
374
375 /* scan for cores */
376 if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) {
377 SI_MSG(("Found chip type SB (0x%08x)\n", w));
378 sb_scan(&sii->pub, regs, devid);
379 } else if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) {
380 SI_MSG(("Found chip type AI (0x%08x)\n", w));
381 /* pass chipc address instead of original core base */
382 ai_scan(&sii->pub, (void *)(uintptr)cc, devid);
383 } else if (CHIPTYPE(sii->pub.socitype) == SOCI_UBUS) {
384 SI_MSG(("Found chip type UBUS (0x%08x), chip id = 0x%4x\n", w, sih->chip));
385 /* pass chipc address instead of original core base */
386 ub_scan(&sii->pub, (void *)(uintptr)cc, devid);
387 } else {
388 SI_ERROR(("Found chip of unknown type (0x%08x)\n", w));
389 return NULL;
390 }
391 /* no cores found, bail out */
392 if (sii->numcores == 0) {
393 SI_ERROR(("si_doattach: could not find any cores\n"));
394 return NULL;
395 }
396 /* bus/core/clk setup */
397 origidx = SI_CC_IDX;
398 if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) {
399 SI_ERROR(("si_doattach: si_buscore_setup failed\n"));
400 goto exit;
401 }
402
403 /* assume current core is CC */
404 if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID ||
405 CHIPID(sih->chip) == BCM43235_CHIP_ID ||
406 CHIPID(sih->chip) == BCM43238_CHIP_ID) &&
407 (CHIPREV(sii->pub.chiprev) == 0))) {
408
409 if ((cc->chipstatus & CST43236_BP_CLK) != 0) {
410 uint clkdiv;
411 clkdiv = R_REG(osh, &cc->clkdiv);
412 /* otp_clk_div is even number, 120/14 < 9mhz */
413 clkdiv = (clkdiv & ~CLKD_OTP) | (14 << CLKD_OTP_SHIFT);
414 W_REG(osh, &cc->clkdiv, clkdiv);
415 SI_ERROR(("%s: set clkdiv to %x\n", __FUNCTION__, clkdiv));
416 }
417 OSL_DELAY(10);
418 }
419
420
421 pvars = NULL;
422
423
424
425 if (sii->pub.ccrev >= 20) {
426 cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
427 ASSERT(cc != NULL);
428 W_REG(osh, &cc->gpiopullup, 0);
429 W_REG(osh, &cc->gpiopulldown, 0);
430 si_setcoreidx(sih, origidx);
431 }
432
433
434
435
436 return (sii);
437
438exit:
439
440 return NULL;
441}
442
443/* may be called with core in reset */
444void
445si_detach(si_t *sih)
446{
447 si_info_t *sii;
448 uint idx;
449
450
451 sii = SI_INFO(sih);
452
453 if (sii == NULL)
454 return;
455
456 if (BUSTYPE(sih->bustype) == SI_BUS)
457 for (idx = 0; idx < SI_MAXCORES; idx++)
458 if (sii->regs[idx]) {
459 REG_UNMAP(sii->regs[idx]);
460 sii->regs[idx] = NULL;
461 }
462
463
464
465#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS)
466 if (sii != &ksii)
467#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */
468 MFREE(sii->osh, sii, sizeof(si_info_t));
469}
470
471void *
472si_osh(si_t *sih)
473{
474 si_info_t *sii;
475
476 sii = SI_INFO(sih);
477 return sii->osh;
478}
479
480void
481si_setosh(si_t *sih, osl_t *osh)
482{
483 si_info_t *sii;
484
485 sii = SI_INFO(sih);
486 if (sii->osh != NULL) {
487 SI_ERROR(("osh is already set....\n"));
488 ASSERT(!sii->osh);
489 }
490 sii->osh = osh;
491}
492
493/* register driver interrupt disabling and restoring callback functions */
494void
495si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn,
496 void *intrsenabled_fn, void *intr_arg)
497{
498 si_info_t *sii;
499
500 sii = SI_INFO(sih);
501 sii->intr_arg = intr_arg;
502 sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn;
503 sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn;
504 sii->intrsenabled_fn = (si_intrsenabled_t)intrsenabled_fn;
505 /* save current core id. when this function called, the current core
506 * must be the core which provides driver functions(il, et, wl, etc.)
507 */
508 sii->dev_coreid = sii->coreid[sii->curidx];
509}
510
511void
512si_deregister_intr_callback(si_t *sih)
513{
514 si_info_t *sii;
515
516 sii = SI_INFO(sih);
517 sii->intrsoff_fn = NULL;
518}
519
520uint
521si_intflag(si_t *sih)
522{
523 si_info_t *sii = SI_INFO(sih);
524
525 if (CHIPTYPE(sih->socitype) == SOCI_SB)
526 return sb_intflag(sih);
527 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
528 return R_REG(sii->osh, ((uint32 *)(uintptr)
529 (sii->oob_router + OOB_STATUSA)));
530 else {
531 ASSERT(0);
532 return 0;
533 }
534}
535
536uint
537si_flag(si_t *sih)
538{
539 if (CHIPTYPE(sih->socitype) == SOCI_SB)
540 return sb_flag(sih);
541 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
542 return ai_flag(sih);
543 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
544 return ub_flag(sih);
545 else {
546 ASSERT(0);
547 return 0;
548 }
549}
550
551void
552si_setint(si_t *sih, int siflag)
553{
554 if (CHIPTYPE(sih->socitype) == SOCI_SB)
555 sb_setint(sih, siflag);
556 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
557 ai_setint(sih, siflag);
558 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
559 ub_setint(sih, siflag);
560 else
561 ASSERT(0);
562}
563
564uint
565si_coreid(si_t *sih)
566{
567 si_info_t *sii;
568
569 sii = SI_INFO(sih);
570 return sii->coreid[sii->curidx];
571}
572
573uint
574si_coreidx(si_t *sih)
575{
576 si_info_t *sii;
577
578 sii = SI_INFO(sih);
579 return sii->curidx;
580}
581
582/* return the core-type instantiation # of the current core */
583uint
584si_coreunit(si_t *sih)
585{
586 si_info_t *sii;
587 uint idx;
588 uint coreid;
589 uint coreunit;
590 uint i;
591
592 sii = SI_INFO(sih);
593 coreunit = 0;
594
595 idx = sii->curidx;
596
597 ASSERT(GOODREGS(sii->curmap));
598 coreid = si_coreid(sih);
599
600 /* count the cores of our type */
601 for (i = 0; i < idx; i++)
602 if (sii->coreid[i] == coreid)
603 coreunit++;
604
605 return (coreunit);
606}
607
608uint
609si_corevendor(si_t *sih)
610{
611 if (CHIPTYPE(sih->socitype) == SOCI_SB)
612 return sb_corevendor(sih);
613 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
614 return ai_corevendor(sih);
615 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
616 return ub_corevendor(sih);
617 else {
618 ASSERT(0);
619 return 0;
620 }
621}
622
623bool
624si_backplane64(si_t *sih)
625{
626 return ((sih->cccaps & CC_CAP_BKPLN64) != 0);
627}
628
629uint
630si_corerev(si_t *sih)
631{
632 if (CHIPTYPE(sih->socitype) == SOCI_SB)
633 return sb_corerev(sih);
634 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
635 return ai_corerev(sih);
636 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
637 return ub_corerev(sih);
638 else {
639 ASSERT(0);
640 return 0;
641 }
642}
643
644/* return index of coreid or BADIDX if not found */
645uint
646si_findcoreidx(si_t *sih, uint coreid, uint coreunit)
647{
648 si_info_t *sii;
649 uint found;
650 uint i;
651
652 sii = SI_INFO(sih);
653
654 found = 0;
655
656 for (i = 0; i < sii->numcores; i++)
657 if (sii->coreid[i] == coreid) {
658 if (found == coreunit)
659 return (i);
660 found++;
661 }
662
663 return (BADIDX);
664}
665
666/* return list of found cores */
667uint
668si_corelist(si_t *sih, uint coreid[])
669{
670 si_info_t *sii;
671
672 sii = SI_INFO(sih);
673
674 bcopy((uchar*)sii->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint)));
675 return (sii->numcores);
676}
677
678/* return current register mapping */
679void *
680si_coreregs(si_t *sih)
681{
682 si_info_t *sii;
683
684 sii = SI_INFO(sih);
685 ASSERT(GOODREGS(sii->curmap));
686
687 return (sii->curmap);
688}
689
690/*
691 * This function changes logical "focus" to the indicated core;
692 * must be called with interrupts off.
693 * Moreover, callers should keep interrupts off during switching out of and back to d11 core
694 */
695void *
696si_setcore(si_t *sih, uint coreid, uint coreunit)
697{
698 uint idx;
699
700 idx = si_findcoreidx(sih, coreid, coreunit);
701 if (!GOODIDX(idx))
702 return (NULL);
703
704 if (CHIPTYPE(sih->socitype) == SOCI_SB)
705 return sb_setcoreidx(sih, idx);
706 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
707 return ai_setcoreidx(sih, idx);
708 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
709 return ub_setcoreidx(sih, idx);
710 else {
711 ASSERT(0);
712 return NULL;
713 }
714}
715
716void *
717si_setcoreidx(si_t *sih, uint coreidx)
718{
719 if (CHIPTYPE(sih->socitype) == SOCI_SB)
720 return sb_setcoreidx(sih, coreidx);
721 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
722 return ai_setcoreidx(sih, coreidx);
723 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
724 return ub_setcoreidx(sih, coreidx);
725 else {
726 ASSERT(0);
727 return NULL;
728 }
729}
730
731/* Turn off interrupt as required by sb_setcore, before switch core */
732void *
733si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val)
734{
735 void *cc;
736 si_info_t *sii;
737
738 sii = SI_INFO(sih);
739
740 if (SI_FAST(sii)) {
741 /* Overloading the origidx variable to remember the coreid,
742 * this works because the core ids cannot be confused with
743 * core indices.
744 */
745 *origidx = coreid;
746 if (coreid == CC_CORE_ID)
747 return (void *)CCREGS_FAST(sii);
748 else if (coreid == sih->buscoretype)
749 return (void *)PCIEREGS(sii);
750 }
751 INTR_OFF(sii, *intr_val);
752 *origidx = sii->curidx;
753 cc = si_setcore(sih, coreid, 0);
754 ASSERT(cc != NULL);
755
756 return cc;
757}
758
759/* restore coreidx and restore interrupt */
760void
761si_restore_core(si_t *sih, uint coreid, uint intr_val)
762{
763 si_info_t *sii;
764
765 sii = SI_INFO(sih);
766 if (SI_FAST(sii) && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype)))
767 return;
768
769 si_setcoreidx(sih, coreid);
770 INTR_RESTORE(sii, intr_val);
771}
772
773int
774si_numaddrspaces(si_t *sih)
775{
776 if (CHIPTYPE(sih->socitype) == SOCI_SB)
777 return sb_numaddrspaces(sih);
778 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
779 return ai_numaddrspaces(sih);
780 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
781 return ub_numaddrspaces(sih);
782 else {
783 ASSERT(0);
784 return 0;
785 }
786}
787
788uint32
789si_addrspace(si_t *sih, uint asidx)
790{
791 if (CHIPTYPE(sih->socitype) == SOCI_SB)
792 return sb_addrspace(sih, asidx);
793 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
794 return ai_addrspace(sih, asidx);
795 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
796 return ub_addrspace(sih, asidx);
797 else {
798 ASSERT(0);
799 return 0;
800 }
801}
802
803uint32
804si_addrspacesize(si_t *sih, uint asidx)
805{
806 if (CHIPTYPE(sih->socitype) == SOCI_SB)
807 return sb_addrspacesize(sih, asidx);
808 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
809 return ai_addrspacesize(sih, asidx);
810 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
811 return ub_addrspacesize(sih, asidx);
812 else {
813 ASSERT(0);
814 return 0;
815 }
816}
817
818uint32
819si_core_cflags(si_t *sih, uint32 mask, uint32 val)
820{
821 if (CHIPTYPE(sih->socitype) == SOCI_SB)
822 return sb_core_cflags(sih, mask, val);
823 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
824 return ai_core_cflags(sih, mask, val);
825 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
826 return ub_core_cflags(sih, mask, val);
827 else {
828 ASSERT(0);
829 return 0;
830 }
831}
832
833void
834si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
835{
836 if (CHIPTYPE(sih->socitype) == SOCI_SB)
837 sb_core_cflags_wo(sih, mask, val);
838 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
839 ai_core_cflags_wo(sih, mask, val);
840 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
841 ub_core_cflags_wo(sih, mask, val);
842 else
843 ASSERT(0);
844}
845
846uint32
847si_core_sflags(si_t *sih, uint32 mask, uint32 val)
848{
849 if (CHIPTYPE(sih->socitype) == SOCI_SB)
850 return sb_core_sflags(sih, mask, val);
851 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
852 return ai_core_sflags(sih, mask, val);
853 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
854 return ub_core_sflags(sih, mask, val);
855 else {
856 ASSERT(0);
857 return 0;
858 }
859}
860
861bool
862si_iscoreup(si_t *sih)
863{
864 if (CHIPTYPE(sih->socitype) == SOCI_SB)
865 return sb_iscoreup(sih);
866 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
867 return ai_iscoreup(sih);
868 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
869 return ub_iscoreup(sih);
870 else {
871 ASSERT(0);
872 return FALSE;
873 }
874}
875
876uint
877si_wrapperreg(si_t *sih, uint32 offset, uint32 mask, uint32 val)
878{
879 /* only for AI back plane chips */
880 if (CHIPTYPE(sih->socitype) == SOCI_AI)
881 return (ai_wrap_reg(sih, offset, mask, val));
882 return 0;
883}
884
885uint
886si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
887{
888 if (CHIPTYPE(sih->socitype) == SOCI_SB)
889 return sb_corereg(sih, coreidx, regoff, mask, val);
890 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
891 return ai_corereg(sih, coreidx, regoff, mask, val);
892 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
893 return ub_corereg(sih, coreidx, regoff, mask, val);
894 else {
895 ASSERT(0);
896 return 0;
897 }
898}
899
900void
901si_core_disable(si_t *sih, uint32 bits)
902{
903 if (CHIPTYPE(sih->socitype) == SOCI_SB)
904 sb_core_disable(sih, bits);
905 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
906 ai_core_disable(sih, bits);
907 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
908 ub_core_disable(sih, bits);
909}
910
911void
912si_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
913{
914 if (CHIPTYPE(sih->socitype) == SOCI_SB)
915 sb_core_reset(sih, bits, resetbits);
916 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
917 ai_core_reset(sih, bits, resetbits);
918 else if (CHIPTYPE(sih->socitype) == SOCI_UBUS)
919 ub_core_reset(sih, bits, resetbits);
920}
921
922/* Run bist on current core. Caller needs to take care of core-specific bist hazards */
923int
924si_corebist(si_t *sih)
925{
926 uint32 cflags;
927 int result = 0;
928
929 /* Read core control flags */
930 cflags = si_core_cflags(sih, 0, 0);
931
932 /* Set bist & fgc */
933 si_core_cflags(sih, ~0, (SICF_BIST_EN | SICF_FGC));
934
935 /* Wait for bist done */
936 SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000);
937
938 if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR)
939 result = BCME_ERROR;
940
941 /* Reset core control flags */
942 si_core_cflags(sih, 0xffff, cflags);
943
944 return result;
945}
946
947static uint32
948factor6(uint32 x)
949{
950 switch (x) {
951 case CC_F6_2: return 2;
952 case CC_F6_3: return 3;
953 case CC_F6_4: return 4;
954 case CC_F6_5: return 5;
955 case CC_F6_6: return 6;
956 case CC_F6_7: return 7;
957 default: return 0;
958 }
959}
960
961/* calculate the speed the SI would run at given a set of clockcontrol values */
962uint32
963si_clock_rate(uint32 pll_type, uint32 n, uint32 m)
964{
965 uint32 n1, n2, clock, m1, m2, m3, mc;
966
967 n1 = n & CN_N1_MASK;
968 n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT;
969
970 if (pll_type == PLL_TYPE6) {
971 if (m & CC_T6_MMASK)
972 return CC_T6_M1;
973 else
974 return CC_T6_M0;
975 } else if ((pll_type == PLL_TYPE1) ||
976 (pll_type == PLL_TYPE3) ||
977 (pll_type == PLL_TYPE4) ||
978 (pll_type == PLL_TYPE7)) {
979 n1 = factor6(n1);
980 n2 += CC_F5_BIAS;
981 } else if (pll_type == PLL_TYPE2) {
982 n1 += CC_T2_BIAS;
983 n2 += CC_T2_BIAS;
984 ASSERT((n1 >= 2) && (n1 <= 7));
985 ASSERT((n2 >= 5) && (n2 <= 23));
986 } else if (pll_type == PLL_TYPE5) {
987 return (100000000);
988 } else
989 ASSERT(0);
990 /* PLL types 3 and 7 use BASE2 (25Mhz) */
991 if ((pll_type == PLL_TYPE3) ||
992 (pll_type == PLL_TYPE7)) {
993 clock = CC_CLOCK_BASE2 * n1 * n2;
994 } else
995 clock = CC_CLOCK_BASE1 * n1 * n2;
996
997 if (clock == 0)
998 return 0;
999
1000 m1 = m & CC_M1_MASK;
1001 m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT;
1002 m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT;
1003 mc = (m & CC_MC_MASK) >> CC_MC_SHIFT;
1004
1005 if ((pll_type == PLL_TYPE1) ||
1006 (pll_type == PLL_TYPE3) ||
1007 (pll_type == PLL_TYPE4) ||
1008 (pll_type == PLL_TYPE7)) {
1009 m1 = factor6(m1);
1010 if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3))
1011 m2 += CC_F5_BIAS;
1012 else
1013 m2 = factor6(m2);
1014 m3 = factor6(m3);
1015
1016 switch (mc) {
1017 case CC_MC_BYPASS: return (clock);
1018 case CC_MC_M1: return (clock / m1);
1019 case CC_MC_M1M2: return (clock / (m1 * m2));
1020 case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3));
1021 case CC_MC_M1M3: return (clock / (m1 * m3));
1022 default: return (0);
1023 }
1024 } else {
1025 ASSERT(pll_type == PLL_TYPE2);
1026
1027 m1 += CC_T2_BIAS;
1028 m2 += CC_T2M2_BIAS;
1029 m3 += CC_T2_BIAS;
1030 ASSERT((m1 >= 2) && (m1 <= 7));
1031 ASSERT((m2 >= 3) && (m2 <= 10));
1032 ASSERT((m3 >= 2) && (m3 <= 7));
1033
1034 if ((mc & CC_T2MC_M1BYP) == 0)
1035 clock /= m1;
1036 if ((mc & CC_T2MC_M2BYP) == 0)
1037 clock /= m2;
1038 if ((mc & CC_T2MC_M3BYP) == 0)
1039 clock /= m3;
1040
1041 return (clock);
1042 }
1043}
1044
1045
1046/* set chip watchdog reset timer to fire in 'ticks' */
1047void
1048si_watchdog(si_t *sih, uint ticks)
1049{
1050 uint nb, maxt;
1051
1052 if (PMUCTL_ENAB(sih)) {
1053
1054 if ((CHIPID(sih->chip) == BCM4319_CHIP_ID) &&
1055 (CHIPREV(sih->chiprev) == 0) && (ticks != 0)) {
1056 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2);
1057 si_setcore(sih, USB20D_CORE_ID, 0);
1058 si_core_disable(sih, 1);
1059 si_setcore(sih, CC_CORE_ID, 0);
1060 }
1061
1062 nb = (sih->ccrev < 26) ? 16 : ((sih->ccrev >= 37) ? 32 : 24);
1063 /* The mips compiler uses the sllv instruction,
1064 * so we specially handle the 32-bit case.
1065 */
1066 if (nb == 32)
1067 maxt = 0xffffffff;
1068 else
1069 maxt = ((1 << nb) - 1);
1070
1071 if (ticks == 1)
1072 ticks = 2;
1073 else if (ticks > maxt)
1074 ticks = maxt;
1075
1076 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog), ~0, ticks);
1077 } else {
1078 maxt = (1 << 28) - 1;
1079 if (ticks > maxt)
1080 ticks = maxt;
1081
1082 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks);
1083 }
1084}
1085
1086/* trigger watchdog reset after ms milliseconds */
1087void
1088si_watchdog_ms(si_t *sih, uint32 ms)
1089{
1090 si_watchdog(sih, wd_msticks * ms);
1091}
1092
1093
1094
1095
1096/* change logical "focus" to the gpio core for optimized access */
1097void *
1098si_gpiosetcore(si_t *sih)
1099{
1100 return (si_setcoreidx(sih, SI_CC_IDX));
1101}
1102
1103/* mask&set gpiocontrol bits */
1104uint32
1105si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1106{
1107 uint regoff;
1108
1109 regoff = 0;
1110
1111 /* gpios could be shared on router platforms
1112 * ignore reservation if it's high priority (e.g., test apps)
1113 */
1114 if ((priority != GPIO_HI_PRIORITY) &&
1115 (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1116 mask = priority ? (si_gpioreservation & mask) :
1117 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1118 val &= mask;
1119 }
1120
1121 regoff = OFFSETOF(chipcregs_t, gpiocontrol);
1122 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1123}
1124
1125/* mask&set gpio output enable bits */
1126uint32
1127si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1128{
1129 uint regoff;
1130
1131 regoff = 0;
1132
1133 /* gpios could be shared on router platforms
1134 * ignore reservation if it's high priority (e.g., test apps)
1135 */
1136 if ((priority != GPIO_HI_PRIORITY) &&
1137 (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1138 mask = priority ? (si_gpioreservation & mask) :
1139 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1140 val &= mask;
1141 }
1142
1143 regoff = OFFSETOF(chipcregs_t, gpioouten);
1144 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1145}
1146
1147/* mask&set gpio output bits */
1148uint32
1149si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1150{
1151 uint regoff;
1152
1153 regoff = 0;
1154
1155 /* gpios could be shared on router platforms
1156 * ignore reservation if it's high priority (e.g., test apps)
1157 */
1158 if ((priority != GPIO_HI_PRIORITY) &&
1159 (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1160 mask = priority ? (si_gpioreservation & mask) :
1161 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1162 val &= mask;
1163 }
1164
1165 regoff = OFFSETOF(chipcregs_t, gpioout);
1166 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1167}
1168
1169/* reserve one gpio */
1170uint32
1171si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority)
1172{
1173 si_info_t *sii;
1174
1175 sii = SI_INFO(sih);
1176
1177 /* only cores on SI_BUS share GPIO's and only applcation users need to
1178 * reserve/release GPIO
1179 */
1180 if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) {
1181 ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority));
1182 return 0xffffffff;
1183 }
1184 /* make sure only one bit is set */
1185 if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
1186 ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
1187 return 0xffffffff;
1188 }
1189
1190 /* already reserved */
1191 if (si_gpioreservation & gpio_bitmask)
1192 return 0xffffffff;
1193 /* set reservation */
1194 si_gpioreservation |= gpio_bitmask;
1195
1196 return si_gpioreservation;
1197}
1198
1199/* release one gpio */
1200/*
1201 * releasing the gpio doesn't change the current value on the GPIO last write value
1202 * persists till some one overwrites it
1203 */
1204
1205uint32
1206si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority)
1207{
1208 si_info_t *sii;
1209
1210 sii = SI_INFO(sih);
1211
1212 /* only cores on SI_BUS share GPIO's and only applcation users need to
1213 * reserve/release GPIO
1214 */
1215 if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) {
1216 ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority));
1217 return 0xffffffff;
1218 }
1219 /* make sure only one bit is set */
1220 if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
1221 ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
1222 return 0xffffffff;
1223 }
1224
1225 /* already released */
1226 if (!(si_gpioreservation & gpio_bitmask))
1227 return 0xffffffff;
1228
1229 /* clear reservation */
1230 si_gpioreservation &= ~gpio_bitmask;
1231
1232 return si_gpioreservation;
1233}
1234
1235/* return the current gpioin register value */
1236uint32
1237si_gpioin(si_t *sih)
1238{
1239 si_info_t *sii;
1240 uint regoff;
1241
1242 sii = SI_INFO(sih);
1243 regoff = 0;
1244
1245 regoff = OFFSETOF(chipcregs_t, gpioin);
1246 return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0));
1247}
1248
1249/* mask&set gpio interrupt polarity bits */
1250uint32
1251si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1252{
1253 si_info_t *sii;
1254 uint regoff;
1255
1256 sii = SI_INFO(sih);
1257 regoff = 0;
1258
1259 /* gpios could be shared on router platforms */
1260 if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1261 mask = priority ? (si_gpioreservation & mask) :
1262 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1263 val &= mask;
1264 }
1265
1266 regoff = OFFSETOF(chipcregs_t, gpiointpolarity);
1267 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1268}
1269
1270/* mask&set gpio interrupt mask bits */
1271uint32
1272si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1273{
1274 si_info_t *sii;
1275 uint regoff;
1276
1277 sii = SI_INFO(sih);
1278 regoff = 0;
1279
1280 /* gpios could be shared on router platforms */
1281 if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1282 mask = priority ? (si_gpioreservation & mask) :
1283 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1284 val &= mask;
1285 }
1286
1287 regoff = OFFSETOF(chipcregs_t, gpiointmask);
1288 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1289}
1290
1291/* assign the gpio to an led */
1292uint32
1293si_gpioled(si_t *sih, uint32 mask, uint32 val)
1294{
1295 si_info_t *sii;
1296
1297 sii = SI_INFO(sih);
1298 if (sih->ccrev < 16)
1299 return 0xffffffff;
1300
1301 /* gpio led powersave reg */
1302 return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val));
1303}
1304
1305/* mask&set gpio timer val */
1306uint32
1307si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval)
1308{
1309 si_info_t *sii;
1310
1311 sii = SI_INFO(sih);
1312
1313 if (sih->ccrev < 16)
1314 return 0xffffffff;
1315
1316 return (si_corereg(sih, SI_CC_IDX,
1317 OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval));
1318}
1319
1320uint32
1321si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val)
1322{
1323 si_info_t *sii;
1324 uint offs;
1325
1326 sii = SI_INFO(sih);
1327 if (sih->ccrev < 20)
1328 return 0xffffffff;
1329
1330 offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup));
1331 return (si_corereg(sih, SI_CC_IDX, offs, mask, val));
1332}
1333
1334uint32
1335si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val)
1336{
1337 si_info_t *sii;
1338 uint offs;
1339
1340 sii = SI_INFO(sih);
1341 if (sih->ccrev < 11)
1342 return 0xffffffff;
1343
1344 if (regtype == GPIO_REGEVT)
1345 offs = OFFSETOF(chipcregs_t, gpioevent);
1346 else if (regtype == GPIO_REGEVT_INTMSK)
1347 offs = OFFSETOF(chipcregs_t, gpioeventintmask);
1348 else if (regtype == GPIO_REGEVT_INTPOL)
1349 offs = OFFSETOF(chipcregs_t, gpioeventintpolarity);
1350 else
1351 return 0xffffffff;
1352
1353 return (si_corereg(sih, SI_CC_IDX, offs, mask, val));
1354}
1355
1356void *
1357si_gpio_handler_register(si_t *sih, uint32 event,
1358 bool level, gpio_handler_t cb, void *arg)
1359{
1360 si_info_t *sii;
1361 gpioh_item_t *gi;
1362
1363 ASSERT(event);
1364 ASSERT(cb != NULL);
1365
1366 sii = SI_INFO(sih);
1367 if (sih->ccrev < 11)
1368 return NULL;
1369
1370 if ((gi = MALLOC(sii->osh, sizeof(gpioh_item_t))) == NULL)
1371 return NULL;
1372
1373 bzero(gi, sizeof(gpioh_item_t));
1374 gi->event = event;
1375 gi->handler = cb;
1376 gi->arg = arg;
1377 gi->level = level;
1378
1379 gi->next = sii->gpioh_head;
1380 sii->gpioh_head = gi;
1381
1382 return (void *)(gi);
1383}
1384
1385void
1386si_gpio_handler_unregister(si_t *sih, void *gpioh)
1387{
1388 si_info_t *sii;
1389 gpioh_item_t *p, *n;
1390
1391 sii = SI_INFO(sih);
1392 if (sih->ccrev < 11)
1393 return;
1394
1395 ASSERT(sii->gpioh_head != NULL);
1396 if ((void*)sii->gpioh_head == gpioh) {
1397 sii->gpioh_head = sii->gpioh_head->next;
1398 MFREE(sii->osh, gpioh, sizeof(gpioh_item_t));
1399 return;
1400 } else {
1401 p = sii->gpioh_head;
1402 n = p->next;
1403 while (n) {
1404 if ((void*)n == gpioh) {
1405 p->next = n->next;
1406 MFREE(sii->osh, gpioh, sizeof(gpioh_item_t));
1407 return;
1408 }
1409 p = n;
1410 n = n->next;
1411 }
1412 }
1413
1414 ASSERT(0); /* Not found in list */
1415}
1416
1417void
1418si_gpio_handler_process(si_t *sih)
1419{
1420 si_info_t *sii;
1421 gpioh_item_t *h;
1422 uint32 level = si_gpioin(sih);
1423 uint32 levelp = si_gpiointpolarity(sih, 0, 0, 0);
1424 uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0);
1425 uint32 edgep = si_gpioevent(sih, GPIO_REGEVT_INTPOL, 0, 0);
1426
1427 sii = SI_INFO(sih);
1428 for (h = sii->gpioh_head; h != NULL; h = h->next) {
1429 if (h->handler) {
1430 uint32 status = (h->level ? level : edge) & h->event;
1431 uint32 polarity = (h->level ? levelp : edgep) & h->event;
1432
1433 /* polarity bitval is opposite of status bitval */
1434 if (status ^ polarity)
1435 h->handler(status, h->arg);
1436 }
1437 }
1438
1439 si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */
1440}
1441
1442uint32
1443si_gpio_int_enable(si_t *sih, bool enable)
1444{
1445 si_info_t *sii;
1446 uint offs;
1447
1448 sii = SI_INFO(sih);
1449 if (sih->ccrev < 11)
1450 return 0xffffffff;
1451
1452 offs = OFFSETOF(chipcregs_t, intmask);
1453 return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0)));
1454}
1455
1456
1457/* Return the size of the specified SOCRAM bank */
1458static uint
1459socram_banksize(si_info_t *sii, sbsocramregs_t *regs, uint8 index, uint8 mem_type)
1460{
1461 uint banksize, bankinfo;
1462 uint bankidx = index | (mem_type << SOCRAM_BANKIDX_MEMTYPE_SHIFT);
1463
1464 ASSERT(mem_type <= SOCRAM_MEMTYPE_DEVRAM);
1465
1466 W_REG(sii->osh, &regs->bankidx, bankidx);
1467 bankinfo = R_REG(sii->osh, &regs->bankinfo);
1468 banksize = SOCRAM_BANKINFO_SZBASE * ((bankinfo & SOCRAM_BANKINFO_SZMASK) + 1);
1469 return banksize;
1470}
1471
1472void
1473si_socdevram(si_t *sih, bool set, uint8 *enable, uint8 *protect)
1474{
1475 si_info_t *sii;
1476 uint origidx;
1477 uint intr_val = 0;
1478 sbsocramregs_t *regs;
1479 bool wasup;
1480 uint corerev;
1481
1482 sii = SI_INFO(sih);
1483
1484 /* Block ints and save current core */
1485 INTR_OFF(sii, intr_val);
1486 origidx = si_coreidx(sih);
1487
1488 if (!set)
1489 *enable = *protect = 0;
1490
1491 /* Switch to SOCRAM core */
1492 if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0)))
1493 goto done;
1494
1495 /* Get info for determining size */
1496 if (!(wasup = si_iscoreup(sih)))
1497 si_core_reset(sih, 0, 0);
1498
1499 corerev = si_corerev(sih);
1500 if (corerev >= 10) {
1501 uint32 extcinfo;
1502 uint8 nb;
1503 uint8 i;
1504 uint32 bankidx, bankinfo;
1505
1506 extcinfo = R_REG(sii->osh, &regs->extracoreinfo);
1507 nb = ((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT);
1508 for (i = 0; i < nb; i++) {
1509 bankidx = i | (SOCRAM_MEMTYPE_DEVRAM << SOCRAM_BANKIDX_MEMTYPE_SHIFT);
1510 W_REG(sii->osh, &regs->bankidx, bankidx);
1511 bankinfo = R_REG(sii->osh, &regs->bankinfo);
1512 if (set) {
1513 bankinfo &= ~SOCRAM_BANKINFO_DEVRAMSEL_MASK;
1514 bankinfo &= ~SOCRAM_BANKINFO_DEVRAMPRO_MASK;
1515 if (*enable) {
1516 bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMSEL_SHIFT);
1517 if (*protect)
1518 bankinfo |= (1 << SOCRAM_BANKINFO_DEVRAMPRO_SHIFT);
1519 }
1520 W_REG(sii->osh, &regs->bankinfo, bankinfo);
1521 }
1522 else if (i == 0) {
1523 if (bankinfo & SOCRAM_BANKINFO_DEVRAMSEL_MASK) {
1524 *enable = 1;
1525 if (bankinfo & SOCRAM_BANKINFO_DEVRAMPRO_MASK)
1526 *protect = 1;
1527 }
1528 }
1529 }
1530 }
1531
1532 /* Return to previous state and core */
1533 if (!wasup)
1534 si_core_disable(sih, 0);
1535 si_setcoreidx(sih, origidx);
1536
1537done:
1538 INTR_RESTORE(sii, intr_val);
1539}
1540
1541bool
1542si_socdevram_pkg(si_t *sih)
1543{
1544 if (si_socdevram_size(sih) > 0)
1545 return TRUE;
1546 else
1547 return FALSE;
1548}
1549
1550uint32
1551si_socdevram_size(si_t *sih)
1552{
1553 si_info_t *sii;
1554 uint origidx;
1555 uint intr_val = 0;
1556 uint32 memsize = 0;
1557 sbsocramregs_t *regs;
1558 bool wasup;
1559 uint corerev;
1560
1561 sii = SI_INFO(sih);
1562
1563 /* Block ints and save current core */
1564 INTR_OFF(sii, intr_val);
1565 origidx = si_coreidx(sih);
1566
1567 /* Switch to SOCRAM core */
1568 if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0)))
1569 goto done;
1570
1571 /* Get info for determining size */
1572 if (!(wasup = si_iscoreup(sih)))
1573 si_core_reset(sih, 0, 0);
1574
1575 corerev = si_corerev(sih);
1576 if (corerev >= 10) {
1577 uint32 extcinfo;
1578 uint8 nb;
1579 uint8 i;
1580
1581 extcinfo = R_REG(sii->osh, &regs->extracoreinfo);
1582 nb = (((extcinfo & SOCRAM_DEVRAMBANK_MASK) >> SOCRAM_DEVRAMBANK_SHIFT));
1583 for (i = 0; i < nb; i++)
1584 memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_DEVRAM);
1585 }
1586
1587 /* Return to previous state and core */
1588 if (!wasup)
1589 si_core_disable(sih, 0);
1590 si_setcoreidx(sih, origidx);
1591
1592done:
1593 INTR_RESTORE(sii, intr_val);
1594
1595 return memsize;
1596}
1597
1598/* Return the RAM size of the SOCRAM core */
1599uint32
1600si_socram_size(si_t *sih)
1601{
1602 si_info_t *sii;
1603 uint origidx;
1604 uint intr_val = 0;
1605
1606 sbsocramregs_t *regs;
1607 bool wasup;
1608 uint corerev;
1609 uint32 coreinfo;
1610 uint memsize = 0;
1611
1612 sii = SI_INFO(sih);
1613
1614 /* Block ints and save current core */
1615 INTR_OFF(sii, intr_val);
1616 origidx = si_coreidx(sih);
1617
1618 /* Switch to SOCRAM core */
1619 if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0)))
1620 goto done;
1621
1622 /* Get info for determining size */
1623 if (!(wasup = si_iscoreup(sih)))
1624 si_core_reset(sih, 0, 0);
1625 corerev = si_corerev(sih);
1626 coreinfo = R_REG(sii->osh, &regs->coreinfo);
1627
1628 /* Calculate size from coreinfo based on rev */
1629 if (corerev == 0)
1630 memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK));
1631 else if (corerev < 3) {
1632 memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK));
1633 memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
1634 } else if ((corerev <= 7) || (corerev == 12)) {
1635 uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
1636 uint bsz = (coreinfo & SRCI_SRBSZ_MASK);
1637 uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT;
1638 if (lss != 0)
1639 nb --;
1640 memsize = nb * (1 << (bsz + SR_BSZ_BASE));
1641 if (lss != 0)
1642 memsize += (1 << ((lss - 1) + SR_BSZ_BASE));
1643 } else {
1644 uint8 i;
1645 uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
1646 for (i = 0; i < nb; i++)
1647 memsize += socram_banksize(sii, regs, i, SOCRAM_MEMTYPE_RAM);
1648 }
1649
1650 /* Return to previous state and core */
1651 if (!wasup)
1652 si_core_disable(sih, 0);
1653 si_setcoreidx(sih, origidx);
1654
1655done:
1656 INTR_RESTORE(sii, intr_val);
1657
1658 return memsize;
1659}
1660
1661
1662void
1663si_btcgpiowar(si_t *sih)
1664{
1665 si_info_t *sii;
1666 uint origidx;
1667 uint intr_val = 0;
1668 chipcregs_t *cc;
1669
1670 sii = SI_INFO(sih);
1671
1672 /* Make sure that there is ChipCommon core present &&
1673 * UART_TX is strapped to 1
1674 */
1675 if (!(sih->cccaps & CC_CAP_UARTGPIO))
1676 return;
1677
1678 /* si_corereg cannot be used as we have to guarantee 8-bit read/writes */
1679 INTR_OFF(sii, intr_val);
1680
1681 origidx = si_coreidx(sih);
1682
1683 cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
1684 ASSERT(cc != NULL);
1685
1686 W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04);
1687
1688 /* restore the original index */
1689 si_setcoreidx(sih, origidx);
1690
1691 INTR_RESTORE(sii, intr_val);
1692}
1693
1694uint
1695si_pll_reset(si_t *sih)
1696{
1697 uint err = 0;
1698
1699 return (err);
1700}
1701
1702/* check if the device is removed */
1703bool
1704si_deviceremoved(si_t *sih)
1705{
1706 uint32 w;
1707 si_info_t *sii;
1708
1709 sii = SI_INFO(sih);
1710
1711 switch (BUSTYPE(sih->bustype)) {
1712 case PCI_BUS:
1713 ASSERT(sii->osh != NULL);
1714 w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_VID, sizeof(uint32));
1715 if ((w & 0xFFFF) != VENDOR_BROADCOM)
1716 return TRUE;
1717 break;
1718 }
1719 return FALSE;
1720}
diff --git a/drivers/net/wireless/bcmdhd/siutils_priv.h b/drivers/net/wireless/bcmdhd/siutils_priv.h
new file mode 100644
index 00000000000..d80246e01d1
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/siutils_priv.h
@@ -0,0 +1,235 @@
1/*
2 * Include file private to the SOC Interconnect support files.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: siutils_priv.h,v 1.17.4.3 2010-10-25 16:56:56 Exp $
25 */
26
27#ifndef _siutils_priv_h_
28#define _siutils_priv_h_
29
30#define SI_ERROR(args)
31
32#define SI_MSG(args)
33
34/* Define SI_VMSG to printf for verbose debugging, but don't check it in */
35#define SI_VMSG(args)
36
37#define IS_SIM(chippkg) ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID))
38
39typedef uint32 (*si_intrsoff_t)(void *intr_arg);
40typedef void (*si_intrsrestore_t)(void *intr_arg, uint32 arg);
41typedef bool (*si_intrsenabled_t)(void *intr_arg);
42
43typedef struct gpioh_item {
44 void *arg;
45 bool level;
46 gpio_handler_t handler;
47 uint32 event;
48 struct gpioh_item *next;
49} gpioh_item_t;
50
51/* misc si info needed by some of the routines */
52typedef struct si_info {
53 struct si_pub pub; /* back plane public state (must be first field) */
54
55 void *osh; /* osl os handle */
56 void *sdh; /* bcmsdh handle */
57
58 uint dev_coreid; /* the core provides driver functions */
59 void *intr_arg; /* interrupt callback function arg */
60 si_intrsoff_t intrsoff_fn; /* turns chip interrupts off */
61 si_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */
62 si_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */
63
64 void *pch; /* PCI/E core handle */
65
66 gpioh_item_t *gpioh_head; /* GPIO event handlers list */
67
68 bool memseg; /* flag to toggle MEM_SEG register */
69
70 char *vars;
71 uint varsz;
72
73 void *curmap; /* current regs va */
74 void *regs[SI_MAXCORES]; /* other regs va */
75
76 uint curidx; /* current core index */
77 uint numcores; /* # discovered cores */
78 uint coreid[SI_MAXCORES]; /* id of each core */
79 uint32 coresba[SI_MAXCORES]; /* backplane address of each core */
80 void *regs2[SI_MAXCORES]; /* va of each core second register set (usbh20) */
81 uint32 coresba2[SI_MAXCORES]; /* address of each core second register set (usbh20) */
82 uint32 coresba_size[SI_MAXCORES]; /* backplane address space size */
83 uint32 coresba2_size[SI_MAXCORES]; /* second address space size */
84
85 void *curwrap; /* current wrapper va */
86 void *wrappers[SI_MAXCORES]; /* other cores wrapper va */
87 uint32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */
88
89 uint32 cia[SI_MAXCORES]; /* erom cia entry for each core */
90 uint32 cib[SI_MAXCORES]; /* erom cia entry for each core */
91 uint32 oob_router; /* oob router registers for axi */
92} si_info_t;
93
94#define SI_INFO(sih) (si_info_t *)(uintptr)sih
95
96#define GOODCOREADDR(x, b) (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \
97 ISALIGNED((x), SI_CORE_SIZE))
98#define GOODREGS(regs) ((regs) != NULL && ISALIGNED((uintptr)(regs), SI_CORE_SIZE))
99#define BADCOREADDR 0
100#define GOODIDX(idx) (((uint)idx) < SI_MAXCORES)
101#define NOREV -1 /* Invalid rev */
102
103#define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \
104 ((si)->pub.buscoretype == PCI_CORE_ID))
105#define PCIE(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \
106 ((si)->pub.buscoretype == PCIE_CORE_ID))
107#define PCMCIA(si) ((BUSTYPE((si)->pub.bustype) == PCMCIA_BUS) && ((si)->memseg == TRUE))
108
109/* Newer chips can access PCI/PCIE and CC core without requiring to change
110 * PCI BAR0 WIN
111 */
112#define SI_FAST(si) (((si)->pub.buscoretype == PCIE_CORE_ID) || \
113 (((si)->pub.buscoretype == PCI_CORE_ID) && (si)->pub.buscorerev >= 13))
114
115#define PCIEREGS(si) (((char *)((si)->curmap) + PCI_16KB0_PCIREGS_OFFSET))
116#define CCREGS_FAST(si) (((char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET))
117
118/*
119 * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts before/
120 * after core switching to avoid invalid register accesss inside ISR.
121 */
122#define INTR_OFF(si, intr_val) \
123 if ((si)->intrsoff_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \
124 intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); }
125#define INTR_RESTORE(si, intr_val) \
126 if ((si)->intrsrestore_fn && (si)->coreid[(si)->curidx] == (si)->dev_coreid) { \
127 (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); }
128
129/* dynamic clock control defines */
130#define LPOMINFREQ 25000 /* low power oscillator min */
131#define LPOMAXFREQ 43000 /* low power oscillator max */
132#define XTALMINFREQ 19800000 /* 20 MHz - 1% */
133#define XTALMAXFREQ 20200000 /* 20 MHz + 1% */
134#define PCIMINFREQ 25000000 /* 25 MHz */
135#define PCIMAXFREQ 34000000 /* 33 MHz + fudge */
136
137#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */
138#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */
139
140#define PCI_FORCEHT(si) \
141 (((PCIE(si)) && (si->pub.chip == BCM4311_CHIP_ID) && ((si->pub.chiprev <= 1))) || \
142 ((PCI(si) || PCIE(si)) && (si->pub.chip == BCM4321_CHIP_ID)) || \
143 (PCIE(si) && (si->pub.chip == BCM4716_CHIP_ID)))
144
145/* GPIO Based LED powersave defines */
146#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */
147#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */
148
149#ifndef DEFAULT_GPIOTIMERVAL
150#define DEFAULT_GPIOTIMERVAL ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME)
151#endif
152
153/* Silicon Backplane externs */
154extern void sb_scan(si_t *sih, void *regs, uint devid);
155extern uint sb_coreid(si_t *sih);
156extern uint sb_intflag(si_t *sih);
157extern uint sb_flag(si_t *sih);
158extern void sb_setint(si_t *sih, int siflag);
159extern uint sb_corevendor(si_t *sih);
160extern uint sb_corerev(si_t *sih);
161extern uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val);
162extern bool sb_iscoreup(si_t *sih);
163extern void *sb_setcoreidx(si_t *sih, uint coreidx);
164extern uint32 sb_core_cflags(si_t *sih, uint32 mask, uint32 val);
165extern void sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val);
166extern uint32 sb_core_sflags(si_t *sih, uint32 mask, uint32 val);
167extern void sb_commit(si_t *sih);
168extern uint32 sb_base(uint32 admatch);
169extern uint32 sb_size(uint32 admatch);
170extern void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits);
171extern void sb_core_disable(si_t *sih, uint32 bits);
172extern uint32 sb_addrspace(si_t *sih, uint asidx);
173extern uint32 sb_addrspacesize(si_t *sih, uint asidx);
174extern int sb_numaddrspaces(si_t *sih);
175
176extern uint32 sb_set_initiator_to(si_t *sih, uint32 to, uint idx);
177
178extern bool sb_taclear(si_t *sih, bool details);
179
180
181/* Wake-on-wireless-LAN (WOWL) */
182extern bool sb_pci_pmecap(si_t *sih);
183struct osl_info;
184extern bool sb_pci_fastpmecap(struct osl_info *osh);
185extern bool sb_pci_pmeclr(si_t *sih);
186extern void sb_pci_pmeen(si_t *sih);
187extern uint sb_pcie_readreg(void *sih, uint addrtype, uint offset);
188
189/* AMBA Interconnect exported externs */
190extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype,
191 void *sdh, char **vars, uint *varsz);
192extern si_t *ai_kattach(osl_t *osh);
193extern void ai_scan(si_t *sih, void *regs, uint devid);
194
195extern uint ai_flag(si_t *sih);
196extern void ai_setint(si_t *sih, int siflag);
197extern uint ai_coreidx(si_t *sih);
198extern uint ai_corevendor(si_t *sih);
199extern uint ai_corerev(si_t *sih);
200extern bool ai_iscoreup(si_t *sih);
201extern void *ai_setcoreidx(si_t *sih, uint coreidx);
202extern uint32 ai_core_cflags(si_t *sih, uint32 mask, uint32 val);
203extern void ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val);
204extern uint32 ai_core_sflags(si_t *sih, uint32 mask, uint32 val);
205extern uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val);
206extern void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits);
207extern void ai_core_disable(si_t *sih, uint32 bits);
208extern int ai_numaddrspaces(si_t *sih);
209extern uint32 ai_addrspace(si_t *sih, uint asidx);
210extern uint32 ai_addrspacesize(si_t *sih, uint asidx);
211extern uint ai_wrap_reg(si_t *sih, uint32 offset, uint32 mask, uint32 val);
212
213
214
215#define ub_scan(a, b, c) do {} while (0)
216#define ub_flag(a) (0)
217#define ub_setint(a, b) do {} while (0)
218#define ub_coreidx(a) (0)
219#define ub_corevendor(a) (0)
220#define ub_corerev(a) (0)
221#define ub_iscoreup(a) (0)
222#define ub_setcoreidx(a, b) (0)
223#define ub_core_cflags(a, b, c) (0)
224#define ub_core_cflags_wo(a, b, c) do {} while (0)
225#define ub_core_sflags(a, b, c) (0)
226#define ub_corereg(a, b, c, d, e) (0)
227#define ub_core_reset(a, b, c) do {} while (0)
228#define ub_core_disable(a, b) do {} while (0)
229#define ub_numaddrspaces(a) (0)
230#define ub_addrspace(a, b) (0)
231#define ub_addrspacesize(a, b) (0)
232#define ub_view(a, b) do {} while (0)
233#define ub_dumpregs(a, b) do {} while (0)
234
235#endif /* _siutils_priv_h_ */
diff --git a/drivers/net/wireless/bcmdhd/uamp_api.h b/drivers/net/wireless/bcmdhd/uamp_api.h
new file mode 100644
index 00000000000..c51c68cd0ee
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/uamp_api.h
@@ -0,0 +1,176 @@
1/*
2 * Name: uamp_api.h
3 *
4 * Description: Universal AMP API
5 *
6 * Copyright (C) 1999-2011, Broadcom Corporation
7 *
8 * Unless you and Broadcom execute a separate written software license
9 * agreement governing use of this software, this software is licensed to you
10 * under the terms of the GNU General Public License version 2 (the "GPL"),
11 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
12 * following added to such license:
13 *
14 * As a special exception, the copyright holders of this software give you
15 * permission to link this software with independent modules, and to copy and
16 * distribute the resulting executable under terms of your choice, provided that
17 * you also meet, for each linked independent module, the terms and conditions of
18 * the license of that module. An independent module is a module which is not
19 * derived from this software. The special exception does not apply to any
20 * modifications of the software.
21 *
22 * Notwithstanding the above, under no circumstances may you combine this
23 * software in any way with any other Broadcom software provided under a license
24 * other than the GPL, without Broadcom's express prior written consent.
25 *
26 * $Id: uamp_api.h,v 1.2.8.1 2011-02-05 00:16:14 Exp $
27 *
28 */
29#ifndef UAMP_API_H
30#define UAMP_API_H
31
32
33#include "typedefs.h"
34
35
36/*****************************************************************************
37** Constant and Type Definitions
38******************************************************************************
39*/
40
41#define BT_API
42
43/* Types. */
44typedef bool BOOLEAN;
45typedef uint8 UINT8;
46typedef uint16 UINT16;
47
48
49/* UAMP identifiers */
50#define UAMP_ID_1 1
51#define UAMP_ID_2 2
52typedef UINT8 tUAMP_ID;
53
54/* UAMP event ids (used by UAMP_CBACK) */
55#define UAMP_EVT_RX_READY 0 /* Data from AMP controller is ready to be read */
56#define UAMP_EVT_CTLR_REMOVED 1 /* Controller removed */
57#define UAMP_EVT_CTLR_READY 2 /* Controller added/ready */
58typedef UINT8 tUAMP_EVT;
59
60
61/* UAMP Channels */
62#define UAMP_CH_HCI_CMD 0 /* HCI Command channel */
63#define UAMP_CH_HCI_EVT 1 /* HCI Event channel */
64#define UAMP_CH_HCI_DATA 2 /* HCI ACL Data channel */
65typedef UINT8 tUAMP_CH;
66
67/* tUAMP_EVT_DATA: union for event-specific data, used by UAMP_CBACK */
68typedef union {
69 tUAMP_CH channel; /* UAMP_EVT_RX_READY: channel for which rx occured */
70} tUAMP_EVT_DATA;
71
72
73/*****************************************************************************
74**
75** Function: UAMP_CBACK
76**
77** Description: Callback for events. Register callback using UAMP_Init.
78**
79** Parameters amp_id: AMP device identifier that generated the event
80** amp_evt: event id
81** p_amp_evt_data: pointer to event-specific data
82**
83******************************************************************************
84*/
85typedef void (*tUAMP_CBACK)(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data);
86
87/*****************************************************************************
88** external function declarations
89******************************************************************************
90*/
91#ifdef __cplusplus
92extern "C"
93{
94#endif
95
96/*****************************************************************************
97**
98** Function: UAMP_Init
99**
100** Description: Initialize UAMP driver
101**
102** Parameters p_cback: Callback function for UAMP event notification
103**
104******************************************************************************
105*/
106BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback);
107
108
109/*****************************************************************************
110**
111** Function: UAMP_Open
112**
113** Description: Open connection to local AMP device.
114**
115** Parameters app_id: Application specific AMP identifer. This value
116** will be included in AMP messages sent to the
117** BTU task, to identify source of the message
118**
119******************************************************************************
120*/
121BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id);
122
123/*****************************************************************************
124**
125** Function: UAMP_Close
126**
127** Description: Close connection to local AMP device.
128**
129** Parameters app_id: Application specific AMP identifer.
130**
131******************************************************************************
132*/
133BT_API void UAMP_Close(tUAMP_ID amp_id);
134
135
136/*****************************************************************************
137**
138** Function: UAMP_Write
139**
140** Description: Send buffer to AMP device. Frees GKI buffer when done.
141**
142**
143** Parameters: app_id: AMP identifer.
144** p_buf: pointer to buffer to write
145** num_bytes: number of bytes to write
146** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_CMD
147**
148** Returns: number of bytes written
149**
150******************************************************************************
151*/
152BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel);
153
154/*****************************************************************************
155**
156** Function: UAMP_Read
157**
158** Description: Read incoming data from AMP. Call after receiving a
159** UAMP_EVT_RX_READY callback event.
160**
161** Parameters: app_id: AMP identifer.
162** p_buf: pointer to buffer for holding incoming AMP data
163** buf_size: size of p_buf
164** channel: UAMP_CH_HCI_ACL, or UAMP_CH_HCI_EVT
165**
166** Returns: number of bytes read
167**
168******************************************************************************
169*/
170BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel);
171
172#ifdef __cplusplus
173}
174#endif
175
176#endif /* UAMP_API_H */
diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c
new file mode 100644
index 00000000000..9ca3d602023
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_android.c
@@ -0,0 +1,840 @@
1/*
2 * Linux cfg80211 driver - Android related functions
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wl_android.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
25 */
26
27#include <linux/module.h>
28#include <linux/netdevice.h>
29
30#include <wl_android.h>
31#include <wldev_common.h>
32#include <wlioctl.h>
33#include <bcmutils.h>
34#include <linux_osl.h>
35#include <dhd_dbg.h>
36#include <dngl_stats.h>
37#include <dhd.h>
38#include <bcmsdbus.h>
39#ifdef WL_CFG80211
40#include <wl_cfg80211.h>
41#endif
42#if defined(CONFIG_WIFI_CONTROL_FUNC)
43#include <linux/platform_device.h>
44#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
45#include <linux/wlan_plat.h>
46#else
47#include <linux/wifi_tiwlan.h>
48#endif
49#endif /* CONFIG_WIFI_CONTROL_FUNC */
50
51/*
52 * Android private command strings, PLEASE define new private commands here
53 * so they can be updated easily in the future (if needed)
54 */
55
56#define CMD_START "START"
57#define CMD_STOP "STOP"
58#define CMD_SCAN_ACTIVE "SCAN-ACTIVE"
59#define CMD_SCAN_PASSIVE "SCAN-PASSIVE"
60#define CMD_RSSI "RSSI"
61#define CMD_LINKSPEED "LINKSPEED"
62#define CMD_RXFILTER_START "RXFILTER-START"
63#define CMD_RXFILTER_STOP "RXFILTER-STOP"
64#define CMD_RXFILTER_ADD "RXFILTER-ADD"
65#define CMD_RXFILTER_REMOVE "RXFILTER-REMOVE"
66#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START"
67#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
68#define CMD_BTCOEXMODE "BTCOEXMODE"
69#define CMD_SETSUSPENDOPT "SETSUSPENDOPT"
70#define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR"
71#define CMD_SETFWPATH "SETFWPATH"
72#define CMD_SETBAND "SETBAND"
73#define CMD_GETBAND "GETBAND"
74#define CMD_COUNTRY "COUNTRY"
75#define CMD_P2P_SET_NOA "P2P_SET_NOA"
76#define CMD_P2P_GET_NOA "P2P_GET_NOA"
77#define CMD_P2P_SET_PS "P2P_SET_PS"
78#define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE"
79
80
81#ifdef PNO_SUPPORT
82#define CMD_PNOSSIDCLR_SET "PNOSSIDCLR"
83#define CMD_PNOSETUP_SET "PNOSETUP "
84#define CMD_PNOENABLE_SET "PNOFORCE"
85#define CMD_PNODEBUG_SET "PNODEBUG"
86
87#define PNO_TLV_PREFIX 'S'
88#define PNO_TLV_VERSION '1'
89#define PNO_TLV_SUBVERSION '2'
90#define PNO_TLV_RESERVED '0'
91#define PNO_TLV_TYPE_SSID_IE 'S'
92#define PNO_TLV_TYPE_TIME 'T'
93#define PNO_TLV_FREQ_REPEAT 'R'
94#define PNO_TLV_FREQ_EXPO_MAX 'M'
95
96typedef struct cmd_tlv {
97 char prefix;
98 char version;
99 char subver;
100 char reserved;
101} cmd_tlv_t;
102#endif /* PNO_SUPPORT */
103
104typedef struct android_wifi_priv_cmd {
105 char *buf;
106 int used_len;
107 int total_len;
108} android_wifi_priv_cmd;
109
110/**
111 * Extern function declarations (TODO: move them to dhd_linux.h)
112 */
113void dhd_customer_gpio_wlan_ctrl(int onoff);
114uint dhd_dev_reset(struct net_device *dev, uint8 flag);
115void dhd_dev_init_ioctl(struct net_device *dev);
116#ifdef WL_CFG80211
117int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
118int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command);
119#else
120int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
121{ return 0; }
122int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
123{ return 0; }
124int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
125{ return 0; }
126int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
127{ return 0; }
128#endif
129extern int dhd_os_check_if_up(void *dhdp);
130extern void *bcmsdh_get_drvdata(void);
131
132extern bool ap_fw_loaded;
133#ifdef CUSTOMER_HW2
134extern char iface_name[IFNAMSIZ];
135#endif
136
137/**
138 * Local (static) functions and variables
139 */
140
141/* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
142 * time (only) in dhd_open, subsequential wifi on will be handled by
143 * wl_android_wifi_on
144 */
145static int g_wifi_on = TRUE;
146
147/**
148 * Local (static) function definitions
149 */
150static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
151{
152 int link_speed;
153 int bytes_written;
154 int error;
155
156 error = wldev_get_link_speed(net, &link_speed);
157 if (error)
158 return -1;
159
160 /* Convert Kbps to Android Mbps */
161 link_speed = link_speed / 1000;
162 bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
163 DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command));
164 return bytes_written;
165}
166
167static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
168{
169 wlc_ssid_t ssid = {0};
170 int rssi;
171 int bytes_written = 0;
172 int error;
173
174 error = wldev_get_rssi(net, &rssi);
175 if (error)
176 return -1;
177
178 error = wldev_get_ssid(net, &ssid);
179 if (error)
180 return -1;
181 if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
182 DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__));
183 } else {
184 memcpy(command, ssid.SSID, ssid.SSID_len);
185 bytes_written = ssid.SSID_len;
186 }
187 bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", rssi);
188 DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written));
189 return bytes_written;
190}
191
192static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len)
193{
194 int suspend_flag;
195 int ret_now;
196 int ret = 0;
197
198 suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
199
200 if (suspend_flag != 0)
201 suspend_flag = 1;
202 ret_now = net_os_set_suspend_disable(dev, suspend_flag);
203
204 if (ret_now != suspend_flag) {
205 if (!(ret = net_os_set_suspend(dev, ret_now)))
206 DHD_INFO(("%s: Suspend Flag %d -> %d\n",
207 __FUNCTION__, ret_now, suspend_flag));
208 else
209 DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
210 }
211 return ret;
212}
213
214static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
215{
216 uint band;
217 int bytes_written;
218 int error;
219
220 error = wldev_get_band(dev, &band);
221 if (error)
222 return -1;
223 bytes_written = snprintf(command, total_len, "Band %d", band);
224 return bytes_written;
225}
226
227#ifdef PNO_SUPPORT
228static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
229{
230 wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
231 int res = -1;
232 int nssid = 0;
233 cmd_tlv_t *cmd_tlv_temp;
234 char *str_ptr;
235 int tlv_size_left;
236 int pno_time = 0;
237 int pno_repeat = 0;
238 int pno_freq_expo_max = 0;
239
240#ifdef PNO_SET_DEBUG
241 int i;
242 char pno_in_example[] = {
243 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
244 'S', '1', '2', '0',
245 'S',
246 0x05,
247 'd', 'l', 'i', 'n', 'k',
248 'S',
249 0x04,
250 'G', 'O', 'O', 'G',
251 'T',
252 '0', 'B',
253 'R',
254 '2',
255 'M',
256 '2',
257 0x00
258 };
259#endif /* PNO_SET_DEBUG */
260
261 DHD_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
262
263 if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
264 DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
265 goto exit_proc;
266 }
267
268#ifdef PNO_SET_DEBUG
269 memcpy(command, pno_in_example, sizeof(pno_in_example));
270 for (i = 0; i < sizeof(pno_in_example); i++)
271 printf("%02X ", command[i]);
272 printf("\n");
273 total_len = sizeof(pno_in_example);
274#endif
275
276 str_ptr = command + strlen(CMD_PNOSETUP_SET);
277 tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
278
279 cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
280 memset(ssids_local, 0, sizeof(ssids_local));
281
282 if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
283 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
284 (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) {
285
286 str_ptr += sizeof(cmd_tlv_t);
287 tlv_size_left -= sizeof(cmd_tlv_t);
288
289 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
290 MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
291 DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
292 goto exit_proc;
293 } else {
294 if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
295 DHD_ERROR(("%s scan duration corrupted field size %d\n",
296 __FUNCTION__, tlv_size_left));
297 goto exit_proc;
298 }
299 str_ptr++;
300 pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
301 DHD_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
302
303 if (str_ptr[0] != 0) {
304 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
305 DHD_ERROR(("%s pno repeat : corrupted field\n",
306 __FUNCTION__));
307 goto exit_proc;
308 }
309 str_ptr++;
310 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
311 DHD_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
312 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
313 DHD_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n",
314 __FUNCTION__));
315 goto exit_proc;
316 }
317 str_ptr++;
318 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
319 DHD_INFO(("%s: pno_freq_expo_max=%d\n",
320 __FUNCTION__, pno_freq_expo_max));
321 }
322 }
323 } else {
324 DHD_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
325 goto exit_proc;
326 }
327
328 res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
329
330exit_proc:
331 return res;
332}
333#endif /* PNO_SUPPORT */
334
335static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
336{
337 int ret;
338 int bytes_written = 0;
339
340 ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command);
341 if (ret)
342 return 0;
343 bytes_written = sizeof(struct ether_addr);
344 return bytes_written;
345}
346
347/**
348 * Global function definitions (declared in wl_android.h)
349 */
350
351int wl_android_wifi_on(struct net_device *dev)
352{
353 int ret = 0;
354
355 printk("%s in\n", __FUNCTION__);
356 if (!dev) {
357 DHD_ERROR(("%s: dev is null\n", __FUNCTION__));
358 return -EINVAL;
359 }
360
361 dhd_net_if_lock(dev);
362 if (!g_wifi_on) {
363 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
364 sdioh_start(NULL, 0);
365 ret = dhd_dev_reset(dev, FALSE);
366 sdioh_start(NULL, 1);
367 if (!ret)
368 dhd_dev_init_ioctl(dev);
369 g_wifi_on = 1;
370 }
371 dhd_net_if_unlock(dev);
372
373 return ret;
374}
375
376int wl_android_wifi_off(struct net_device *dev)
377{
378 int ret = 0;
379
380 printk("%s in\n", __FUNCTION__);
381 if (!dev) {
382 DHD_TRACE(("%s: dev is null\n", __FUNCTION__));
383 return -EINVAL;
384 }
385
386 dhd_net_if_lock(dev);
387 if (g_wifi_on) {
388 ret = dhd_dev_reset(dev, TRUE);
389 sdioh_stop(NULL);
390 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
391 g_wifi_on = 0;
392 }
393 dhd_net_if_unlock(dev);
394
395 return ret;
396}
397
398static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
399{
400 if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
401 return -1;
402 bcm_strncpy_s(fw_path, sizeof(fw_path),
403 command + strlen(CMD_SETFWPATH) + 1, MOD_PARAM_PATHLEN - 1);
404 if (strstr(fw_path, "apsta") != NULL) {
405 DHD_INFO(("GOT APSTA FIRMWARE\n"));
406 ap_fw_loaded = TRUE;
407 } else {
408 DHD_INFO(("GOT STA FIRMWARE\n"));
409 ap_fw_loaded = FALSE;
410 }
411 return 0;
412}
413
414int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
415{
416 int ret = 0;
417 char *command = NULL;
418 int bytes_written = 0;
419 android_wifi_priv_cmd priv_cmd;
420
421 net_os_wake_lock(net);
422
423 if (!ifr->ifr_data) {
424 ret = -EINVAL;
425 goto exit;
426 }
427 if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
428 ret = -EFAULT;
429 goto exit;
430 }
431 command = kmalloc(priv_cmd.total_len, GFP_KERNEL);
432 if (!command)
433 {
434 DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
435 ret = -ENOMEM;
436 goto exit;
437 }
438 if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
439 ret = -EFAULT;
440 goto exit;
441 }
442
443 DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
444
445 if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
446 DHD_INFO(("%s, Received regular START command\n", __FUNCTION__));
447 bytes_written = wl_android_wifi_on(net);
448 }
449 else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
450 bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
451 }
452
453 if (!g_wifi_on) {
454 DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n",
455 __FUNCTION__, command, ifr->ifr_name));
456 ret = 0;
457 goto exit;
458 }
459
460 if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
461 bytes_written = wl_android_wifi_off(net);
462 }
463 else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
464 /* TBD: SCAN-ACTIVE */
465 }
466 else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
467 /* TBD: SCAN-PASSIVE */
468 }
469 else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
470 bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
471 }
472 else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
473 bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
474 }
475 else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
476 bytes_written = net_os_set_packet_filter(net, 1);
477 }
478 else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
479 bytes_written = net_os_set_packet_filter(net, 0);
480 }
481 else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
482 int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
483 bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
484 }
485 else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
486 int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
487 bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
488 }
489 else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
490 /* TBD: BTCOEXSCAN-START */
491 }
492 else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
493 /* TBD: BTCOEXSCAN-STOP */
494 }
495 else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
496 uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
497
498 if (mode == 1)
499 net_os_set_packet_filter(net, 0); /* DHCP starts */
500 else
501 net_os_set_packet_filter(net, 1); /* DHCP ends */
502#ifdef WL_CFG80211
503 bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
504#endif
505 }
506 else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
507 bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
508 }
509 else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
510 uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
511 bytes_written = wldev_set_band(net, band);
512 }
513 else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
514 bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
515 }
516 else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
517 char *country_code = command + strlen(CMD_COUNTRY) + 1;
518 bytes_written = wldev_set_country(net, country_code);
519 }
520#ifdef PNO_SUPPORT
521 else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
522 bytes_written = dhd_dev_pno_reset(net);
523 }
524 else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
525 bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
526 }
527 else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
528 uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
529 bytes_written = dhd_dev_pno_enable(net, pfn_enabled);
530 }
531#endif
532 else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
533 bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
534 }
535 else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
536 int skip = strlen(CMD_P2P_SET_NOA) + 1;
537 bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
538 priv_cmd.total_len - skip);
539 }
540 else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
541 bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
542 }
543 else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
544 int skip = strlen(CMD_P2P_SET_PS) + 1;
545 bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
546 priv_cmd.total_len - skip);
547 }
548#ifdef WL_CFG80211
549 else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
550 strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
551 int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
552 bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
553 priv_cmd.total_len - skip, *(command + skip - 2) - '0');
554 }
555#endif /* WL_CFG80211 */
556 else {
557 DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
558 snprintf(command, 3, "OK");
559 bytes_written = strlen("OK");
560 }
561
562 if (bytes_written > 0) {
563 if (bytes_written > priv_cmd.total_len) {
564 DHD_ERROR(("%s: bytes_written = %d\n", __FUNCTION__, bytes_written));
565 bytes_written = priv_cmd.total_len;
566 } else {
567 bytes_written++;
568 }
569 priv_cmd.used_len = bytes_written;
570 if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
571 DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
572 ret = -EFAULT;
573 }
574 } else {
575 ret = bytes_written;
576 }
577
578exit:
579 net_os_wake_unlock(net);
580 if (command) {
581 kfree(command);
582 }
583
584 return ret;
585}
586
587int wl_android_init(void)
588{
589 int ret = 0;
590
591 dhd_msg_level = DHD_ERROR_VAL;
592#ifdef ENABLE_INSMOD_NO_FW_LOAD
593 dhd_download_fw_on_driverload = FALSE;
594#endif /* ENABLE_INSMOD_NO_FW_LOAD */
595#ifdef CUSTOMER_HW2
596 if (!iface_name[0]) {
597 memset(iface_name, 0, IFNAMSIZ);
598 bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
599 }
600#endif /* CUSTOMER_HW2 */
601 return ret;
602}
603
604int wl_android_exit(void)
605{
606 int ret = 0;
607
608 return ret;
609}
610
611int wl_android_post_init(void)
612{
613 struct net_device *ndev;
614 int ret = 0;
615 char buf[IFNAMSIZ];
616 if (!dhd_download_fw_on_driverload) {
617 /* Call customer gpio to turn off power with WL_REG_ON signal */
618 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
619 g_wifi_on = 0;
620 } else {
621 memset(buf, 0, IFNAMSIZ);
622#ifdef CUSTOMER_HW2
623 snprintf(buf, IFNAMSIZ, "%s%d", iface_name, 0);
624#else
625 snprintf(buf, IFNAMSIZ, "%s%d", "eth", 0);
626#endif
627 if ((ndev = dev_get_by_name (&init_net, buf)) != NULL) {
628 dhd_dev_init_ioctl(ndev);
629 dev_put(ndev);
630 }
631 }
632 return ret;
633}
634
635/**
636 * Functions for Android WiFi card detection
637 */
638#if defined(CONFIG_WIFI_CONTROL_FUNC)
639
640static int g_wifidev_registered = 0;
641static struct semaphore wifi_control_sem;
642static struct wifi_platform_data *wifi_control_data = NULL;
643static struct resource *wifi_irqres = NULL;
644
645static int wifi_add_dev(void);
646static void wifi_del_dev(void);
647
648int wl_android_wifictrl_func_add(void)
649{
650 int ret = 0;
651 sema_init(&wifi_control_sem, 0);
652
653 ret = wifi_add_dev();
654 if (ret) {
655 DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__));
656 return ret;
657 }
658 g_wifidev_registered = 1;
659
660 /* Waiting callback after platform_driver_register is done or exit with error */
661 if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) {
662 ret = -EINVAL;
663 DHD_ERROR(("%s: platform_driver_register timeout\n", __FUNCTION__));
664 }
665
666 return ret;
667}
668
669void wl_android_wifictrl_func_del(void)
670{
671 if (g_wifidev_registered)
672 {
673 wifi_del_dev();
674 g_wifidev_registered = 0;
675 }
676}
677
678void* wl_android_prealloc(int section, unsigned long size)
679{
680 void *alloc_ptr = NULL;
681 if (wifi_control_data && wifi_control_data->mem_prealloc) {
682 alloc_ptr = wifi_control_data->mem_prealloc(section, size);
683 if (alloc_ptr) {
684 DHD_INFO(("success alloc section %d\n", section));
685 bzero(alloc_ptr, size);
686 return alloc_ptr;
687 }
688 }
689
690 DHD_ERROR(("can't alloc section %d\n", section));
691 return 0;
692}
693
694int wifi_get_irq_number(unsigned long *irq_flags_ptr)
695{
696 if (wifi_irqres) {
697 *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK;
698 return (int)wifi_irqres->start;
699 }
700#ifdef CUSTOM_OOB_GPIO_NUM
701 return CUSTOM_OOB_GPIO_NUM;
702#else
703 return -1;
704#endif
705}
706
707int wifi_set_power(int on, unsigned long msec)
708{
709 DHD_ERROR(("%s = %d\n", __FUNCTION__, on));
710 if (wifi_control_data && wifi_control_data->set_power) {
711 wifi_control_data->set_power(on);
712 }
713 if (msec)
714 msleep(msec);
715 return 0;
716}
717
718#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
719int wifi_get_mac_addr(unsigned char *buf)
720{
721 DHD_ERROR(("%s\n", __FUNCTION__));
722 if (!buf)
723 return -EINVAL;
724 if (wifi_control_data && wifi_control_data->get_mac_addr) {
725 return wifi_control_data->get_mac_addr(buf);
726 }
727 return -EOPNOTSUPP;
728}
729#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */
730
731#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
732void *wifi_get_country_code(char *ccode)
733{
734 DHD_TRACE(("%s\n", __FUNCTION__));
735 if (!ccode)
736 return NULL;
737 if (wifi_control_data && wifi_control_data->get_country_code) {
738 return wifi_control_data->get_country_code(ccode);
739 }
740 return NULL;
741}
742#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
743
744static int wifi_set_carddetect(int on)
745{
746 DHD_ERROR(("%s = %d\n", __FUNCTION__, on));
747 if (wifi_control_data && wifi_control_data->set_carddetect) {
748 wifi_control_data->set_carddetect(on);
749 }
750 return 0;
751}
752
753static int wifi_probe(struct platform_device *pdev)
754{
755 struct wifi_platform_data *wifi_ctrl =
756 (struct wifi_platform_data *)(pdev->dev.platform_data);
757
758 DHD_ERROR(("## %s\n", __FUNCTION__));
759 wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
760 if (wifi_irqres == NULL)
761 wifi_irqres = platform_get_resource_byname(pdev,
762 IORESOURCE_IRQ, "bcm4329_wlan_irq");
763 wifi_control_data = wifi_ctrl;
764
765 wifi_set_power(1, 0); /* Power On */
766 wifi_set_carddetect(1); /* CardDetect (0->1) */
767
768 up(&wifi_control_sem);
769 return 0;
770}
771
772static int wifi_remove(struct platform_device *pdev)
773{
774 struct wifi_platform_data *wifi_ctrl =
775 (struct wifi_platform_data *)(pdev->dev.platform_data);
776
777 DHD_ERROR(("## %s\n", __FUNCTION__));
778 wifi_control_data = wifi_ctrl;
779
780 wifi_set_power(0, 0); /* Power Off */
781 wifi_set_carddetect(0); /* CardDetect (1->0) */
782
783 up(&wifi_control_sem);
784 return 0;
785}
786
787static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
788{
789 DHD_TRACE(("##> %s\n", __FUNCTION__));
790#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
791 bcmsdh_oob_intr_set(0);
792#endif
793 return 0;
794}
795
796static int wifi_resume(struct platform_device *pdev)
797{
798 DHD_TRACE(("##> %s\n", __FUNCTION__));
799#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
800 if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
801 bcmsdh_oob_intr_set(1);
802#endif
803 return 0;
804}
805
806static struct platform_driver wifi_device = {
807 .probe = wifi_probe,
808 .remove = wifi_remove,
809 .suspend = wifi_suspend,
810 .resume = wifi_resume,
811 .driver = {
812 .name = "bcmdhd_wlan",
813 }
814};
815
816static struct platform_driver wifi_device_legacy = {
817 .probe = wifi_probe,
818 .remove = wifi_remove,
819 .suspend = wifi_suspend,
820 .resume = wifi_resume,
821 .driver = {
822 .name = "bcm4329_wlan",
823 }
824};
825
826static int wifi_add_dev(void)
827{
828 DHD_TRACE(("## Calling platform_driver_register\n"));
829 platform_driver_register(&wifi_device);
830 platform_driver_register(&wifi_device_legacy);
831 return 0;
832}
833
834static void wifi_del_dev(void)
835{
836 DHD_TRACE(("## Unregister platform_driver_register\n"));
837 platform_driver_unregister(&wifi_device);
838 platform_driver_unregister(&wifi_device_legacy);
839}
840#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
diff --git a/drivers/net/wireless/bcmdhd/wl_android.h b/drivers/net/wireless/bcmdhd/wl_android.h
new file mode 100644
index 00000000000..17373b7f6d5
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_android.h
@@ -0,0 +1,57 @@
1/*
2 * Linux cfg80211 driver - Android related functions
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wl_android.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
25 */
26
27#include <linux/module.h>
28#include <linux/netdevice.h>
29#include <wldev_common.h>
30
31/**
32 * Android platform dependent functions, feel free to add Android specific functions here
33 * (save the macros in dhd). Please do NOT declare functions that are NOT exposed to dhd
34 * or cfg, define them as static in wl_android.c
35 */
36
37/**
38 * wl_android_init will be called from module init function (dhd_module_init now), similarly
39 * wl_android_exit will be called from module exit function (dhd_module_cleanup now)
40 */
41int wl_android_init(void);
42int wl_android_exit(void);
43int wl_android_post_init(void);
44int wl_android_wifi_on(struct net_device *dev);
45int wl_android_wifi_off(struct net_device *dev);
46int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
47
48#if defined(CONFIG_WIFI_CONTROL_FUNC)
49int wl_android_wifictrl_func_add(void);
50void wl_android_wifictrl_func_del(void);
51void* wl_android_prealloc(int section, unsigned long size);
52
53int wifi_get_irq_number(unsigned long *irq_flags_ptr);
54int wifi_set_power(int on, unsigned long msec);
55int wifi_get_mac_addr(unsigned char *buf);
56void *wifi_get_country_code(char *ccode);
57#endif /* CONFIG_WIFI_CONTROL_FUNC */
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
new file mode 100644
index 00000000000..daa7d2605aa
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
@@ -0,0 +1,7330 @@
1/*
2 * Linux cfg80211 driver
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
25 */
26
27#include <typedefs.h>
28#include <linuxver.h>
29#include <osl.h>
30#include <linux/kernel.h>
31
32#include <bcmutils.h>
33#include <bcmwifi.h>
34#include <bcmendian.h>
35#include <proto/ethernet.h>
36#include <proto/802.11.h>
37#include <linux/if_arp.h>
38#include <asm/uaccess.h>
39
40#include <dngl_stats.h>
41#include <dhd.h>
42#include <dhdioctl.h>
43#include <wlioctl.h>
44
45#include <proto/ethernet.h>
46#include <dngl_stats.h>
47#include <dhd.h>
48#include <linux/kernel.h>
49#include <linux/kthread.h>
50#include <linux/netdevice.h>
51#include <linux/sched.h>
52#include <linux/etherdevice.h>
53#include <linux/wireless.h>
54#include <linux/ieee80211.h>
55#include <linux/wait.h>
56#include <net/cfg80211.h>
57
58#include <net/rtnetlink.h>
59#include <linux/mmc/sdio_func.h>
60#include <linux/firmware.h>
61#include <bcmsdbus.h>
62
63#include <wlioctl.h>
64#include <wldev_common.h>
65#include <wl_cfg80211.h>
66#include <wl_cfgp2p.h>
67
68static struct sdio_func *cfg80211_sdio_func;
69static struct wl_priv *wlcfg_drv_priv;
70
71u32 wl_dbg_level = WL_DBG_ERR;
72
73#define WL_4329_FW_FILE "brcm/bcm4329-fullmac-4-218-248-5.bin"
74#define WL_4329_NVRAM_FILE "brcm/bcm4329-fullmac-4-218-248-5.txt"
75#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
76#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
77#define MAX_WAIT_TIME 1500
78static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
79
80#define COEX_DHCP
81
82#if defined(COEX_DHCP)
83#define BT_DHCP_eSCO_FIX /* use New SCO/eSCO smart YG
84 * suppression
85 */
86#define BT_DHCP_USE_FLAGS /* this flag boost wifi pkt priority
87 * to max, caution: -not fair to sco
88 */
89#define BT_DHCP_OPPR_WIN_TIME 2500 /* T1 start SCO/ESCo priority
90 * suppression
91 */
92#define BT_DHCP_FLAG_FORCE_TIME 5500 /* T2 turn off SCO/SCO supperesion
93 * is (timeout)
94 */
95enum wl_cfg80211_btcoex_status {
96 BT_DHCP_IDLE,
97 BT_DHCP_START,
98 BT_DHCP_OPPR_WIN,
99 BT_DHCP_FLAG_FORCE_TIMEOUT
100};
101
102static int wl_cfg80211_btcoex_init(struct wl_priv *wl);
103static void wl_cfg80211_btcoex_deinit(struct wl_priv *wl);
104#endif
105
106/* This is to override regulatory domains defined in cfg80211 module (reg.c)
107 * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN
108 * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165).
109 * With respect to these flags, wpa_supplicant doesn't start p2p operations on 5GHz channels.
110 * All the chnages in world regulatory domain are to be done here.
111 */
112static const struct ieee80211_regdomain brcm_regdom = {
113 .n_reg_rules = 5,
114 .alpha2 = "99",
115 .reg_rules = {
116 /* IEEE 802.11b/g, channels 1..11 */
117 REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
118 /* IEEE 802.11b/g, channels 12..13. No HT40
119 * channel fits here.
120 */
121 REG_RULE(2467-10, 2472+10, 20, 6, 20,
122 NL80211_RRF_PASSIVE_SCAN |
123 NL80211_RRF_NO_IBSS),
124 /* IEEE 802.11 channel 14 - Only JP enables
125 * this and for 802.11b only
126 */
127 REG_RULE(2484-10, 2484+10, 20, 6, 20,
128 NL80211_RRF_PASSIVE_SCAN |
129 NL80211_RRF_NO_IBSS |
130 NL80211_RRF_NO_OFDM),
131 /* IEEE 802.11a, channel 36..64 */
132 REG_RULE(5150-10, 5350+10, 40, 6, 20, 0),
133 /* IEEE 802.11a, channel 100..165 */
134 REG_RULE(5470-10, 5850+10, 40, 6, 20, 0), }
135};
136
137
138/* Data Element Definitions */
139#define WPS_ID_CONFIG_METHODS 0x1008
140#define WPS_ID_REQ_TYPE 0x103A
141#define WPS_ID_DEVICE_NAME 0x1011
142#define WPS_ID_VERSION 0x104A
143#define WPS_ID_DEVICE_PWD_ID 0x1012
144#define WPS_ID_REQ_DEV_TYPE 0x106A
145#define WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS 0x1053
146#define WPS_ID_PRIM_DEV_TYPE 0x1054
147
148/* Device Password ID */
149#define DEV_PW_DEFAULT 0x0000
150#define DEV_PW_USER_SPECIFIED 0x0001,
151#define DEV_PW_MACHINE_SPECIFIED 0x0002
152#define DEV_PW_REKEY 0x0003
153#define DEV_PW_PUSHBUTTON 0x0004
154#define DEV_PW_REGISTRAR_SPECIFIED 0x0005
155
156/* Config Methods */
157#define WPS_CONFIG_USBA 0x0001
158#define WPS_CONFIG_ETHERNET 0x0002
159#define WPS_CONFIG_LABEL 0x0004
160#define WPS_CONFIG_DISPLAY 0x0008
161#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
162#define WPS_CONFIG_INT_NFC_TOKEN 0x0020
163#define WPS_CONFIG_NFC_INTERFACE 0x0040
164#define WPS_CONFIG_PUSHBUTTON 0x0080
165#define WPS_CONFIG_KEYPAD 0x0100
166#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
167#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
168#define WPS_CONFIG_VIRT_DISPLAY 0x2008
169#define WPS_CONFIG_PHY_DISPLAY 0x4008
170
171/*
172 * cfg80211_ops api/callback list
173 */
174static s32 wl_frame_get_mgmt(u16 fc, const struct ether_addr *da,
175 const struct ether_addr *sa, const struct ether_addr *bssid,
176 u8 **pheader, u32 *body_len, u8 *pbody);
177static s32 __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
178 struct cfg80211_scan_request *request,
179 struct cfg80211_ssid *this_ssid);
180static s32 wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
181 struct cfg80211_scan_request *request);
182static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed);
183static s32 wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
184 struct cfg80211_ibss_params *params);
185static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy,
186 struct net_device *dev);
187static s32 wl_cfg80211_get_station(struct wiphy *wiphy,
188 struct net_device *dev, u8 *mac,
189 struct station_info *sinfo);
190static s32 wl_cfg80211_set_power_mgmt(struct wiphy *wiphy,
191 struct net_device *dev, bool enabled,
192 s32 timeout);
193static int wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
194 struct cfg80211_connect_params *sme);
195static s32 wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
196 u16 reason_code);
197static s32 wl_cfg80211_set_tx_power(struct wiphy *wiphy,
198 enum nl80211_tx_power_setting type,
199 s32 dbm);
200static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm);
201static s32 wl_cfg80211_config_default_key(struct wiphy *wiphy,
202 struct net_device *dev,
203 u8 key_idx, bool unicast, bool multicast);
204static s32 wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
205 u8 key_idx, bool pairwise, const u8 *mac_addr,
206 struct key_params *params);
207static s32 wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
208 u8 key_idx, bool pairwise, const u8 *mac_addr);
209static s32 wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
210 u8 key_idx, bool pairwise, const u8 *mac_addr,
211 void *cookie, void (*callback) (void *cookie,
212 struct key_params *params));
213static s32 wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
214 struct net_device *dev, u8 key_idx);
215static s32 wl_cfg80211_resume(struct wiphy *wiphy);
216#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
217static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
218#else
219static s32 wl_cfg80211_suspend(struct wiphy *wiphy);
220#endif
221static s32 wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
222 struct cfg80211_pmksa *pmksa);
223static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
224 struct cfg80211_pmksa *pmksa);
225static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy,
226 struct net_device *dev);
227static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted);
228/*
229 * event & event Q handlers for cfg80211 interfaces
230 */
231static s32 wl_create_event_handler(struct wl_priv *wl);
232static void wl_destroy_event_handler(struct wl_priv *wl);
233static s32 wl_event_handler(void *data);
234static void wl_init_eq(struct wl_priv *wl);
235static void wl_flush_eq(struct wl_priv *wl);
236static unsigned long wl_lock_eq(struct wl_priv *wl);
237static void wl_unlock_eq(struct wl_priv *wl, unsigned long flags);
238static void wl_init_eq_lock(struct wl_priv *wl);
239static void wl_init_event_handler(struct wl_priv *wl);
240static struct wl_event_q *wl_deq_event(struct wl_priv *wl);
241static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 type,
242 const wl_event_msg_t *msg, void *data);
243static void wl_put_event(struct wl_event_q *e);
244static void wl_wakeup_event(struct wl_priv *wl);
245static s32 wl_notify_connect_status(struct wl_priv *wl,
246 struct net_device *ndev,
247 const wl_event_msg_t *e, void *data);
248static s32 wl_notify_roaming_status(struct wl_priv *wl,
249 struct net_device *ndev,
250 const wl_event_msg_t *e, void *data);
251static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
252 const wl_event_msg_t *e, void *data);
253static s32 wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
254 const wl_event_msg_t *e, void *data, bool completed);
255static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
256 const wl_event_msg_t *e, void *data);
257static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
258 const wl_event_msg_t *e, void *data);
259/*
260 * register/deregister sdio function
261 */
262struct sdio_func *wl_cfg80211_get_sdio_func(void);
263static void wl_clear_sdio_func(void);
264
265/*
266 * ioctl utilites
267 */
268static s32 wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
269 s32 buf_len);
270static __used s32 wl_dev_bufvar_set(struct net_device *dev, s8 *name,
271 s8 *buf, s32 len);
272static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val);
273static s32 wl_dev_intvar_get(struct net_device *dev, s8 *name,
274 s32 *retval);
275
276/*
277 * cfg80211 set_wiphy_params utilities
278 */
279static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold);
280static s32 wl_set_rts(struct net_device *dev, u32 frag_threshold);
281static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l);
282
283/*
284 * wl profile utilities
285 */
286static s32 wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e,
287 void *data, s32 item);
288static void *wl_read_prof(struct wl_priv *wl, s32 item);
289static void wl_init_prof(struct wl_priv *wl);
290
291/*
292 * cfg80211 connect utilites
293 */
294static s32 wl_set_wpa_version(struct net_device *dev,
295 struct cfg80211_connect_params *sme);
296static s32 wl_set_auth_type(struct net_device *dev,
297 struct cfg80211_connect_params *sme);
298static s32 wl_set_set_cipher(struct net_device *dev,
299 struct cfg80211_connect_params *sme);
300static s32 wl_set_key_mgmt(struct net_device *dev,
301 struct cfg80211_connect_params *sme);
302static s32 wl_set_set_sharedkey(struct net_device *dev,
303 struct cfg80211_connect_params *sme);
304static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev);
305static void wl_ch_to_chanspec(int ch,
306 struct wl_join_params *join_params, size_t *join_params_size);
307
308/*
309 * information element utilities
310 */
311static void wl_rst_ie(struct wl_priv *wl);
312static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v);
313static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size);
314static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size);
315static u32 wl_get_ielen(struct wl_priv *wl);
316
317static s32 wl_mode_to_nl80211_iftype(s32 mode);
318
319static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev);
320static void wl_free_wdev(struct wl_priv *wl);
321
322static s32 wl_inform_bss(struct wl_priv *wl);
323static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi);
324static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev);
325
326static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
327 u8 key_idx, const u8 *mac_addr,
328 struct key_params *params);
329/*
330 * key indianess swap utilities
331 */
332static void swap_key_from_BE(struct wl_wsec_key *key);
333static void swap_key_to_BE(struct wl_wsec_key *key);
334
335/*
336 * wl_priv memory init/deinit utilities
337 */
338static s32 wl_init_priv_mem(struct wl_priv *wl);
339static void wl_deinit_priv_mem(struct wl_priv *wl);
340
341static void wl_delay(u32 ms);
342
343/*
344 * ibss mode utilities
345 */
346static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev);
347static __used bool wl_is_ibssstarter(struct wl_priv *wl);
348
349/*
350 * dongle up/down , default configuration utilities
351 */
352static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e);
353static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev);
354static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e);
355static void wl_link_up(struct wl_priv *wl);
356static void wl_link_down(struct wl_priv *wl);
357static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype);
358static s32 __wl_cfg80211_up(struct wl_priv *wl);
359static s32 __wl_cfg80211_down(struct wl_priv *wl);
360static s32 wl_dongle_probecap(struct wl_priv *wl);
361static void wl_init_conf(struct wl_conf *conf);
362static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add);
363
364/*
365 * dongle configuration utilities
366 */
367#ifndef EMBEDDED_PLATFORM
368static s32 wl_dongle_country(struct net_device *ndev, u8 ccode);
369static s32 wl_dongle_up(struct net_device *ndev, u32 up);
370static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode);
371static s32 wl_dongle_glom(struct net_device *ndev, u32 glom,
372 u32 dongle_align);
373static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar,
374 u32 bcn_timeout);
375static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
376 s32 scan_unassoc_time);
377static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe,
378 s32 arp_ol);
379static s32 wl_pattern_atoh(s8 *src, s8 *dst);
380static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode);
381static s32 wl_update_wiphybands(struct wl_priv *wl);
382#endif /* !EMBEDDED_PLATFORM */
383static __used void wl_dongle_poweron(struct wl_priv *wl);
384static __used void wl_dongle_poweroff(struct wl_priv *wl);
385static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock);
386
387/*
388 * iscan handler
389 */
390static void wl_iscan_timer(unsigned long data);
391static void wl_term_iscan(struct wl_priv *wl);
392static s32 wl_init_scan(struct wl_priv *wl);
393static s32 wl_iscan_thread(void *data);
394static s32 wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request,
395 u16 action);
396static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request);
397static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan);
398static s32 wl_invoke_iscan(struct wl_priv *wl);
399static s32 wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status,
400 struct wl_scan_results **bss_list);
401static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted);
402static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan);
403static s32 wl_iscan_done(struct wl_priv *wl);
404static s32 wl_iscan_pending(struct wl_priv *wl);
405static s32 wl_iscan_inprogress(struct wl_priv *wl);
406static s32 wl_iscan_aborted(struct wl_priv *wl);
407
408/*
409 * fw/nvram downloading handler
410 */
411static void wl_init_fw(struct wl_fw_ctrl *fw);
412
413/*
414 * find most significant bit set
415 */
416static __used u32 wl_find_msb(u16 bit16);
417
418/*
419 * update pmklist to dongle
420 */
421static __used s32 wl_update_pmklist(struct net_device *dev,
422 struct wl_pmk_list *pmk_list, s32 err);
423
424/*
425 * debufs support
426 */
427static int wl_debugfs_add_netdev_params(struct wl_priv *wl);
428static void wl_debugfs_remove_netdev(struct wl_priv *wl);
429
430/*
431 * rfkill support
432 */
433static int wl_setup_rfkill(struct wl_priv *wl, bool setup);
434static int wl_rfkill_set(void *data, bool blocked);
435
436/*
437 * Some external functions, TODO: move them to dhd_linux.h
438 */
439int dhd_add_monitor(char *name, struct net_device **new_ndev);
440int dhd_del_monitor(struct net_device *ndev);
441int dhd_monitor_init(void *dhd_pub);
442int dhd_monitor_uninit(void);
443int dhd_start_xmit(struct sk_buff *skb, struct net_device *net);
444
445#define CHECK_SYS_UP(wlpriv) \
446do { \
447 if (unlikely(!wl_get_drv_status(wlpriv, READY))) { \
448 WL_INFO(("device is not ready : status (%d)\n", \
449 (int)wlpriv->status)); \
450 return -EIO; \
451 } \
452} while (0)
453
454
455#define IS_WPA_AKM(akm) ((akm) == RSN_AKM_NONE || \
456 (akm) == RSN_AKM_UNSPECIFIED || \
457 (akm) == RSN_AKM_PSK)
458
459
460extern int dhd_wait_pend8021x(struct net_device *dev);
461
462#if (WL_DBG_LEVEL > 0)
463#define WL_DBG_ESTR_MAX 50
464static s8 wl_dbg_estr[][WL_DBG_ESTR_MAX] = {
465 "SET_SSID", "JOIN", "START", "AUTH", "AUTH_IND",
466 "DEAUTH", "DEAUTH_IND", "ASSOC", "ASSOC_IND", "REASSOC",
467 "REASSOC_IND", "DISASSOC", "DISASSOC_IND", "QUIET_START", "QUIET_END",
468 "BEACON_RX", "LINK", "MIC_ERROR", "NDIS_LINK", "ROAM",
469 "TXFAIL", "PMKID_CACHE", "RETROGRADE_TSF", "PRUNE", "AUTOAUTH",
470 "EAPOL_MSG", "SCAN_COMPLETE", "ADDTS_IND", "DELTS_IND", "BCNSENT_IND",
471 "BCNRX_MSG", "BCNLOST_MSG", "ROAM_PREP", "PFN_NET_FOUND",
472 "PFN_NET_LOST",
473 "RESET_COMPLETE", "JOIN_START", "ROAM_START", "ASSOC_START",
474 "IBSS_ASSOC",
475 "RADIO", "PSM_WATCHDOG", "WLC_E_CCX_ASSOC_START", "WLC_E_CCX_ASSOC_ABORT",
476 "PROBREQ_MSG",
477 "SCAN_CONFIRM_IND", "PSK_SUP", "COUNTRY_CODE_CHANGED",
478 "EXCEEDED_MEDIUM_TIME", "ICV_ERROR",
479 "UNICAST_DECODE_ERROR", "MULTICAST_DECODE_ERROR", "TRACE",
480 "WLC_E_BTA_HCI_EVENT", "IF", "WLC_E_P2P_DISC_LISTEN_COMPLETE",
481 "RSSI", "PFN_SCAN_COMPLETE", "WLC_E_EXTLOG_MSG",
482 "ACTION_FRAME", "ACTION_FRAME_COMPLETE", "WLC_E_PRE_ASSOC_IND",
483 "WLC_E_PRE_REASSOC_IND", "WLC_E_CHANNEL_ADOPTED", "WLC_E_AP_STARTED",
484 "WLC_E_DFS_AP_STOP", "WLC_E_DFS_AP_RESUME", "WLC_E_WAI_STA_EVENT",
485 "WLC_E_WAI_MSG", "WLC_E_ESCAN_RESULT", "WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE",
486 "WLC_E_PROBRESP_MSG", "WLC_E_P2P_PROBREQ_MSG", "WLC_E_DCS_REQUEST", "WLC_E_FIFO_CREDIT_MAP",
487 "WLC_E_ACTION_FRAME_RX", "WLC_E_WAKE_EVENT", "WLC_E_RM_COMPLETE"
488};
489#endif /* WL_DBG_LEVEL */
490
491#define CHAN2G(_channel, _freq, _flags) { \
492 .band = IEEE80211_BAND_2GHZ, \
493 .center_freq = (_freq), \
494 .hw_value = (_channel), \
495 .flags = (_flags), \
496 .max_antenna_gain = 0, \
497 .max_power = 30, \
498}
499
500#define CHAN5G(_channel, _flags) { \
501 .band = IEEE80211_BAND_5GHZ, \
502 .center_freq = 5000 + (5 * (_channel)), \
503 .hw_value = (_channel), \
504 .flags = (_flags), \
505 .max_antenna_gain = 0, \
506 .max_power = 30, \
507}
508
509#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2)
510#define RATETAB_ENT(_rateid, _flags) \
511 { \
512 .bitrate = RATE_TO_BASE100KBPS(_rateid), \
513 .hw_value = (_rateid), \
514 .flags = (_flags), \
515 }
516
517static struct ieee80211_rate __wl_rates[] = {
518 RATETAB_ENT(WLC_RATE_1M, 0),
519 RATETAB_ENT(WLC_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE),
520 RATETAB_ENT(WLC_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE),
521 RATETAB_ENT(WLC_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE),
522 RATETAB_ENT(WLC_RATE_6M, 0),
523 RATETAB_ENT(WLC_RATE_9M, 0),
524 RATETAB_ENT(WLC_RATE_12M, 0),
525 RATETAB_ENT(WLC_RATE_18M, 0),
526 RATETAB_ENT(WLC_RATE_24M, 0),
527 RATETAB_ENT(WLC_RATE_36M, 0),
528 RATETAB_ENT(WLC_RATE_48M, 0),
529 RATETAB_ENT(WLC_RATE_54M, 0)
530};
531
532#define wl_a_rates (__wl_rates + 4)
533#define wl_a_rates_size 8
534#define wl_g_rates (__wl_rates + 0)
535#define wl_g_rates_size 12
536
537static struct ieee80211_channel __wl_2ghz_channels[] = {
538 CHAN2G(1, 2412, 0),
539 CHAN2G(2, 2417, 0),
540 CHAN2G(3, 2422, 0),
541 CHAN2G(4, 2427, 0),
542 CHAN2G(5, 2432, 0),
543 CHAN2G(6, 2437, 0),
544 CHAN2G(7, 2442, 0),
545 CHAN2G(8, 2447, 0),
546 CHAN2G(9, 2452, 0),
547 CHAN2G(10, 2457, 0),
548 CHAN2G(11, 2462, 0),
549 CHAN2G(12, 2467, 0),
550 CHAN2G(13, 2472, 0),
551 CHAN2G(14, 2484, 0)
552};
553
554static struct ieee80211_channel __wl_5ghz_a_channels[] = {
555 CHAN5G(34, 0), CHAN5G(36, 0),
556 CHAN5G(38, 0), CHAN5G(40, 0),
557 CHAN5G(42, 0), CHAN5G(44, 0),
558 CHAN5G(46, 0), CHAN5G(48, 0),
559 CHAN5G(52, 0), CHAN5G(56, 0),
560 CHAN5G(60, 0), CHAN5G(64, 0),
561 CHAN5G(100, 0), CHAN5G(104, 0),
562 CHAN5G(108, 0), CHAN5G(112, 0),
563 CHAN5G(116, 0), CHAN5G(120, 0),
564 CHAN5G(124, 0), CHAN5G(128, 0),
565 CHAN5G(132, 0), CHAN5G(136, 0),
566 CHAN5G(140, 0), CHAN5G(149, 0),
567 CHAN5G(153, 0), CHAN5G(157, 0),
568 CHAN5G(161, 0), CHAN5G(165, 0)
569};
570
571static struct ieee80211_supported_band __wl_band_2ghz = {
572 .band = IEEE80211_BAND_2GHZ,
573 .channels = __wl_2ghz_channels,
574 .n_channels = ARRAY_SIZE(__wl_2ghz_channels),
575 .bitrates = wl_g_rates,
576 .n_bitrates = wl_g_rates_size
577};
578
579static struct ieee80211_supported_band __wl_band_5ghz_a = {
580 .band = IEEE80211_BAND_5GHZ,
581 .channels = __wl_5ghz_a_channels,
582 .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels),
583 .bitrates = wl_a_rates,
584 .n_bitrates = wl_a_rates_size
585};
586
587static const u32 __wl_cipher_suites[] = {
588 WLAN_CIPHER_SUITE_WEP40,
589 WLAN_CIPHER_SUITE_WEP104,
590 WLAN_CIPHER_SUITE_TKIP,
591 WLAN_CIPHER_SUITE_CCMP,
592 WLAN_CIPHER_SUITE_AES_CMAC,
593};
594
595/* There isn't a lot of sense in it, but you can transmit anything you like */
596static const struct ieee80211_txrx_stypes
597wl_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
598 [NL80211_IFTYPE_ADHOC] = {
599 .tx = 0xffff,
600 .rx = BIT(IEEE80211_STYPE_ACTION >> 4)
601 },
602 [NL80211_IFTYPE_STATION] = {
603 .tx = 0xffff,
604 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
605 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
606 },
607 [NL80211_IFTYPE_AP] = {
608 .tx = 0xffff,
609 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
610 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
611 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
612 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
613 BIT(IEEE80211_STYPE_AUTH >> 4) |
614 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
615 BIT(IEEE80211_STYPE_ACTION >> 4)
616 },
617 [NL80211_IFTYPE_AP_VLAN] = {
618 /* copy AP */
619 .tx = 0xffff,
620 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
621 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
622 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
623 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
624 BIT(IEEE80211_STYPE_AUTH >> 4) |
625 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
626 BIT(IEEE80211_STYPE_ACTION >> 4)
627 },
628 [NL80211_IFTYPE_P2P_CLIENT] = {
629 .tx = 0xffff,
630 .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
631 BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
632 },
633 [NL80211_IFTYPE_P2P_GO] = {
634 .tx = 0xffff,
635 .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
636 BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
637 BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
638 BIT(IEEE80211_STYPE_DISASSOC >> 4) |
639 BIT(IEEE80211_STYPE_AUTH >> 4) |
640 BIT(IEEE80211_STYPE_DEAUTH >> 4) |
641 BIT(IEEE80211_STYPE_ACTION >> 4)
642 }
643};
644
645static void swap_key_from_BE(struct wl_wsec_key *key)
646{
647 key->index = htod32(key->index);
648 key->len = htod32(key->len);
649 key->algo = htod32(key->algo);
650 key->flags = htod32(key->flags);
651 key->rxiv.hi = htod32(key->rxiv.hi);
652 key->rxiv.lo = htod16(key->rxiv.lo);
653 key->iv_initialized = htod32(key->iv_initialized);
654}
655
656static void swap_key_to_BE(struct wl_wsec_key *key)
657{
658 key->index = dtoh32(key->index);
659 key->len = dtoh32(key->len);
660 key->algo = dtoh32(key->algo);
661 key->flags = dtoh32(key->flags);
662 key->rxiv.hi = dtoh32(key->rxiv.hi);
663 key->rxiv.lo = dtoh16(key->rxiv.lo);
664 key->iv_initialized = dtoh32(key->iv_initialized);
665}
666
667/* For debug: Dump the contents of the encoded wps ie buffe */
668static void
669wl_validate_wps_ie(char *wps_ie, bool *pbc)
670{
671 #define WPS_IE_FIXED_LEN 6
672 u16 len = (u16) wps_ie[TLV_LEN_OFF];
673 u8 *subel = wps_ie+ WPS_IE_FIXED_LEN;
674 u16 subelt_id;
675 u16 subelt_len;
676 u16 val;
677 u8 *valptr = (uint8*) &val;
678
679 WL_DBG(("wps_ie len=%d\n", len));
680
681 len -= 4; /* for the WPS IE's OUI, oui_type fields */
682
683 while (len >= 4) { /* must have attr id, attr len fields */
684 valptr[0] = *subel++;
685 valptr[1] = *subel++;
686 subelt_id = HTON16(val);
687
688 valptr[0] = *subel++;
689 valptr[1] = *subel++;
690 subelt_len = HTON16(val);
691
692 len -= 4; /* for the attr id, attr len fields */
693 len -= subelt_len; /* for the remaining fields in this attribute */
694 WL_DBG((" subel=%p, subelt_id=0x%x subelt_len=%u\n",
695 subel, subelt_id, subelt_len));
696
697 if (subelt_id == WPS_ID_VERSION) {
698 WL_DBG((" attr WPS_ID_VERSION: %u\n", *subel));
699 } else if (subelt_id == WPS_ID_REQ_TYPE) {
700 WL_DBG((" attr WPS_ID_REQ_TYPE: %u\n", *subel));
701 } else if (subelt_id == WPS_ID_CONFIG_METHODS) {
702 valptr[0] = *subel;
703 valptr[1] = *(subel + 1);
704 WL_DBG((" attr WPS_ID_CONFIG_METHODS: %x\n", HTON16(val)));
705 } else if (subelt_id == WPS_ID_DEVICE_NAME) {
706 char devname[100];
707 memcpy(devname, subel, subelt_len);
708 devname[subelt_len] = '\0';
709 WL_DBG((" attr WPS_ID_DEVICE_NAME: %s (len %u)\n",
710 devname, subelt_len));
711 } else if (subelt_id == WPS_ID_DEVICE_PWD_ID) {
712 valptr[0] = *subel;
713 valptr[1] = *(subel + 1);
714 WL_DBG((" attr WPS_ID_DEVICE_PWD_ID: %u\n", HTON16(val)));
715 *pbc = (HTON16(val) == DEV_PW_PUSHBUTTON) ? true : false;
716 } else if (subelt_id == WPS_ID_PRIM_DEV_TYPE) {
717 valptr[0] = *subel;
718 valptr[1] = *(subel + 1);
719 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: cat=%u \n", HTON16(val)));
720 valptr[0] = *(subel + 6);
721 valptr[1] = *(subel + 7);
722 WL_DBG((" attr WPS_ID_PRIM_DEV_TYPE: subcat=%u\n", HTON16(val)));
723 } else if (subelt_id == WPS_ID_REQ_DEV_TYPE) {
724 valptr[0] = *subel;
725 valptr[1] = *(subel + 1);
726 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: cat=%u\n", HTON16(val)));
727 valptr[0] = *(subel + 6);
728 valptr[1] = *(subel + 7);
729 WL_DBG((" attr WPS_ID_REQ_DEV_TYPE: subcat=%u\n", HTON16(val)));
730 } else if (subelt_id == WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS) {
731 valptr[0] = *subel;
732 valptr[1] = *(subel + 1);
733 WL_DBG((" attr WPS_ID_SELECTED_REGISTRAR_CONFIG_METHODS"
734 ": cat=%u\n", HTON16(val)));
735 } else {
736 WL_DBG((" unknown attr 0x%x\n", subelt_id));
737 }
738
739 subel += subelt_len;
740 }
741}
742
743static struct net_device* wl_cfg80211_add_monitor_if(char *name)
744{
745 int ret = 0;
746 struct net_device* ndev = NULL;
747
748 ret = dhd_add_monitor(name, &ndev);
749 WL_INFO(("wl_cfg80211_add_monitor_if net device returned: 0x%p\n", ndev));
750 return ndev;
751}
752
753static struct net_device *
754wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name,
755 enum nl80211_iftype type, u32 *flags,
756 struct vif_params *params)
757{
758 s32 err;
759 s32 timeout = -1;
760 s32 wlif_type = -1;
761 s32 index = 0;
762 s32 mode = 0;
763 chanspec_t chspec;
764 struct wl_priv *wl = wiphy_priv(wiphy);
765 struct net_device *_ndev;
766 dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
767 int (*net_attach)(dhd_pub_t *dhdp, int ifidx);
768 bool rollback_lock = false;
769
770 WL_DBG(("if name: %s, type: %d\n", name, type));
771 switch (type) {
772 case NL80211_IFTYPE_ADHOC:
773 case NL80211_IFTYPE_AP_VLAN:
774 case NL80211_IFTYPE_WDS:
775 case NL80211_IFTYPE_MESH_POINT:
776 WL_ERR(("Unsupported interface type\n"));
777 mode = WL_MODE_IBSS;
778 return NULL;
779 case NL80211_IFTYPE_MONITOR:
780 return wl_cfg80211_add_monitor_if(name);
781 case NL80211_IFTYPE_P2P_CLIENT:
782 case NL80211_IFTYPE_STATION:
783 wlif_type = WL_P2P_IF_CLIENT;
784 mode = WL_MODE_BSS;
785 break;
786 case NL80211_IFTYPE_P2P_GO:
787 case NL80211_IFTYPE_AP:
788 wlif_type = WL_P2P_IF_GO;
789 mode = WL_MODE_AP;
790 break;
791 default:
792 WL_ERR(("Unsupported interface type\n"));
793 return NULL;
794 break;
795 }
796
797 if (!name) {
798 WL_ERR(("name is NULL\n"));
799 return NULL;
800 }
801 if (wl->p2p_supported && (wlif_type != -1)) {
802 if (wl_get_p2p_status(wl, IF_DELETING)) {
803 /* wait till IF_DEL is complete
804 * release the lock for the unregister to proceed
805 */
806 if (rtnl_is_locked()) {
807 rtnl_unlock();
808 rollback_lock = true;
809 }
810 WL_INFO(("%s: Released the lock and wait till IF_DEL is complete\n",
811 __func__));
812 timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
813 (wl_get_p2p_status(wl, IF_DELETING) == false),
814 msecs_to_jiffies(MAX_WAIT_TIME));
815
816 /* put back the rtnl_lock again */
817 if (rollback_lock) {
818 rtnl_lock();
819 rollback_lock = false;
820 }
821 if (timeout > 0) {
822 WL_ERR(("IF DEL is Success\n"));
823
824 } else {
825 WL_ERR(("timeount < 0, return -EAGAIN\n"));
826 return ERR_PTR(-EAGAIN);
827 }
828 }
829 if (!p2p_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) {
830 p2p_on(wl) = true;
831 wl_cfgp2p_set_firm_p2p(wl);
832 wl_cfgp2p_init_discovery(wl);
833 }
834 memset(wl->p2p->vir_ifname, 0, IFNAMSIZ);
835 strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1);
836 wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
837
838 /* Temporary use channel 11, in case GO will be changed with set_channel API */
839 chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
840
841 /* For P2P mode, use P2P-specific driver features to create the
842 * bss: "wl p2p_ifadd"
843 */
844 wl_set_p2p_status(wl, IF_ADD);
845 err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
846
847 if (unlikely(err))
848 return ERR_PTR(-ENOMEM);
849
850 timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
851 (wl_get_p2p_status(wl, IF_ADD) == false),
852 msecs_to_jiffies(MAX_WAIT_TIME));
853 if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) {
854
855 struct wireless_dev *vwdev;
856 vwdev = kzalloc(sizeof(*vwdev), GFP_KERNEL);
857 if (unlikely(!vwdev)) {
858 WL_ERR(("Could not allocate wireless device\n"));
859 return ERR_PTR(-ENOMEM);
860 }
861 vwdev->wiphy = wl->wdev->wiphy;
862 WL_INFO((" virtual interface(%s) is created memalloc done \n",
863 wl->p2p->vir_ifname));
864 index = alloc_idx_vwdev(wl);
865 wl->vwdev[index] = vwdev;
866 vwdev->iftype =
867 (wlif_type == WL_P2P_IF_CLIENT) ? NL80211_IFTYPE_STATION
868 : NL80211_IFTYPE_AP;
869 _ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
870 _ndev->ieee80211_ptr = vwdev;
871 SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy));
872 vwdev->netdev = _ndev;
873 wl_set_drv_status(wl, READY);
874 wl->p2p->vif_created = true;
875 set_mode_by_netdev(wl, _ndev, mode);
876 net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION);
877 if (rtnl_is_locked()) {
878 rtnl_unlock();
879 rollback_lock = true;
880 }
881 if (net_attach && !net_attach(dhd, _ndev->ifindex)) {
882 WL_DBG((" virtual interface(%s) is "
883 "created net attach done\n", wl->p2p->vir_ifname));
884 } else {
885 /* put back the rtnl_lock again */
886 if (rollback_lock)
887 rtnl_lock();
888 goto fail;
889 }
890 /* put back the rtnl_lock again */
891 if (rollback_lock)
892 rtnl_lock();
893 return _ndev;
894
895 } else {
896 wl_clr_p2p_status(wl, IF_ADD);
897 WL_ERR((" virtual interface(%s) is not created \n", wl->p2p->vir_ifname));
898 memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ);
899 wl->p2p->vif_created = false;
900 }
901 }
902fail:
903 return ERR_PTR(-ENODEV);
904}
905
906static s32
907wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev)
908{
909 struct ether_addr p2p_mac;
910 struct wl_priv *wl = wiphy_priv(wiphy);
911 s32 timeout = -1;
912 s32 ret = 0;
913 WL_DBG(("Enter\n"));
914 if (wl->p2p_supported) {
915 memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN);
916 if (wl->p2p->vif_created) {
917 if (wl_get_drv_status(wl, SCANNING)) {
918 wl_cfg80211_scan_abort(wl, dev);
919 }
920 wldev_iovar_setint(dev, "mpc", 1);
921 wl_set_p2p_status(wl, IF_DELETING);
922 ret = wl_cfgp2p_ifdel(wl, &p2p_mac);
923 if (ret) {
924 /* Firmware could not delete the interface so we will not get WLC_E_IF
925 * event for cleaning the dhd virtual nw interace
926 * So lets do it here. Failures from fw will ensure the application to do
927 * ifconfig <inter> down and up sequnce, which will reload the fw
928 * however we should cleanup the linux network virtual interfaces
929 */
930 dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
931 WL_ERR(("Firmware returned an error from p2p_ifdel\n"));
932 WL_ERR(("try to remove linux virtual interface %s\n", dev->name));
933 dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev));
934 }
935
936 /* Wait for any pending scan req to get aborted from the sysioc context */
937 timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
938 (wl_get_p2p_status(wl, IF_DELETING) == false),
939 msecs_to_jiffies(MAX_WAIT_TIME));
940 if (timeout > 0 && !wl_get_p2p_status(wl, IF_DELETING)) {
941 WL_DBG(("IFDEL operation done\n"));
942 } else {
943 WL_ERR(("IFDEL didn't complete properly\n"));
944 }
945 ret = dhd_del_monitor(dev);
946 }
947 }
948 return ret;
949}
950
951static s32
952wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev,
953 enum nl80211_iftype type, u32 *flags,
954 struct vif_params *params)
955{
956 s32 ap = 0;
957 s32 infra = 0;
958 s32 err = BCME_OK;
959 s32 timeout = -1;
960 s32 wlif_type;
961 s32 mode = 0;
962 chanspec_t chspec;
963 struct wl_priv *wl = wiphy_priv(wiphy);
964 WL_DBG(("Enter \n"));
965 switch (type) {
966 case NL80211_IFTYPE_MONITOR:
967 case NL80211_IFTYPE_WDS:
968 case NL80211_IFTYPE_MESH_POINT:
969 ap = 1;
970 WL_ERR(("type (%d) : currently we do not support this type\n",
971 type));
972 break;
973 case NL80211_IFTYPE_ADHOC:
974 mode = WL_MODE_IBSS;
975 break;
976 case NL80211_IFTYPE_STATION:
977 case NL80211_IFTYPE_P2P_CLIENT:
978 mode = WL_MODE_BSS;
979 infra = 1;
980 break;
981 case NL80211_IFTYPE_AP:
982 case NL80211_IFTYPE_AP_VLAN:
983 case NL80211_IFTYPE_P2P_GO:
984 mode = WL_MODE_AP;
985 ap = 1;
986 break;
987 default:
988 return -EINVAL;
989 }
990
991
992 if (ap) {
993 set_mode_by_netdev(wl, ndev, mode);
994 if (wl->p2p_supported && wl->p2p->vif_created) {
995 WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created,
996 p2p_on(wl)));
997 chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN);
998 wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT;
999 WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n",
1000 ndev->name, ap, infra, type));
1001 wl_set_p2p_status(wl, IF_CHANGING);
1002 wl_clr_p2p_status(wl, IF_CHANGED);
1003 err = wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec);
1004 timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
1005 (wl_get_p2p_status(wl, IF_CHANGED) == true),
1006 msecs_to_jiffies(MAX_WAIT_TIME));
1007 set_mode_by_netdev(wl, ndev, mode);
1008 wl_clr_p2p_status(wl, IF_CHANGING);
1009 wl_clr_p2p_status(wl, IF_CHANGED);
1010 } else if (ndev == wl_to_prmry_ndev(wl) &&
1011 !wl_get_drv_status(wl, AP_CREATED)) {
1012 wl_set_drv_status(wl, AP_CREATING);
1013 if (!wl->ap_info &&
1014 !(wl->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) {
1015 WL_ERR(("struct ap_saved_ie allocation failed\n"));
1016 return -ENOMEM;
1017 }
1018 } else {
1019 WL_ERR(("Cannot change the interface for GO or SOFTAP\n"));
1020 return -EINVAL;
1021 }
1022 }
1023
1024 ndev->ieee80211_ptr->iftype = type;
1025 return 0;
1026}
1027
1028s32
1029wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx,
1030int (*_net_attach)(dhd_pub_t *dhdp, int ifidx))
1031{
1032 struct wl_priv *wl = wlcfg_drv_priv;
1033 s32 ret = BCME_OK;
1034 if (!ndev) {
1035 WL_ERR(("net is NULL\n"));
1036 return 0;
1037 }
1038 if (wl->p2p_supported) {
1039 WL_DBG(("IF_ADD event called from dongle, old interface name: %s,"
1040 "new name: %s\n", ndev->name, wl->p2p->vir_ifname));
1041 /* Assign the net device to CONNECT BSSCFG */
1042 strncpy(ndev->name, wl->p2p->vir_ifname, IFNAMSIZ - 1);
1043 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = ndev;
1044 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = bssidx;
1045 wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION) = _net_attach;
1046 ndev->ifindex = idx;
1047 wl_clr_p2p_status(wl, IF_ADD);
1048
1049 wake_up_interruptible(&wl->dongle_event_wait);
1050 }
1051 return ret;
1052}
1053
1054s32
1055wl_cfg80211_notify_ifdel(struct net_device *ndev)
1056{
1057 struct wl_priv *wl = wlcfg_drv_priv;
1058 bool rollback_lock = false;
1059 s32 index = 0;
1060
1061 if (!ndev || !ndev->name) {
1062 WL_ERR(("net is NULL\n"));
1063 return 0;
1064 }
1065
1066 if (p2p_is_on(wl) && wl->p2p->vif_created) {
1067 if (wl->scan_request) {
1068 /* Abort any pending scan requests */
1069 wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
1070 if (!rtnl_is_locked()) {
1071 rtnl_lock();
1072 rollback_lock = true;
1073 }
1074 WL_DBG(("ESCAN COMPLETED\n"));
1075 wl_notify_escan_complete(wl, true);
1076 if (rollback_lock)
1077 rtnl_unlock();
1078 }
1079 WL_ERR(("IF_DEL event called from dongle, net %x, vif name: %s\n",
1080 (unsigned int)ndev, wl->p2p->vir_ifname));
1081
1082 memset(wl->p2p->vir_ifname, '\0', IFNAMSIZ);
1083 index = wl_cfgp2p_find_idx(wl, ndev);
1084 wl_to_p2p_bss_ndev(wl, index) = NULL;
1085 wl_to_p2p_bss_bssidx(wl, index) = 0;
1086 wl->p2p->vif_created = false;
1087 wl_cfgp2p_clear_management_ie(wl,
1088 index);
1089 wl_clr_p2p_status(wl, IF_DELETING);
1090 WL_DBG(("index : %d\n", index));
1091
1092 }
1093 /* Wake up any waiting thread */
1094 wake_up_interruptible(&wl->dongle_event_wait);
1095
1096 return 0;
1097}
1098
1099s32
1100wl_cfg80211_is_progress_ifadd(void)
1101{
1102 s32 is_progress = 0;
1103 struct wl_priv *wl = wlcfg_drv_priv;
1104 if (wl_get_p2p_status(wl, IF_ADD))
1105 is_progress = 1;
1106 return is_progress;
1107}
1108
1109s32
1110wl_cfg80211_is_progress_ifchange(void)
1111{
1112 s32 is_progress = 0;
1113 struct wl_priv *wl = wlcfg_drv_priv;
1114 if (wl_get_p2p_status(wl, IF_CHANGING))
1115 is_progress = 1;
1116 return is_progress;
1117}
1118
1119
1120s32
1121wl_cfg80211_notify_ifchange(void)
1122{
1123 struct wl_priv *wl = wlcfg_drv_priv;
1124 if (wl_get_p2p_status(wl, IF_CHANGING)) {
1125 wl_set_p2p_status(wl, IF_CHANGED);
1126 wake_up_interruptible(&wl->dongle_event_wait);
1127 }
1128 return 0;
1129}
1130
1131static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request)
1132{
1133 u32 n_ssids = request->n_ssids;
1134 u32 n_channels = request->n_channels;
1135 u16 channel;
1136 chanspec_t chanspec;
1137 s32 i, offset;
1138 char *ptr;
1139 wlc_ssid_t ssid;
1140
1141 memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
1142 params->bss_type = DOT11_BSSTYPE_ANY;
1143 params->scan_type = 0;
1144 params->nprobes = -1;
1145 params->active_time = -1;
1146 params->passive_time = -1;
1147 params->home_time = -1;
1148 params->channel_num = 0;
1149 memset(&params->ssid, 0, sizeof(wlc_ssid_t));
1150
1151 WL_SCAN(("Preparing Scan request\n"));
1152 WL_SCAN(("nprobes=%d\n", params->nprobes));
1153 WL_SCAN(("active_time=%d\n", params->active_time));
1154 WL_SCAN(("passive_time=%d\n", params->passive_time));
1155 WL_SCAN(("home_time=%d\n", params->home_time));
1156 WL_SCAN(("scan_type=%d\n", params->scan_type));
1157
1158 params->nprobes = htod32(params->nprobes);
1159 params->active_time = htod32(params->active_time);
1160 params->passive_time = htod32(params->passive_time);
1161 params->home_time = htod32(params->home_time);
1162
1163 /* Copy channel array if applicable */
1164 WL_SCAN(("### List of channelspecs to scan ###\n"));
1165 if (n_channels > 0) {
1166 for (i = 0; i < n_channels; i++) {
1167 chanspec = 0;
1168 channel = ieee80211_frequency_to_channel(request->channels[i]->center_freq);
1169 if (request->channels[i]->band == IEEE80211_BAND_2GHZ)
1170 chanspec |= WL_CHANSPEC_BAND_2G;
1171 else
1172 chanspec |= WL_CHANSPEC_BAND_5G;
1173
1174 if (request->channels[i]->flags & IEEE80211_CHAN_NO_HT40) {
1175 chanspec |= WL_CHANSPEC_BW_20;
1176 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
1177 } else {
1178 chanspec |= WL_CHANSPEC_BW_40;
1179 if (request->channels[i]->flags & IEEE80211_CHAN_NO_HT40PLUS)
1180 chanspec |= WL_CHANSPEC_CTL_SB_LOWER;
1181 else
1182 chanspec |= WL_CHANSPEC_CTL_SB_UPPER;
1183 }
1184
1185 params->channel_list[i] = channel;
1186 params->channel_list[i] &= WL_CHANSPEC_CHAN_MASK;
1187 params->channel_list[i] |= chanspec;
1188 WL_SCAN(("Chan : %d, Channel spec: %x \n",
1189 channel, params->channel_list[i]));
1190 params->channel_list[i] = htod16(params->channel_list[i]);
1191 }
1192 } else {
1193 WL_SCAN(("Scanning all channels\n"));
1194 }
1195
1196 /* Copy ssid array if applicable */
1197 WL_SCAN(("### List of SSIDs to scan ###\n"));
1198 if (n_ssids > 0) {
1199 offset = offsetof(wl_scan_params_t, channel_list) + n_channels * sizeof(u16);
1200 offset = roundup(offset, sizeof(u32));
1201 ptr = (char*)params + offset;
1202 for (i = 0; i < n_ssids; i++) {
1203 memset(&ssid, 0, sizeof(wlc_ssid_t));
1204 ssid.SSID_len = request->ssids[i].ssid_len;
1205 memcpy(ssid.SSID, request->ssids[i].ssid, ssid.SSID_len);
1206 if (!ssid.SSID_len)
1207 WL_SCAN(("%d: Broadcast scan\n", i));
1208 else
1209 WL_SCAN(("%d: scan for %s size =%d\n", i,
1210 ssid.SSID, ssid.SSID_len));
1211 memcpy(ptr, &ssid, sizeof(wlc_ssid_t));
1212 ptr += sizeof(wlc_ssid_t);
1213 }
1214 } else {
1215 WL_SCAN(("Broadcast scan\n"));
1216 }
1217 /* Adding mask to channel numbers */
1218 params->channel_num =
1219 htod32((n_ssids << WL_SCAN_PARAMS_NSSID_SHIFT) |
1220 (n_channels & WL_SCAN_PARAMS_COUNT_MASK));
1221}
1222
1223static s32
1224wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, u16 action)
1225{
1226 u32 n_channels;
1227 u32 n_ssids;
1228 s32 params_size =
1229 (WL_SCAN_PARAMS_FIXED_SIZE + offsetof(wl_iscan_params_t, params));
1230 struct wl_iscan_params *params;
1231 s32 err = 0;
1232
1233 if (request != NULL) {
1234 n_channels = request->n_channels;
1235 n_ssids = request->n_ssids;
1236 /* Allocate space for populating ssids in wl_iscan_params struct */
1237 if (n_channels % 2)
1238 /* If n_channels is odd, add a padd of u16 */
1239 params_size += sizeof(u16) * (n_channels + 1);
1240 else
1241 params_size += sizeof(u16) * n_channels;
1242
1243 /* Allocate space for populating ssids in wl_iscan_params struct */
1244 params_size += sizeof(struct wlc_ssid) * n_ssids;
1245 }
1246 params = (struct wl_iscan_params *)kzalloc(params_size, GFP_KERNEL);
1247 if (!params) {
1248 return -ENOMEM;
1249 }
1250
1251 if (request != NULL)
1252 wl_scan_prep(&params->params, request);
1253
1254 params->version = htod32(ISCAN_REQ_VERSION);
1255 params->action = htod16(action);
1256 params->scan_duration = htod16(0);
1257
1258 if (params_size + sizeof("iscan") >= WLC_IOCTL_MEDLEN) {
1259 WL_ERR(("ioctl buffer length is not sufficient\n"));
1260 err = -ENOMEM;
1261 goto done;
1262 }
1263 err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size,
1264 iscan->ioctl_buf, WLC_IOCTL_MEDLEN);
1265 if (unlikely(err)) {
1266 if (err == -EBUSY) {
1267 WL_ERR(("system busy : iscan canceled\n"));
1268 } else {
1269 WL_ERR(("error (%d)\n", err));
1270 }
1271 }
1272done:
1273 kfree(params);
1274 return err;
1275}
1276
1277static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request)
1278{
1279 struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
1280 struct net_device *ndev = wl_to_prmry_ndev(wl);
1281 s32 passive_scan;
1282 s32 err = 0;
1283
1284 iscan->state = WL_ISCAN_STATE_SCANING;
1285
1286 passive_scan = wl->active_scan ? 0 : 1;
1287 err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
1288 &passive_scan, sizeof(passive_scan), false);
1289 if (unlikely(err)) {
1290 WL_DBG(("error (%d)\n", err));
1291 return err;
1292 }
1293 wl->iscan_kickstart = true;
1294 wl_run_iscan(iscan, request, WL_SCAN_ACTION_START);
1295 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
1296 iscan->timer_on = 1;
1297
1298 return err;
1299}
1300
1301static s32
1302wl_run_escan(struct wl_priv *wl, struct net_device *ndev,
1303 struct cfg80211_scan_request *request, uint16 action)
1304{
1305 s32 err = BCME_OK;
1306 u32 n_channels;
1307 u32 n_ssids;
1308 s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params));
1309 wl_escan_params_t *params;
1310 struct cfg80211_scan_request *scan_request = wl->scan_request;
1311 u32 num_chans = 0;
1312 s32 search_state = WL_P2P_DISC_ST_SCAN;
1313 u32 i;
1314 u16 *default_chan_list = NULL;
1315 struct net_device *dev = NULL;
1316 WL_DBG(("Enter \n"));
1317
1318
1319 if (!wl->p2p_supported || ((ndev == wl_to_prmry_ndev(wl)) &&
1320 !p2p_scan(wl))) {
1321 /* LEGACY SCAN TRIGGER */
1322 WL_SCAN((" LEGACY E-SCAN START\n"));
1323
1324 if (request != NULL) {
1325 n_channels = request->n_channels;
1326 n_ssids = request->n_ssids;
1327 /* Allocate space for populating ssids in wl_iscan_params struct */
1328 if (n_channels % 2)
1329 /* If n_channels is odd, add a padd of u16 */
1330 params_size += sizeof(u16) * (n_channels + 1);
1331 else
1332 params_size += sizeof(u16) * n_channels;
1333
1334 /* Allocate space for populating ssids in wl_iscan_params struct */
1335 params_size += sizeof(struct wlc_ssid) * n_ssids;
1336 }
1337 params = (wl_escan_params_t *) kzalloc(params_size, GFP_KERNEL);
1338 if (params == NULL) {
1339 err = -ENOMEM;
1340 goto exit;
1341 }
1342
1343 if (request != NULL)
1344 wl_scan_prep(&params->params, request);
1345 params->version = htod32(ESCAN_REQ_VERSION);
1346 params->action = htod16(action);
1347 params->sync_id = htod16(0x1234);
1348 if (params_size + sizeof("escan") >= WLC_IOCTL_MEDLEN) {
1349 WL_ERR(("ioctl buffer length not sufficient\n"));
1350 kfree(params);
1351 err = -ENOMEM;
1352 goto exit;
1353 }
1354 err = wldev_iovar_setbuf(ndev, "escan", params, params_size,
1355 wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN);
1356 if (unlikely(err))
1357 WL_ERR((" Escan set error (%d)\n", err));
1358 kfree(params);
1359 }
1360 else if (p2p_on(wl) && p2p_scan(wl)) {
1361 /* P2P SCAN TRIGGER */
1362 if (scan_request && scan_request->n_channels) {
1363 num_chans = scan_request->n_channels;
1364 WL_SCAN((" chann number : %d\n", num_chans));
1365 default_chan_list = kzalloc(num_chans * sizeof(*default_chan_list),
1366 GFP_KERNEL);
1367 if (default_chan_list == NULL) {
1368 WL_ERR(("channel list allocation failed \n"));
1369 err = -ENOMEM;
1370 goto exit;
1371 }
1372 for (i = 0; i < num_chans; i++)
1373 {
1374 default_chan_list[i] =
1375 ieee80211_frequency_to_channel(
1376 scan_request->channels[i]->center_freq);
1377 }
1378 if (num_chans == 3 && (
1379 (default_chan_list[0] == SOCIAL_CHAN_1) &&
1380 (default_chan_list[1] == SOCIAL_CHAN_2) &&
1381 (default_chan_list[2] == SOCIAL_CHAN_3))) {
1382 /* SOCIAL CHANNELS 1, 6, 11 */
1383 search_state = WL_P2P_DISC_ST_SEARCH;
1384 WL_INFO(("P2P SEARCH PHASE START \n"));
1385 } else if ((dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)) &&
1386 (get_mode_by_netdev(wl, dev) == WL_MODE_AP)) {
1387 /* If you are already a GO, then do SEARCH only */
1388 WL_INFO(("Already a GO. Do SEARCH Only"));
1389 search_state = WL_P2P_DISC_ST_SEARCH;
1390 } else {
1391 WL_INFO(("P2P SCAN STATE START \n"));
1392 }
1393
1394 }
1395 err = wl_cfgp2p_escan(wl, ndev, wl->active_scan, num_chans, default_chan_list,
1396 search_state, action,
1397 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
1398 kfree(default_chan_list);
1399 }
1400exit:
1401 if (unlikely(err)) {
1402 WL_ERR(("error (%d)\n", err));
1403 }
1404 return err;
1405}
1406
1407
1408static s32
1409wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev,
1410 struct cfg80211_scan_request *request)
1411{
1412 s32 err = BCME_OK;
1413 s32 passive_scan;
1414 wl_scan_results_t *results;
1415 WL_SCAN(("Enter \n"));
1416
1417 wl->escan_info.wiphy = wiphy;
1418 wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING;
1419 passive_scan = wl->active_scan ? 0 : 1;
1420 err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
1421 &passive_scan, sizeof(passive_scan), false);
1422 if (unlikely(err)) {
1423 WL_ERR(("error (%d)\n", err));
1424 return err;
1425 }
1426 results = (wl_scan_results_t *) wl->escan_info.escan_buf;
1427 results->version = 0;
1428 results->count = 0;
1429 results->buflen = WL_SCAN_RESULTS_FIXED_SIZE;
1430
1431 err = wl_run_escan(wl, ndev, request, WL_SCAN_ACTION_START);
1432 return err;
1433}
1434
1435static s32
1436__wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
1437 struct cfg80211_scan_request *request,
1438 struct cfg80211_ssid *this_ssid)
1439{
1440 struct wl_priv *wl = wiphy_priv(wiphy);
1441 struct cfg80211_ssid *ssids;
1442 struct wl_scan_req *sr = wl_to_sr(wl);
1443 wpa_ie_fixed_t *wps_ie;
1444 s32 passive_scan;
1445 bool iscan_req;
1446 bool escan_req;
1447 bool spec_scan;
1448 bool p2p_ssid;
1449 s32 err = 0;
1450 s32 i;
1451 u32 wpsie_len = 0;
1452 u8 wpsie[IE_MAX_LEN];
1453
1454 WL_DBG(("Enter wiphy (%p)\n", wiphy));
1455 if (unlikely(wl_get_drv_status(wl, SCANNING))) {
1456 WL_ERR(("Scanning already : status (%d)\n", (int)wl->status));
1457 return -EAGAIN;
1458 }
1459 if (unlikely(wl_get_drv_status(wl, SCAN_ABORTING))) {
1460 WL_ERR(("Scanning being aborted : status (%d)\n",
1461 (int)wl->status));
1462 return -EAGAIN;
1463 }
1464 if (request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) {
1465 WL_ERR(("n_ssids > WL_SCAN_PARAMS_SSID_MAX\n"));
1466 return -EOPNOTSUPP;
1467 }
1468
1469 /* Arm scan timeout timer */
1470 mod_timer(&wl->scan_timeout, jiffies + WL_SCAN_TIMER_INTERVAL_MS * HZ / 1000);
1471 iscan_req = false;
1472 spec_scan = false;
1473 if (request) { /* scan bss */
1474 ssids = request->ssids;
1475 if (wl->iscan_on && (!ssids || !ssids->ssid_len || request->n_ssids != 1)) {
1476 iscan_req = true;
1477 } else if (wl->escan_on) {
1478 escan_req = true;
1479 p2p_ssid = false;
1480 for (i = 0; i < request->n_ssids; i++) {
1481 if (ssids[i].ssid_len && IS_P2P_SSID(ssids[i].ssid)) {
1482 p2p_ssid = true;
1483 break;
1484 }
1485 }
1486 if (p2p_ssid) {
1487 if (wl->p2p_supported) {
1488 /* p2p scan trigger */
1489 if (p2p_on(wl) == false) {
1490 /* p2p on at the first time */
1491 p2p_on(wl) = true;
1492 wl_cfgp2p_set_firm_p2p(wl);
1493 }
1494 p2p_scan(wl) = true;
1495 }
1496 } else {
1497 /* legacy scan trigger
1498 * So, we have to disable p2p discovery if p2p discovery is on
1499 */
1500 if (wl->p2p_supported) {
1501 p2p_scan(wl) = false;
1502 /* If Netdevice is not equals to primary and p2p is on
1503 * , we will do p2p scan using P2PAPI_BSSCFG_DEVICE.
1504 */
1505 if (p2p_on(wl) && (ndev != wl_to_prmry_ndev(wl)))
1506 p2p_scan(wl) = true;
1507
1508 if (p2p_scan(wl) == false) {
1509 if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
1510 err = wl_cfgp2p_discover_enable_search(wl,
1511 false);
1512 if (unlikely(err)) {
1513 goto scan_out;
1514 }
1515
1516 }
1517 }
1518 }
1519 if (!wl->p2p_supported || !p2p_scan(wl)) {
1520 if (ndev == wl_to_prmry_ndev(wl)) {
1521 /* find the WPSIE */
1522 memset(wpsie, 0, sizeof(wpsie));
1523 if ((wps_ie = wl_cfgp2p_find_wpsie(
1524 (u8 *)request->ie,
1525 request->ie_len)) != NULL) {
1526 wpsie_len =
1527 wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
1528 memcpy(wpsie, wps_ie, wpsie_len);
1529 } else {
1530 wpsie_len = 0;
1531 }
1532 err = wl_cfgp2p_set_management_ie(wl, ndev, -1,
1533 VNDR_IE_PRBREQ_FLAG, wpsie, wpsie_len);
1534 if (unlikely(err)) {
1535 goto scan_out;
1536 }
1537 }
1538 }
1539 }
1540 }
1541 } else { /* scan in ibss */
1542 /* we don't do iscan in ibss */
1543 ssids = this_ssid;
1544 }
1545 wl->scan_request = request;
1546 wl_set_drv_status(wl, SCANNING);
1547 if (iscan_req) {
1548 err = wl_do_iscan(wl, request);
1549 if (likely(!err))
1550 return err;
1551 else
1552 goto scan_out;
1553 } else if (escan_req) {
1554 if (wl->p2p_supported) {
1555 if (p2p_on(wl) && p2p_scan(wl)) {
1556
1557 err = wl_cfgp2p_enable_discovery(wl, ndev,
1558 request->ie, request->ie_len);
1559
1560 if (unlikely(err)) {
1561 goto scan_out;
1562 }
1563 }
1564 }
1565 err = wl_do_escan(wl, wiphy, ndev, request);
1566 if (likely(!err))
1567 return err;
1568 else
1569 goto scan_out;
1570
1571
1572 } else {
1573 memset(&sr->ssid, 0, sizeof(sr->ssid));
1574 sr->ssid.SSID_len =
1575 min_t(u8, sizeof(sr->ssid.SSID), ssids->ssid_len);
1576 if (sr->ssid.SSID_len) {
1577 memcpy(sr->ssid.SSID, ssids->ssid, sr->ssid.SSID_len);
1578 sr->ssid.SSID_len = htod32(sr->ssid.SSID_len);
1579 WL_SCAN(("Specific scan ssid=\"%s\" len=%d\n",
1580 sr->ssid.SSID, sr->ssid.SSID_len));
1581 spec_scan = true;
1582 } else {
1583 WL_SCAN(("Broadcast scan\n"));
1584 }
1585 WL_SCAN(("sr->ssid.SSID_len (%d)\n", sr->ssid.SSID_len));
1586 passive_scan = wl->active_scan ? 0 : 1;
1587 err = wldev_ioctl(ndev, WLC_SET_PASSIVE_SCAN,
1588 &passive_scan, sizeof(passive_scan), false);
1589 if (unlikely(err)) {
1590 WL_SCAN(("WLC_SET_PASSIVE_SCAN error (%d)\n", err));
1591 goto scan_out;
1592 }
1593 err = wldev_ioctl(ndev, WLC_SCAN, &sr->ssid,
1594 sizeof(sr->ssid), false);
1595 if (err) {
1596 if (err == -EBUSY) {
1597 WL_ERR(("system busy : scan for \"%s\" "
1598 "canceled\n", sr->ssid.SSID));
1599 } else {
1600 WL_ERR(("WLC_SCAN error (%d)\n", err));
1601 }
1602 goto scan_out;
1603 }
1604 }
1605
1606 return 0;
1607
1608scan_out:
1609 wl_clr_drv_status(wl, SCANNING);
1610 wl->scan_request = NULL;
1611 return err;
1612}
1613
1614static s32
1615wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
1616 struct cfg80211_scan_request *request)
1617{
1618 s32 err = 0;
1619 struct wl_priv *wl = wiphy_priv(wiphy);
1620
1621 WL_DBG(("Enter \n"));
1622 CHECK_SYS_UP(wl);
1623
1624 err = __wl_cfg80211_scan(wiphy, ndev, request, NULL);
1625 if (unlikely(err)) {
1626 WL_ERR(("scan error (%d)\n", err));
1627 return err;
1628 }
1629
1630 return err;
1631}
1632
1633static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val)
1634{
1635 s8 buf[WLC_IOCTL_SMLEN];
1636 u32 len;
1637 s32 err = 0;
1638
1639 val = htod32(val);
1640 len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
1641 BUG_ON(unlikely(!len));
1642
1643 err = wldev_ioctl(dev, WLC_SET_VAR, buf, len, false);
1644 if (unlikely(err)) {
1645 WL_ERR(("error (%d)\n", err));
1646 }
1647
1648 return err;
1649}
1650
1651static s32
1652wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval)
1653{
1654 union {
1655 s8 buf[WLC_IOCTL_SMLEN];
1656 s32 val;
1657 } var;
1658 u32 len;
1659 u32 data_null;
1660 s32 err = 0;
1661
1662 len = bcm_mkiovar(name, (char *)(&data_null), 0,
1663 (char *)(&var), sizeof(var.buf));
1664 BUG_ON(unlikely(!len));
1665 err = wldev_ioctl(dev, WLC_GET_VAR, &var, len, false);
1666 if (unlikely(err)) {
1667 WL_ERR(("error (%d)\n", err));
1668 }
1669 *retval = dtoh32(var.val);
1670
1671 return err;
1672}
1673
1674static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold)
1675{
1676 s32 err = 0;
1677
1678 err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold);
1679 if (unlikely(err)) {
1680 WL_ERR(("Error (%d)\n", err));
1681 return err;
1682 }
1683 return err;
1684}
1685
1686static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold)
1687{
1688 s32 err = 0;
1689
1690 err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold);
1691 if (unlikely(err)) {
1692 WL_ERR(("Error (%d)\n", err));
1693 return err;
1694 }
1695 return err;
1696}
1697
1698static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l)
1699{
1700 s32 err = 0;
1701 u32 cmd = (l ? WLC_SET_LRL : WLC_SET_SRL);
1702
1703 retry = htod32(retry);
1704 err = wldev_ioctl(dev, cmd, &retry, sizeof(retry), false);
1705 if (unlikely(err)) {
1706 WL_ERR(("cmd (%d) , error (%d)\n", cmd, err));
1707 return err;
1708 }
1709 return err;
1710}
1711
1712static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
1713{
1714 struct wl_priv *wl = (struct wl_priv *)wiphy_priv(wiphy);
1715 struct net_device *ndev = wl_to_prmry_ndev(wl);
1716 s32 err = 0;
1717
1718 CHECK_SYS_UP(wl);
1719 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
1720 (wl->conf->rts_threshold != wiphy->rts_threshold)) {
1721 wl->conf->rts_threshold = wiphy->rts_threshold;
1722 err = wl_set_rts(ndev, wl->conf->rts_threshold);
1723 if (!err)
1724 return err;
1725 }
1726 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
1727 (wl->conf->frag_threshold != wiphy->frag_threshold)) {
1728 wl->conf->frag_threshold = wiphy->frag_threshold;
1729 err = wl_set_frag(ndev, wl->conf->frag_threshold);
1730 if (!err)
1731 return err;
1732 }
1733 if (changed & WIPHY_PARAM_RETRY_LONG &&
1734 (wl->conf->retry_long != wiphy->retry_long)) {
1735 wl->conf->retry_long = wiphy->retry_long;
1736 err = wl_set_retry(ndev, wl->conf->retry_long, true);
1737 if (!err)
1738 return err;
1739 }
1740 if (changed & WIPHY_PARAM_RETRY_SHORT &&
1741 (wl->conf->retry_short != wiphy->retry_short)) {
1742 wl->conf->retry_short = wiphy->retry_short;
1743 err = wl_set_retry(ndev, wl->conf->retry_short, false);
1744 if (!err) {
1745 return err;
1746 }
1747 }
1748
1749 return err;
1750}
1751
1752static s32
1753wl_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
1754 struct cfg80211_ibss_params *params)
1755{
1756 struct wl_priv *wl = wiphy_priv(wiphy);
1757 struct cfg80211_bss *bss;
1758 struct ieee80211_channel *chan;
1759 struct wl_join_params join_params;
1760 struct cfg80211_ssid ssid;
1761 s32 scan_retry = 0;
1762 s32 err = 0;
1763 bool rollback_lock = false;
1764
1765 WL_TRACE(("In\n"));
1766 CHECK_SYS_UP(wl);
1767 if (params->bssid) {
1768 WL_ERR(("Invalid bssid\n"));
1769 return -EOPNOTSUPP;
1770 }
1771 bss = cfg80211_get_ibss(wiphy, NULL, params->ssid, params->ssid_len);
1772 if (!bss) {
1773 memcpy(ssid.ssid, params->ssid, params->ssid_len);
1774 ssid.ssid_len = params->ssid_len;
1775 do {
1776 if (unlikely
1777 (__wl_cfg80211_scan(wiphy, dev, NULL, &ssid) ==
1778 -EBUSY)) {
1779 wl_delay(150);
1780 } else {
1781 break;
1782 }
1783 } while (++scan_retry < WL_SCAN_RETRY_MAX);
1784 /* to allow scan_inform to propagate to cfg80211 plane */
1785 if (rtnl_is_locked()) {
1786 rtnl_unlock();
1787 rollback_lock = true;
1788 }
1789
1790 /* wait 4 secons till scan done.... */
1791 schedule_timeout_interruptible(4 * HZ);
1792 if (rollback_lock)
1793 rtnl_lock();
1794 bss = cfg80211_get_ibss(wiphy, NULL,
1795 params->ssid, params->ssid_len);
1796 }
1797 if (bss) {
1798 wl->ibss_starter = false;
1799 WL_DBG(("Found IBSS\n"));
1800 } else {
1801 wl->ibss_starter = true;
1802 }
1803 chan = params->channel;
1804 if (chan)
1805 wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
1806 /*
1807 * Join with specific BSSID and cached SSID
1808 * If SSID is zero join based on BSSID only
1809 */
1810 memset(&join_params, 0, sizeof(join_params));
1811 memcpy((void *)join_params.ssid.SSID, (void *)params->ssid,
1812 params->ssid_len);
1813 join_params.ssid.SSID_len = htod32(params->ssid_len);
1814 if (params->bssid)
1815 memcpy(&join_params.params.bssid, params->bssid,
1816 ETHER_ADDR_LEN);
1817 else
1818 memset(&join_params.params.bssid, 0, ETHER_ADDR_LEN);
1819
1820 err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
1821 sizeof(join_params), false);
1822 if (unlikely(err)) {
1823 WL_ERR(("Error (%d)\n", err));
1824 return err;
1825 }
1826 return err;
1827}
1828
1829static s32 wl_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
1830{
1831 struct wl_priv *wl = wiphy_priv(wiphy);
1832 s32 err = 0;
1833
1834 CHECK_SYS_UP(wl);
1835 wl_link_down(wl);
1836
1837 return err;
1838}
1839
1840static s32
1841wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme)
1842{
1843 struct wl_priv *wl = wlcfg_drv_priv;
1844 struct wl_security *sec;
1845 s32 val = 0;
1846 s32 err = 0;
1847 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
1848
1849 if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1)
1850 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1851 else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)
1852 val = WPA2_AUTH_PSK| WPA2_AUTH_UNSPECIFIED;
1853 else
1854 val = WPA_AUTH_DISABLED;
1855
1856 if (is_wps_conn(sme))
1857 val = WPA_AUTH_DISABLED;
1858
1859 WL_DBG(("setting wpa_auth to 0x%0x\n", val));
1860 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
1861 if (unlikely(err)) {
1862 WL_ERR(("set wpa_auth failed (%d)\n", err));
1863 return err;
1864 }
1865 sec = wl_read_prof(wl, WL_PROF_SEC);
1866 sec->wpa_versions = sme->crypto.wpa_versions;
1867 return err;
1868}
1869
1870static s32
1871wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme)
1872{
1873 struct wl_priv *wl = wlcfg_drv_priv;
1874 struct wl_security *sec;
1875 s32 val = 0;
1876 s32 err = 0;
1877 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
1878 switch (sme->auth_type) {
1879 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1880 val = 0;
1881 WL_DBG(("open system\n"));
1882 break;
1883 case NL80211_AUTHTYPE_SHARED_KEY:
1884 val = 1;
1885 WL_DBG(("shared key\n"));
1886 break;
1887 case NL80211_AUTHTYPE_AUTOMATIC:
1888 val = 2;
1889 WL_DBG(("automatic\n"));
1890 break;
1891 case NL80211_AUTHTYPE_NETWORK_EAP:
1892 WL_DBG(("network eap\n"));
1893 default:
1894 val = 2;
1895 WL_ERR(("invalid auth type (%d)\n", sme->auth_type));
1896 break;
1897 }
1898
1899 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
1900 if (unlikely(err)) {
1901 WL_ERR(("set auth failed (%d)\n", err));
1902 return err;
1903 }
1904 sec = wl_read_prof(wl, WL_PROF_SEC);
1905 sec->auth_type = sme->auth_type;
1906 return err;
1907}
1908
1909static s32
1910wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme)
1911{
1912 struct wl_priv *wl = wlcfg_drv_priv;
1913 struct wl_security *sec;
1914 s32 pval = 0;
1915 s32 gval = 0;
1916 s32 err = 0;
1917 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
1918
1919 if (sme->crypto.n_ciphers_pairwise) {
1920 switch (sme->crypto.ciphers_pairwise[0]) {
1921 case WLAN_CIPHER_SUITE_WEP40:
1922 case WLAN_CIPHER_SUITE_WEP104:
1923 pval = WEP_ENABLED;
1924 break;
1925 case WLAN_CIPHER_SUITE_TKIP:
1926 pval = TKIP_ENABLED;
1927 break;
1928 case WLAN_CIPHER_SUITE_CCMP:
1929 pval = AES_ENABLED;
1930 break;
1931 case WLAN_CIPHER_SUITE_AES_CMAC:
1932 pval = AES_ENABLED;
1933 break;
1934 default:
1935 WL_ERR(("invalid cipher pairwise (%d)\n",
1936 sme->crypto.ciphers_pairwise[0]));
1937 return -EINVAL;
1938 }
1939 }
1940 if (sme->crypto.cipher_group) {
1941 switch (sme->crypto.cipher_group) {
1942 case WLAN_CIPHER_SUITE_WEP40:
1943 case WLAN_CIPHER_SUITE_WEP104:
1944 gval = WEP_ENABLED;
1945 break;
1946 case WLAN_CIPHER_SUITE_TKIP:
1947 gval = TKIP_ENABLED;
1948 break;
1949 case WLAN_CIPHER_SUITE_CCMP:
1950 gval = AES_ENABLED;
1951 break;
1952 case WLAN_CIPHER_SUITE_AES_CMAC:
1953 gval = AES_ENABLED;
1954 break;
1955 default:
1956 WL_ERR(("invalid cipher group (%d)\n",
1957 sme->crypto.cipher_group));
1958 return -EINVAL;
1959 }
1960 }
1961
1962 WL_DBG(("pval (%d) gval (%d)\n", pval, gval));
1963
1964 if (is_wps_conn(sme)) {
1965 err = wldev_iovar_setint_bsscfg(dev, "wsec", 4, bssidx);
1966 } else {
1967 WL_DBG((" NO, is_wps_conn, Set pval | gval to WSEC"));
1968 err = wldev_iovar_setint_bsscfg(dev, "wsec",
1969 pval | gval, bssidx);
1970 }
1971 if (unlikely(err)) {
1972 WL_ERR(("error (%d)\n", err));
1973 return err;
1974 }
1975
1976 sec = wl_read_prof(wl, WL_PROF_SEC);
1977 sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0];
1978 sec->cipher_group = sme->crypto.cipher_group;
1979
1980 return err;
1981}
1982
1983static s32
1984wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme)
1985{
1986 struct wl_priv *wl = wlcfg_drv_priv;
1987 struct wl_security *sec;
1988 s32 val = 0;
1989 s32 err = 0;
1990 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
1991
1992 if (sme->crypto.n_akm_suites) {
1993 err = wl_dev_intvar_get(dev, "wpa_auth", &val);
1994 if (unlikely(err)) {
1995 WL_ERR(("could not get wpa_auth (%d)\n", err));
1996 return err;
1997 }
1998 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
1999 switch (sme->crypto.akm_suites[0]) {
2000 case WLAN_AKM_SUITE_8021X:
2001 val = WPA_AUTH_UNSPECIFIED;
2002 break;
2003 case WLAN_AKM_SUITE_PSK:
2004 val = WPA_AUTH_PSK;
2005 break;
2006 default:
2007 WL_ERR(("invalid cipher group (%d)\n",
2008 sme->crypto.cipher_group));
2009 return -EINVAL;
2010 }
2011 } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
2012 switch (sme->crypto.akm_suites[0]) {
2013 case WLAN_AKM_SUITE_8021X:
2014 val = WPA2_AUTH_UNSPECIFIED;
2015 break;
2016 case WLAN_AKM_SUITE_PSK:
2017 val = WPA2_AUTH_PSK;
2018 break;
2019 default:
2020 WL_ERR(("invalid cipher group (%d)\n",
2021 sme->crypto.cipher_group));
2022 return -EINVAL;
2023 }
2024 }
2025 WL_DBG(("setting wpa_auth to %d\n", val));
2026
2027 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", val, bssidx);
2028 if (unlikely(err)) {
2029 WL_ERR(("could not set wpa_auth (%d)\n", err));
2030 return err;
2031 }
2032 }
2033 sec = wl_read_prof(wl, WL_PROF_SEC);
2034 sec->wpa_auth = sme->crypto.akm_suites[0];
2035
2036 return err;
2037}
2038
2039static s32
2040wl_set_set_sharedkey(struct net_device *dev,
2041 struct cfg80211_connect_params *sme)
2042{
2043 struct wl_priv *wl = wlcfg_drv_priv;
2044 struct wl_security *sec;
2045 struct wl_wsec_key key;
2046 s32 val;
2047 s32 err = 0;
2048 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
2049
2050 WL_DBG(("key len (%d)\n", sme->key_len));
2051 if (sme->key_len) {
2052 sec = wl_read_prof(wl, WL_PROF_SEC);
2053 WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n",
2054 sec->wpa_versions, sec->cipher_pairwise));
2055 if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 |
2056 NL80211_WPA_VERSION_2)) &&
2057 (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 |
2058 WLAN_CIPHER_SUITE_WEP104))) {
2059 memset(&key, 0, sizeof(key));
2060 key.len = (u32) sme->key_len;
2061 key.index = (u32) sme->key_idx;
2062 if (unlikely(key.len > sizeof(key.data))) {
2063 WL_ERR(("Too long key length (%u)\n", key.len));
2064 return -EINVAL;
2065 }
2066 memcpy(key.data, sme->key, key.len);
2067 key.flags = WL_PRIMARY_KEY;
2068 switch (sec->cipher_pairwise) {
2069 case WLAN_CIPHER_SUITE_WEP40:
2070 key.algo = CRYPTO_ALGO_WEP1;
2071 break;
2072 case WLAN_CIPHER_SUITE_WEP104:
2073 key.algo = CRYPTO_ALGO_WEP128;
2074 break;
2075 default:
2076 WL_ERR(("Invalid algorithm (%d)\n",
2077 sme->crypto.ciphers_pairwise[0]));
2078 return -EINVAL;
2079 }
2080 /* Set the new key/index */
2081 WL_DBG(("key length (%d) key index (%d) algo (%d)\n",
2082 key.len, key.index, key.algo));
2083 WL_DBG(("key \"%s\"\n", key.data));
2084 swap_key_from_BE(&key);
2085 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key),
2086 ioctlbuf, sizeof(ioctlbuf), bssidx);
2087 if (unlikely(err)) {
2088 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
2089 return err;
2090 }
2091 if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) {
2092 WL_DBG(("set auth_type to shared key\n"));
2093 val = 1; /* shared key */
2094 err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx);
2095 if (unlikely(err)) {
2096 WL_ERR(("set auth failed (%d)\n", err));
2097 return err;
2098 }
2099 }
2100 }
2101 }
2102 return err;
2103}
2104
2105static s32
2106wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
2107 struct cfg80211_connect_params *sme)
2108{
2109 struct wl_priv *wl = wiphy_priv(wiphy);
2110 struct ieee80211_channel *chan = sme->channel;
2111 wl_extjoin_params_t *ext_join_params;
2112 struct wl_join_params join_params;
2113 size_t join_params_size;
2114 s32 err = 0;
2115 wpa_ie_fixed_t *wpa_ie;
2116 wpa_ie_fixed_t *wps_ie;
2117 bcm_tlv_t *wpa2_ie;
2118 u8* wpaie = 0;
2119 u32 wpaie_len = 0;
2120 u32 wpsie_len = 0;
2121 u32 chan_cnt = 0;
2122 u8 wpsie[IE_MAX_LEN];
2123 struct ether_addr bssid;
2124
2125 WL_DBG(("In\n"));
2126 CHECK_SYS_UP(wl);
2127
2128 /*
2129 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
2130 */
2131 if (wl->scan_request) {
2132 wl_cfg80211_scan_abort(wl, dev);
2133 }
2134 /* Clean BSSID */
2135 bzero(&bssid, sizeof(bssid));
2136 wl_update_prof(wl, NULL, (void *)&bssid, WL_PROF_BSSID);
2137
2138 if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) {
2139 /* we only allow to connect using virtual interface in case of P2P */
2140 if (p2p_on(wl) && is_wps_conn(sme)) {
2141 WL_DBG(("ASSOC1 p2p index : %d sme->ie_len %d\n",
2142 wl_cfgp2p_find_idx(wl, dev), sme->ie_len));
2143 /* Have to apply WPS IE + P2P IE in assoc req frame */
2144 wl_cfgp2p_set_management_ie(wl, dev,
2145 wl_cfgp2p_find_idx(wl, dev), VNDR_IE_PRBREQ_FLAG,
2146 wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie,
2147 wl_to_p2p_bss_saved_ie(wl,
2148 P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len);
2149 wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
2150 VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
2151 } else if (p2p_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) {
2152 /* This is the connect req after WPS is done [credentials exchanged]
2153 * currently identified with WPA_VERSION_2 .
2154 * Update the previously set IEs with
2155 * the newly received IEs from Supplicant. This will remove the WPS IE from
2156 * the Assoc Req.
2157 */
2158 WL_DBG(("ASSOC2 p2p index : %d sme->ie_len %d\n",
2159 wl_cfgp2p_find_idx(wl, dev), sme->ie_len));
2160 wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev),
2161 VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len);
2162 }
2163
2164 } else if (dev == wl_to_prmry_ndev(wl)) {
2165 /* find the RSN_IE */
2166 if ((wpa2_ie = bcm_parse_tlvs((u8 *)sme->ie, sme->ie_len,
2167 DOT11_MNG_RSN_ID)) != NULL) {
2168 WL_DBG((" WPA2 IE is found\n"));
2169 }
2170 /* find the WPA_IE */
2171 if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)sme->ie,
2172 sme->ie_len)) != NULL) {
2173 WL_DBG((" WPA IE is found\n"));
2174 }
2175 if (wpa_ie != NULL || wpa2_ie != NULL) {
2176 wpaie = (wpa_ie != NULL) ? (u8 *)wpa_ie : (u8 *)wpa2_ie;
2177 wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len;
2178 wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN;
2179 wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len,
2180 ioctlbuf, sizeof(ioctlbuf));
2181 } else {
2182 wldev_iovar_setbuf(dev, "wpaie", NULL, 0,
2183 ioctlbuf, sizeof(ioctlbuf));
2184 }
2185
2186 /* find the WPSIE */
2187 memset(wpsie, 0, sizeof(wpsie));
2188 if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)sme->ie,
2189 sme->ie_len)) != NULL) {
2190 wpsie_len = wps_ie->length +WPA_RSN_IE_TAG_FIXED_LEN;
2191 memcpy(wpsie, wps_ie, wpsie_len);
2192 } else {
2193 wpsie_len = 0;
2194 }
2195 err = wl_cfgp2p_set_management_ie(wl, dev, -1,
2196 VNDR_IE_ASSOCREQ_FLAG, wpsie, wpsie_len);
2197 if (unlikely(err)) {
2198 return err;
2199 }
2200 }
2201 if (unlikely(!sme->ssid)) {
2202 WL_ERR(("Invalid ssid\n"));
2203 return -EOPNOTSUPP;
2204 }
2205 if (chan) {
2206 wl->channel = ieee80211_frequency_to_channel(chan->center_freq);
2207 chan_cnt = 1;
2208 WL_DBG(("channel (%d), center_req (%d)\n", wl->channel,
2209 chan->center_freq));
2210 } else
2211 wl->channel = 0;
2212 WL_DBG(("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len));
2213 err = wl_set_wpa_version(dev, sme);
2214 if (unlikely(err)) {
2215 WL_ERR(("Invalid wpa_version\n"));
2216 return err;
2217 }
2218
2219 err = wl_set_auth_type(dev, sme);
2220 if (unlikely(err)) {
2221 WL_ERR(("Invalid auth type\n"));
2222 return err;
2223 }
2224
2225 err = wl_set_set_cipher(dev, sme);
2226 if (unlikely(err)) {
2227 WL_ERR(("Invalid ciper\n"));
2228 return err;
2229 }
2230
2231 err = wl_set_key_mgmt(dev, sme);
2232 if (unlikely(err)) {
2233 WL_ERR(("Invalid key mgmt\n"));
2234 return err;
2235 }
2236
2237 err = wl_set_set_sharedkey(dev, sme);
2238 if (unlikely(err)) {
2239 WL_ERR(("Invalid shared key\n"));
2240 return err;
2241 }
2242
2243 /*
2244 * Join with specific BSSID and cached SSID
2245 * If SSID is zero join based on BSSID only
2246 */
2247 join_params_size = WL_EXTJOIN_PARAMS_FIXED_SIZE +
2248 chan_cnt * sizeof(chanspec_t);
2249 ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL);
2250 if (ext_join_params == NULL) {
2251 err = -ENOMEM;
2252 wl_clr_drv_status(wl, CONNECTING);
2253 goto exit;
2254 }
2255 ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len);
2256 memcpy(&ext_join_params->ssid.SSID, sme->ssid, ext_join_params->ssid.SSID_len);
2257 ext_join_params->ssid.SSID_len = htod32(ext_join_params->ssid.SSID_len);
2258 /* Set up join scan parameters */
2259 ext_join_params->scan.scan_type = -1;
2260 ext_join_params->scan.nprobes = 2;
2261 /* increate dwell time to receive probe response
2262 * from target AP at a noisy air
2263 */
2264 ext_join_params->scan.active_time = 150;
2265 ext_join_params->scan.passive_time = 300;
2266 ext_join_params->scan.home_time = -1;
2267 if (sme->bssid)
2268 memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN);
2269 else
2270 memcpy(&ext_join_params->assoc.bssid, &ether_bcast, ETH_ALEN);
2271 ext_join_params->assoc.chanspec_num = chan_cnt;
2272 if (chan_cnt) {
2273 u16 channel, band, bw, ctl_sb;
2274 chanspec_t chspec;
2275 channel = wl->channel;
2276 band = (channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G
2277 : WL_CHANSPEC_BAND_5G;
2278 bw = WL_CHANSPEC_BW_20;
2279 ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
2280 chspec = (channel | band | bw | ctl_sb);
2281 ext_join_params->assoc.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
2282 ext_join_params->assoc.chanspec_list[0] |= chspec;
2283 ext_join_params->assoc.chanspec_list[0] =
2284 htodchanspec(ext_join_params->assoc.chanspec_list[0]);
2285 }
2286 ext_join_params->assoc.chanspec_num = htod32(ext_join_params->assoc.chanspec_num);
2287 if (ext_join_params->ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
2288 WL_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID,
2289 ext_join_params->ssid.SSID_len));
2290 }
2291 wl_set_drv_status(wl, CONNECTING);
2292 err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, ioctlbuf,
2293 sizeof(ioctlbuf), wl_cfgp2p_find_idx(wl, dev));
2294 kfree(ext_join_params);
2295 if (err) {
2296 wl_clr_drv_status(wl, CONNECTING);
2297 if (err == BCME_UNSUPPORTED) {
2298 WL_DBG(("join iovar is not supported\n"));
2299 goto set_ssid;
2300 } else
2301 WL_ERR(("error (%d)\n", err));
2302 } else
2303 goto exit;
2304
2305set_ssid:
2306 memset(&join_params, 0, sizeof(join_params));
2307 join_params_size = sizeof(join_params.ssid);
2308
2309 join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len);
2310 memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len);
2311 join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len);
2312 wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID);
2313 if (sme->bssid)
2314 memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN);
2315 else
2316 memcpy(&join_params.params.bssid, &ether_bcast, ETH_ALEN);
2317
2318 wl_ch_to_chanspec(wl->channel, &join_params, &join_params_size);
2319 WL_DBG(("join_param_size %d\n", join_params_size));
2320
2321 if (join_params.ssid.SSID_len < IEEE80211_MAX_SSID_LEN) {
2322 WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID,
2323 join_params.ssid.SSID_len));
2324 }
2325 wl_set_drv_status(wl, CONNECTING);
2326 err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true);
2327 if (err) {
2328 WL_ERR(("error (%d)\n", err));
2329 wl_clr_drv_status(wl, CONNECTING);
2330 }
2331exit:
2332 return err;
2333}
2334
2335static s32
2336wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
2337 u16 reason_code)
2338{
2339 struct wl_priv *wl = wiphy_priv(wiphy);
2340 scb_val_t scbval;
2341 bool act = false;
2342 s32 err = 0;
2343 u8 *curbssid;
2344 WL_ERR(("Reason %d\n", reason_code));
2345 CHECK_SYS_UP(wl);
2346 act = *(bool *) wl_read_prof(wl, WL_PROF_ACT);
2347 curbssid = wl_read_prof(wl, WL_PROF_BSSID);
2348 if (likely(act)) {
2349 /*
2350 * Cancel ongoing scan to sync up with sme state machine of cfg80211.
2351 */
2352 if (wl->scan_request) {
2353 wl_cfg80211_scan_abort(wl, dev);
2354 }
2355 wl_set_drv_status(wl, DISCONNECTING);
2356 scbval.val = reason_code;
2357 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
2358 scbval.val = htod32(scbval.val);
2359 err = wldev_ioctl(dev, WLC_DISASSOC, &scbval,
2360 sizeof(scb_val_t), true);
2361 if (unlikely(err)) {
2362 wl_clr_drv_status(wl, DISCONNECTING);
2363 WL_ERR(("error (%d)\n", err));
2364 return err;
2365 }
2366 }
2367
2368 return err;
2369}
2370
2371static s32
2372wl_cfg80211_set_tx_power(struct wiphy *wiphy,
2373 enum nl80211_tx_power_setting type, s32 dbm)
2374{
2375
2376 struct wl_priv *wl = wiphy_priv(wiphy);
2377 struct net_device *ndev = wl_to_prmry_ndev(wl);
2378 u16 txpwrmw;
2379 s32 err = 0;
2380 s32 disable = 0;
2381
2382 CHECK_SYS_UP(wl);
2383 switch (type) {
2384 case NL80211_TX_POWER_AUTOMATIC:
2385 break;
2386 case NL80211_TX_POWER_LIMITED:
2387 if (dbm < 0) {
2388 WL_ERR(("TX_POWER_LIMITTED - dbm is negative\n"));
2389 return -EINVAL;
2390 }
2391 break;
2392 case NL80211_TX_POWER_FIXED:
2393 if (dbm < 0) {
2394 WL_ERR(("TX_POWER_FIXED - dbm is negative..\n"));
2395 return -EINVAL;
2396 }
2397 break;
2398 }
2399 /* Make sure radio is off or on as far as software is concerned */
2400 disable = WL_RADIO_SW_DISABLE << 16;
2401 disable = htod32(disable);
2402 err = wldev_ioctl(ndev, WLC_SET_RADIO, &disable, sizeof(disable), true);
2403 if (unlikely(err)) {
2404 WL_ERR(("WLC_SET_RADIO error (%d)\n", err));
2405 return err;
2406 }
2407
2408 if (dbm > 0xffff)
2409 txpwrmw = 0xffff;
2410 else
2411 txpwrmw = (u16) dbm;
2412 err = wl_dev_intvar_set(ndev, "qtxpower",
2413 (s32) (bcm_mw_to_qdbm(txpwrmw)));
2414 if (unlikely(err)) {
2415 WL_ERR(("qtxpower error (%d)\n", err));
2416 return err;
2417 }
2418 wl->conf->tx_power = dbm;
2419
2420 return err;
2421}
2422
2423static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
2424{
2425 struct wl_priv *wl = wiphy_priv(wiphy);
2426 struct net_device *ndev = wl_to_prmry_ndev(wl);
2427 s32 txpwrdbm;
2428 u8 result;
2429 s32 err = 0;
2430
2431 CHECK_SYS_UP(wl);
2432 err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm);
2433 if (unlikely(err)) {
2434 WL_ERR(("error (%d)\n", err));
2435 return err;
2436 }
2437 result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE);
2438 *dbm = (s32) bcm_qdbm_to_mw(result);
2439
2440 return err;
2441}
2442
2443static s32
2444wl_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *dev,
2445 u8 key_idx, bool unicast, bool multicast)
2446{
2447 struct wl_priv *wl = wiphy_priv(wiphy);
2448 u32 index;
2449 s32 wsec;
2450 s32 err = 0;
2451 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
2452
2453 WL_DBG(("key index (%d)\n", key_idx));
2454 CHECK_SYS_UP(wl);
2455 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
2456 if (unlikely(err)) {
2457 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
2458 return err;
2459 }
2460 if (wsec & WEP_ENABLED) {
2461 /* Just select a new current key */
2462 index = (u32) key_idx;
2463 index = htod32(index);
2464 err = wldev_ioctl(dev, WLC_SET_KEY_PRIMARY, &index,
2465 sizeof(index), true);
2466 if (unlikely(err)) {
2467 WL_ERR(("error (%d)\n", err));
2468 }
2469 }
2470 return err;
2471}
2472
2473static s32
2474wl_add_keyext(struct wiphy *wiphy, struct net_device *dev,
2475 u8 key_idx, const u8 *mac_addr, struct key_params *params)
2476{
2477 struct wl_priv *wl = wiphy_priv(wiphy);
2478 struct wl_wsec_key key;
2479 s32 err = 0;
2480 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
2481 s32 mode = get_mode_by_netdev(wl, dev);
2482 memset(&key, 0, sizeof(key));
2483 key.index = (u32) key_idx;
2484
2485 if (!ETHER_ISMULTI(mac_addr))
2486 memcpy((char *)&key.ea, (void *)mac_addr, ETHER_ADDR_LEN);
2487 key.len = (u32) params->key_len;
2488
2489 /* check for key index change */
2490 if (key.len == 0) {
2491 /* key delete */
2492 swap_key_from_BE(&key);
2493 wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
2494 sizeof(ioctlbuf), bssidx);
2495 if (unlikely(err)) {
2496 WL_ERR(("key delete error (%d)\n", err));
2497 return err;
2498 }
2499 } else {
2500 if (key.len > sizeof(key.data)) {
2501 WL_ERR(("Invalid key length (%d)\n", key.len));
2502 return -EINVAL;
2503 }
2504 WL_DBG(("Setting the key index %d\n", key.index));
2505 memcpy(key.data, params->key, key.len);
2506
2507 if ((mode == WL_MODE_BSS) &&
2508 (params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
2509 u8 keybuf[8];
2510 memcpy(keybuf, &key.data[24], sizeof(keybuf));
2511 memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
2512 memcpy(&key.data[16], keybuf, sizeof(keybuf));
2513 }
2514
2515 /* if IW_ENCODE_EXT_RX_SEQ_VALID set */
2516 if (params->seq && params->seq_len == 6) {
2517 /* rx iv */
2518 u8 *ivptr;
2519 ivptr = (u8 *) params->seq;
2520 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
2521 (ivptr[3] << 8) | ivptr[2];
2522 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
2523 key.iv_initialized = true;
2524 }
2525
2526 switch (params->cipher) {
2527 case WLAN_CIPHER_SUITE_WEP40:
2528 key.algo = CRYPTO_ALGO_WEP1;
2529 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
2530 break;
2531 case WLAN_CIPHER_SUITE_WEP104:
2532 key.algo = CRYPTO_ALGO_WEP128;
2533 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
2534 break;
2535 case WLAN_CIPHER_SUITE_TKIP:
2536 key.algo = CRYPTO_ALGO_TKIP;
2537 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
2538 break;
2539 case WLAN_CIPHER_SUITE_AES_CMAC:
2540 key.algo = CRYPTO_ALGO_AES_CCM;
2541 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
2542 break;
2543 case WLAN_CIPHER_SUITE_CCMP:
2544 key.algo = CRYPTO_ALGO_AES_CCM;
2545 WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
2546 break;
2547 default:
2548 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
2549 return -EINVAL;
2550 }
2551 swap_key_from_BE(&key);
2552#ifdef CONFIG_WIRELESS_EXT
2553 dhd_wait_pend8021x(dev);
2554#endif
2555 wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
2556 sizeof(ioctlbuf), bssidx);
2557 if (unlikely(err)) {
2558 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
2559 return err;
2560 }
2561 }
2562 return err;
2563}
2564
2565static s32
2566wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev,
2567 u8 key_idx, bool pairwise, const u8 *mac_addr,
2568 struct key_params *params)
2569{
2570 struct wl_wsec_key key;
2571 s32 val = 0;
2572 s32 wsec = 0;
2573 s32 err = 0;
2574 u8 keybuf[8];
2575 s32 bssidx = 0;
2576 struct wl_priv *wl = wiphy_priv(wiphy);
2577 s32 mode = get_mode_by_netdev(wl, dev);
2578 WL_DBG(("key index (%d)\n", key_idx));
2579 CHECK_SYS_UP(wl);
2580
2581 bssidx = wl_cfgp2p_find_idx(wl, dev);
2582
2583 if (mac_addr) {
2584 wl_add_keyext(wiphy, dev, key_idx, mac_addr, params);
2585 goto exit;
2586 }
2587 memset(&key, 0, sizeof(key));
2588
2589 key.len = (u32) params->key_len;
2590 key.index = (u32) key_idx;
2591
2592 if (unlikely(key.len > sizeof(key.data))) {
2593 WL_ERR(("Too long key length (%u)\n", key.len));
2594 return -EINVAL;
2595 }
2596 memcpy(key.data, params->key, key.len);
2597
2598 key.flags = WL_PRIMARY_KEY;
2599 switch (params->cipher) {
2600 case WLAN_CIPHER_SUITE_WEP40:
2601 key.algo = CRYPTO_ALGO_WEP1;
2602 val = WEP_ENABLED;
2603 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
2604 break;
2605 case WLAN_CIPHER_SUITE_WEP104:
2606 key.algo = CRYPTO_ALGO_WEP128;
2607 val = WEP_ENABLED;
2608 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
2609 break;
2610 case WLAN_CIPHER_SUITE_TKIP:
2611 key.algo = CRYPTO_ALGO_TKIP;
2612 val = TKIP_ENABLED;
2613 /* wpa_supplicant switches the third and fourth quarters of the TKIP key */
2614 if (mode == WL_MODE_BSS) {
2615 bcopy(&key.data[24], keybuf, sizeof(keybuf));
2616 bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
2617 bcopy(keybuf, &key.data[16], sizeof(keybuf));
2618 }
2619 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
2620 break;
2621 case WLAN_CIPHER_SUITE_AES_CMAC:
2622 key.algo = CRYPTO_ALGO_AES_CCM;
2623 val = AES_ENABLED;
2624 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
2625 break;
2626 case WLAN_CIPHER_SUITE_CCMP:
2627 key.algo = CRYPTO_ALGO_AES_CCM;
2628 val = AES_ENABLED;
2629 WL_DBG(("WLAN_CIPHER_SUITE_CCMP\n"));
2630 break;
2631 default:
2632 WL_ERR(("Invalid cipher (0x%x)\n", params->cipher));
2633 return -EINVAL;
2634 }
2635
2636 /* Set the new key/index */
2637 swap_key_from_BE(&key);
2638 err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
2639 sizeof(ioctlbuf), bssidx);
2640 if (unlikely(err)) {
2641 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
2642 return err;
2643 }
2644
2645exit:
2646 err = wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
2647 if (unlikely(err)) {
2648 WL_ERR(("get wsec error (%d)\n", err));
2649 return err;
2650 }
2651
2652 wsec |= val;
2653 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
2654 if (unlikely(err)) {
2655 WL_ERR(("set wsec error (%d)\n", err));
2656 return err;
2657 }
2658
2659 return err;
2660}
2661
2662static s32
2663wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev,
2664 u8 key_idx, bool pairwise, const u8 *mac_addr)
2665{
2666 struct wl_wsec_key key;
2667 struct wl_priv *wl = wiphy_priv(wiphy);
2668 s32 err = 0;
2669 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
2670
2671 WL_DBG(("Enter\n"));
2672 CHECK_SYS_UP(wl);
2673 memset(&key, 0, sizeof(key));
2674
2675 key.index = (u32) key_idx;
2676 key.flags = WL_PRIMARY_KEY;
2677 key.algo = CRYPTO_ALGO_OFF;
2678
2679 WL_DBG(("key index (%d)\n", key_idx));
2680 /* Set the new key/index */
2681 swap_key_from_BE(&key);
2682 wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf,
2683 sizeof(ioctlbuf), bssidx);
2684 if (unlikely(err)) {
2685 if (err == -EINVAL) {
2686 if (key.index >= DOT11_MAX_DEFAULT_KEYS) {
2687 /* we ignore this key index in this case */
2688 WL_DBG(("invalid key index (%d)\n", key_idx));
2689 }
2690 } else {
2691 WL_ERR(("WLC_SET_KEY error (%d)\n", err));
2692 }
2693 return err;
2694 }
2695 return err;
2696}
2697
2698static s32
2699wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev,
2700 u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
2701 void (*callback) (void *cookie, struct key_params * params))
2702{
2703 struct key_params params;
2704 struct wl_wsec_key key;
2705 struct wl_priv *wl = wiphy_priv(wiphy);
2706 struct wl_security *sec;
2707 s32 wsec;
2708 s32 err = 0;
2709 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
2710
2711 WL_DBG(("key index (%d)\n", key_idx));
2712 CHECK_SYS_UP(wl);
2713 memset(&key, 0, sizeof(key));
2714 key.index = key_idx;
2715 swap_key_to_BE(&key);
2716 memset(&params, 0, sizeof(params));
2717 params.key_len = (u8) min_t(u8, DOT11_MAX_KEY_SIZE, key.len);
2718 memcpy(params.key, key.data, params.key_len);
2719
2720 wldev_iovar_getint_bsscfg(dev, "wsec", &wsec, bssidx);
2721 if (unlikely(err)) {
2722 WL_ERR(("WLC_GET_WSEC error (%d)\n", err));
2723 return err;
2724 }
2725 switch (wsec & ~SES_OW_ENABLED) {
2726 case WEP_ENABLED:
2727 sec = wl_read_prof(wl, WL_PROF_SEC);
2728 if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) {
2729 params.cipher = WLAN_CIPHER_SUITE_WEP40;
2730 WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n"));
2731 } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) {
2732 params.cipher = WLAN_CIPHER_SUITE_WEP104;
2733 WL_DBG(("WLAN_CIPHER_SUITE_WEP104\n"));
2734 }
2735 break;
2736 case TKIP_ENABLED:
2737 params.cipher = WLAN_CIPHER_SUITE_TKIP;
2738 WL_DBG(("WLAN_CIPHER_SUITE_TKIP\n"));
2739 break;
2740 case AES_ENABLED:
2741 params.cipher = WLAN_CIPHER_SUITE_AES_CMAC;
2742 WL_DBG(("WLAN_CIPHER_SUITE_AES_CMAC\n"));
2743 break;
2744 default:
2745 WL_ERR(("Invalid algo (0x%x)\n", wsec));
2746 return -EINVAL;
2747 }
2748
2749 callback(cookie, &params);
2750 return err;
2751}
2752
2753static s32
2754wl_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
2755 struct net_device *dev, u8 key_idx)
2756{
2757 WL_INFO(("Not supported\n"));
2758 return -EOPNOTSUPP;
2759}
2760
2761static s32
2762wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
2763 u8 *mac, struct station_info *sinfo)
2764{
2765 struct wl_priv *wl = wiphy_priv(wiphy);
2766 scb_val_t scb_val;
2767 s32 rssi;
2768 s32 rate;
2769 s32 err = 0;
2770 sta_info_t *sta;
2771#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
2772 s8 eabuf[ETHER_ADDR_STR_LEN];
2773#endif
2774 dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
2775
2776 CHECK_SYS_UP(wl);
2777 if (get_mode_by_netdev(wl, dev) == WL_MODE_AP) {
2778 err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac,
2779 ETHER_ADDR_LEN, ioctlbuf, sizeof(ioctlbuf));
2780 if (err < 0) {
2781 WL_ERR(("GET STA INFO failed, %d\n", err));
2782 return err;
2783 }
2784 sinfo->filled = STATION_INFO_INACTIVE_TIME;
2785 sta = (sta_info_t *)ioctlbuf;
2786 sta->len = dtoh16(sta->len);
2787 sta->cap = dtoh16(sta->cap);
2788 sta->flags = dtoh32(sta->flags);
2789 sta->idle = dtoh32(sta->idle);
2790 sta->in = dtoh32(sta->in);
2791 sinfo->inactive_time = sta->idle * 1000;
2792#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 0, 0)
2793 if (sta->flags & WL_STA_ASSOC) {
2794 sinfo->filled |= STATION_INFO_CONNECTED_TIME;
2795 sinfo->connected_time = sta->in;
2796 }
2797 WL_INFO(("STA %s : idle time : %d sec, connected time :%d ms\n",
2798 bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time,
2799 sta->idle * 1000));
2800#endif
2801 } else if (get_mode_by_netdev(wl, dev) == WL_MODE_BSS) {
2802 u8 *curmacp = wl_read_prof(wl, WL_PROF_BSSID);
2803
2804 if (!wl_get_drv_status(wl, CONNECTED) ||
2805 (dhd_is_associated(dhd, NULL) == FALSE)) {
2806 WL_ERR(("NOT assoc\n"));
2807 err = -ENODEV;
2808 goto get_station_err;
2809 }
2810 if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) {
2811 WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n",
2812 MAC2STR(mac), MAC2STR(curmacp)));
2813 }
2814
2815 /* Report the current tx rate */
2816 err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false);
2817 if (err) {
2818 WL_ERR(("Could not get rate (%d)\n", err));
2819 } else {
2820 rate = dtoh32(rate);
2821 sinfo->filled |= STATION_INFO_TX_BITRATE;
2822 sinfo->txrate.legacy = rate * 5;
2823 WL_DBG(("Rate %d Mbps\n", (rate / 2)));
2824 }
2825
2826 memset(&scb_val, 0, sizeof(scb_val));
2827 scb_val.val = 0;
2828 err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val,
2829 sizeof(scb_val_t), false);
2830 if (err) {
2831 WL_ERR(("Could not get rssi (%d)\n", err));
2832 goto get_station_err;
2833 }
2834
2835 rssi = dtoh32(scb_val.val);
2836 sinfo->filled |= STATION_INFO_SIGNAL;
2837 sinfo->signal = rssi;
2838 WL_DBG(("RSSI %d dBm\n", rssi));
2839
2840get_station_err:
2841 if (err) {
2842 /* Disconnect due to zero BSSID or error to get RSSI */
2843 WL_ERR(("force cfg80211_disconnected\n"));
2844 wl_clr_drv_status(wl, CONNECTED);
2845 cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL);
2846 wl_link_down(wl);
2847 }
2848 }
2849
2850 return err;
2851}
2852
2853static s32
2854wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
2855 bool enabled, s32 timeout)
2856{
2857 s32 pm;
2858 s32 err = 0;
2859 struct wl_priv *wl = wiphy_priv(wiphy);
2860
2861 CHECK_SYS_UP(wl);
2862 pm = enabled ? PM_FAST : PM_OFF;
2863 /* Do not enable the power save after assoc if it is p2p interface */
2864 if (wl->p2p && wl->p2p->vif_created) {
2865 WL_DBG(("Do not enable the power save for p2p interfaces even after assoc\n"));
2866 pm = PM_OFF;
2867 }
2868 pm = htod32(pm);
2869 WL_DBG(("power save %s\n", (pm ? "enabled" : "disabled")));
2870 err = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), true);
2871 if (unlikely(err)) {
2872 if (err == -ENODEV)
2873 WL_DBG(("net_device is not ready yet\n"));
2874 else
2875 WL_ERR(("error (%d)\n", err));
2876 return err;
2877 }
2878 return err;
2879}
2880
2881static __used u32 wl_find_msb(u16 bit16)
2882{
2883 u32 ret = 0;
2884
2885 if (bit16 & 0xff00) {
2886 ret += 8;
2887 bit16 >>= 8;
2888 }
2889
2890 if (bit16 & 0xf0) {
2891 ret += 4;
2892 bit16 >>= 4;
2893 }
2894
2895 if (bit16 & 0xc) {
2896 ret += 2;
2897 bit16 >>= 2;
2898 }
2899
2900 if (bit16 & 2)
2901 ret += bit16 & 2;
2902 else if (bit16)
2903 ret += bit16;
2904
2905 return ret;
2906}
2907
2908static s32 wl_cfg80211_resume(struct wiphy *wiphy)
2909{
2910 struct wl_priv *wl = wiphy_priv(wiphy);
2911 s32 err = 0;
2912
2913 if (unlikely(!wl_get_drv_status(wl, READY))) {
2914 WL_INFO(("device is not ready : status (%d)\n",
2915 (int)wl->status));
2916 return 0;
2917 }
2918
2919 wl_invoke_iscan(wl);
2920
2921 return err;
2922}
2923
2924#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
2925static s32 wl_cfg80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wow)
2926#else
2927static s32 wl_cfg80211_suspend(struct wiphy *wiphy)
2928#endif
2929{
2930#ifdef DHD_CLEAR_ON_SUSPEND
2931 struct wl_priv *wl = wiphy_priv(wiphy);
2932 struct net_device *ndev = wl_to_prmry_ndev(wl);
2933 unsigned long flags;
2934
2935 if (unlikely(!wl_get_drv_status(wl, READY))) {
2936 WL_INFO(("device is not ready : status (%d)\n",
2937 (int)wl->status));
2938 return 0;
2939 }
2940
2941 wl_set_drv_status(wl, SCAN_ABORTING);
2942 wl_term_iscan(wl);
2943 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
2944 if (wl->scan_request) {
2945 cfg80211_scan_done(wl->scan_request, true);
2946 wl->scan_request = NULL;
2947 }
2948 wl_clr_drv_status(wl, SCANNING);
2949 wl_clr_drv_status(wl, SCAN_ABORTING);
2950 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
2951 if (wl_get_drv_status(wl, CONNECTING)) {
2952 wl_bss_connect_done(wl, ndev, NULL, NULL, false);
2953 }
2954#endif
2955 return 0;
2956}
2957
2958static __used s32
2959wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list,
2960 s32 err)
2961{
2962 int i, j;
2963 struct wl_priv *wl = wlcfg_drv_priv;
2964 struct net_device *primary_dev = wl_to_prmry_ndev(wl);
2965
2966 /* Firmware is supporting pmk list only for STA interface i.e. primary interface
2967 * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init
2968 * Do we really need to support PMK cache in P2P in firmware?
2969 */
2970 if (primary_dev != dev) {
2971 WL_INFO(("Not supporting Flushing pmklist on virtual"
2972 " interfaces than primary interface\n"));
2973 return err;
2974 }
2975
2976 WL_DBG(("No of elements %d\n", pmk_list->pmkids.npmkid));
2977 for (i = 0; i < pmk_list->pmkids.npmkid; i++) {
2978 WL_DBG(("PMKID[%d]: %pM =\n", i,
2979 &pmk_list->pmkids.pmkid[i].BSSID));
2980 for (j = 0; j < WPA2_PMKID_LEN; j++) {
2981 WL_DBG(("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]));
2982 }
2983 }
2984 if (likely(!err)) {
2985 err = wl_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list,
2986 sizeof(*pmk_list));
2987 }
2988
2989 return err;
2990}
2991
2992static s32
2993wl_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *dev,
2994 struct cfg80211_pmksa *pmksa)
2995{
2996 struct wl_priv *wl = wiphy_priv(wiphy);
2997 s32 err = 0;
2998 int i;
2999
3000 CHECK_SYS_UP(wl);
3001 for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++)
3002 if (!memcmp(pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID,
3003 ETHER_ADDR_LEN))
3004 break;
3005 if (i < WL_NUM_PMKIDS_MAX) {
3006 memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID, pmksa->bssid,
3007 ETHER_ADDR_LEN);
3008 memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID, pmksa->pmkid,
3009 WPA2_PMKID_LEN);
3010 if (i == wl->pmk_list->pmkids.npmkid)
3011 wl->pmk_list->pmkids.npmkid++;
3012 } else {
3013 err = -EINVAL;
3014 }
3015 WL_DBG(("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n",
3016 &wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1].BSSID));
3017 for (i = 0; i < WPA2_PMKID_LEN; i++) {
3018 WL_DBG(("%02x\n",
3019 wl->pmk_list->pmkids.pmkid[wl->pmk_list->pmkids.npmkid - 1].
3020 PMKID[i]));
3021 }
3022
3023 err = wl_update_pmklist(dev, wl->pmk_list, err);
3024
3025 return err;
3026}
3027
3028static s32
3029wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev,
3030 struct cfg80211_pmksa *pmksa)
3031{
3032 struct wl_priv *wl = wiphy_priv(wiphy);
3033 struct _pmkid_list pmkid;
3034 s32 err = 0;
3035 int i;
3036
3037 CHECK_SYS_UP(wl);
3038 memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETHER_ADDR_LEN);
3039 memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WPA2_PMKID_LEN);
3040
3041 WL_DBG(("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n",
3042 &pmkid.pmkid[0].BSSID));
3043 for (i = 0; i < WPA2_PMKID_LEN; i++) {
3044 WL_DBG(("%02x\n", pmkid.pmkid[0].PMKID[i]));
3045 }
3046
3047 for (i = 0; i < wl->pmk_list->pmkids.npmkid; i++)
3048 if (!memcmp
3049 (pmksa->bssid, &wl->pmk_list->pmkids.pmkid[i].BSSID,
3050 ETHER_ADDR_LEN))
3051 break;
3052
3053 if ((wl->pmk_list->pmkids.npmkid > 0) &&
3054 (i < wl->pmk_list->pmkids.npmkid)) {
3055 memset(&wl->pmk_list->pmkids.pmkid[i], 0, sizeof(pmkid_t));
3056 for (; i < (wl->pmk_list->pmkids.npmkid - 1); i++) {
3057 memcpy(&wl->pmk_list->pmkids.pmkid[i].BSSID,
3058 &wl->pmk_list->pmkids.pmkid[i + 1].BSSID,
3059 ETHER_ADDR_LEN);
3060 memcpy(&wl->pmk_list->pmkids.pmkid[i].PMKID,
3061 &wl->pmk_list->pmkids.pmkid[i + 1].PMKID,
3062 WPA2_PMKID_LEN);
3063 }
3064 wl->pmk_list->pmkids.npmkid--;
3065 } else {
3066 err = -EINVAL;
3067 }
3068
3069 err = wl_update_pmklist(dev, wl->pmk_list, err);
3070
3071 return err;
3072
3073}
3074
3075static s32
3076wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev)
3077{
3078 struct wl_priv *wl = wiphy_priv(wiphy);
3079 s32 err = 0;
3080 CHECK_SYS_UP(wl);
3081 memset(wl->pmk_list, 0, sizeof(*wl->pmk_list));
3082 err = wl_update_pmklist(dev, wl->pmk_list, err);
3083 return err;
3084
3085}
3086
3087wl_scan_params_t *
3088wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size)
3089{
3090 wl_scan_params_t *params;
3091 int params_size;
3092 int num_chans;
3093
3094 *out_params_size = 0;
3095
3096 /* Our scan params only need space for 1 channel and 0 ssids */
3097 params_size = WL_SCAN_PARAMS_FIXED_SIZE + 1 * sizeof(uint16);
3098 params = (wl_scan_params_t*) kzalloc(params_size, GFP_KERNEL);
3099 if (params == NULL) {
3100 WL_ERR(("%s: mem alloc failed (%d bytes)\n", __func__, params_size));
3101 return params;
3102 }
3103 memset(params, 0, params_size);
3104 params->nprobes = nprobes;
3105
3106 num_chans = (channel == 0) ? 0 : 1;
3107
3108 memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
3109 params->bss_type = DOT11_BSSTYPE_ANY;
3110 params->scan_type = DOT11_SCANTYPE_ACTIVE;
3111 params->nprobes = htod32(1);
3112 params->active_time = htod32(-1);
3113 params->passive_time = htod32(-1);
3114 params->home_time = htod32(10);
3115 params->channel_list[0] = htodchanspec(channel);
3116
3117 /* Our scan params have 1 channel and 0 ssids */
3118 params->channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
3119 (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
3120
3121 *out_params_size = params_size; /* rtn size to the caller */
3122 return params;
3123}
3124
3125s32
3126wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev)
3127{
3128 wl_scan_params_t *params = NULL;
3129 s32 params_size = 0;
3130 s32 err = BCME_OK;
3131 unsigned long flags;
3132
3133 WL_DBG(("Enter\n"));
3134
3135 /* Our scan params only need space for 1 channel and 0 ssids */
3136 params = wl_cfg80211_scan_alloc_params(-1, 0, &params_size);
3137 if (params == NULL) {
3138 WL_ERR(("scan params allocation failed \n"));
3139 err = -ENOMEM;
3140 } else {
3141 /* Do a scan abort to stop the driver's scan engine */
3142 err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, true);
3143 if (err < 0) {
3144 WL_ERR(("scan abort failed \n"));
3145 }
3146 }
3147 del_timer_sync(&wl->scan_timeout);
3148 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
3149 if (wl->scan_request) {
3150 cfg80211_scan_done(wl->scan_request, true);
3151 wl->scan_request = NULL;
3152 }
3153 wl_clr_drv_status(wl, SCANNING);
3154 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
3155 if (params)
3156 kfree(params);
3157 return err;
3158}
3159
3160static s32
3161wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
3162 struct ieee80211_channel * channel,
3163 enum nl80211_channel_type channel_type,
3164 unsigned int duration, u64 *cookie)
3165{
3166 s32 target_channel;
3167
3168 s32 err = BCME_OK;
3169 struct wl_priv *wl = wiphy_priv(wiphy);
3170 dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
3171 WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex));
3172 if (likely(wl_get_drv_status(wl, SCANNING))) {
3173 wl_cfg80211_scan_abort(wl, dev);
3174 }
3175
3176 target_channel = ieee80211_frequency_to_channel(channel->center_freq);
3177 memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel));
3178 wl->remain_on_chan_type = channel_type;
3179 wl->cache_cookie = *cookie;
3180 cfg80211_ready_on_channel(dev, *cookie, channel,
3181 channel_type, duration, GFP_KERNEL);
3182 if (!p2p_on(wl)) {
3183 wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
3184
3185 /* In case of p2p_listen command, supplicant send remain_on_channel
3186 * without turning on P2P
3187 */
3188
3189 p2p_on(wl) = true;
3190 err = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0);
3191
3192 if (unlikely(err)) {
3193 goto exit;
3194 }
3195 }
3196 if (p2p_on(wl))
3197 wl_cfgp2p_discover_listen(wl, target_channel, duration);
3198
3199
3200exit:
3201 return err;
3202}
3203
3204static s32
3205wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev,
3206 u64 cookie)
3207{
3208 s32 err = 0;
3209 WL_DBG((" enter ) netdev_ifidx: %d \n", dev->ifindex));
3210 return err;
3211}
3212
3213static s32
3214wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
3215 struct ieee80211_channel *channel, bool offchan,
3216 enum nl80211_channel_type channel_type,
3217 bool channel_type_valid, unsigned int wait,
3218 const u8* buf, size_t len, u64 *cookie)
3219{
3220 wl_action_frame_t *action_frame;
3221 wl_af_params_t *af_params;
3222 wifi_p2p_ie_t *p2p_ie;
3223 wpa_ie_fixed_t *wps_ie;
3224 const struct ieee80211_mgmt *mgmt;
3225 struct wl_priv *wl = wiphy_priv(wiphy);
3226 dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
3227 s32 err = BCME_OK;
3228 s32 bssidx = 0;
3229 u32 p2pie_len = 0;
3230 u32 wpsie_len = 0;
3231 u16 fc;
3232 bool ack = false;
3233 wifi_p2p_pub_act_frame_t *act_frm;
3234 WL_DBG(("Enter \n"));
3235 /* find bssidx based on ndev */
3236 bssidx = wl_cfgp2p_find_idx(wl, dev);
3237 /* cookie generation */
3238 *cookie = (unsigned long) buf;
3239
3240 if (bssidx == -1) {
3241
3242 WL_ERR(("Can not find the bssidx for dev( %p )\n", dev));
3243 return -ENODEV;
3244 }
3245 if (wl->p2p_supported && p2p_on(wl)) {
3246 wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
3247 /* Suspend P2P discovery search-listen to prevent it from changing the
3248 * channel.
3249 */
3250 if ((err = wl_cfgp2p_discover_enable_search(wl, false)) < 0) {
3251 WL_ERR(("Can not disable discovery mode\n"));
3252 return -EFAULT;
3253 }
3254 }
3255
3256 mgmt = (const struct ieee80211_mgmt *) buf;
3257 fc = mgmt->frame_control;
3258 if (fc != IEEE80211_STYPE_ACTION) {
3259 if (fc == IEEE80211_STYPE_PROBE_RESP) {
3260 s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3261 s32 ie_len = len - ie_offset;
3262 if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)(buf + ie_offset), ie_len))
3263 != NULL) {
3264 /* Total length of P2P Information Element */
3265 p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id);
3266 /* Have to change p2p device address in dev_info attribute
3267 * because Supplicant use primary eth0 address
3268 */
3269 #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */
3270 wl_cfg80211_change_ifaddr((u8 *)p2p_ie,
3271 &wl->p2p_dev_addr, P2P_SEID_DEV_INFO);
3272 #endif
3273 }
3274 if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)(buf + ie_offset), ie_len))
3275 != NULL) {
3276 /* Order of Vendor IE is 1) WPS IE +
3277 * 2) P2P IE created by supplicant
3278 * So, it is ok to find start address of WPS IE
3279 * to save IEs to firmware
3280 */
3281 wpsie_len = wps_ie->length + sizeof(wps_ie->length) +
3282 sizeof(wps_ie->tag);
3283 wl_cfgp2p_set_management_ie(wl, dev, bssidx,
3284 VNDR_IE_PRBRSP_FLAG,
3285 (u8 *)wps_ie, wpsie_len + p2pie_len);
3286 }
3287 }
3288 cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL);
3289 goto exit;
3290 } else {
3291 /* Abort the dwell time of any previous off-channel action frame that may
3292 * be still in effect. Sending off-channel action frames relies on the
3293 * driver's scan engine. If a previous off-channel action frame tx is
3294 * still in progress (including the dwell time), then this new action
3295 * frame will not be sent out.
3296 */
3297 wl_cfg80211_scan_abort(wl, dev);
3298 }
3299 af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL);
3300
3301 if (af_params == NULL)
3302 {
3303 WL_ERR(("unable to allocate frame\n"));
3304 return -ENOMEM;
3305 }
3306
3307 action_frame = &af_params->action_frame;
3308
3309 /* Add the packet Id */
3310 action_frame->packetId = (u32) action_frame;
3311 WL_DBG(("action frame %d\n", action_frame->packetId));
3312 /* Add BSSID */
3313 memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN);
3314 memcpy(&af_params->BSSID, &mgmt->bssid[0], ETHER_ADDR_LEN);
3315
3316 /* Add the length exepted for 802.11 header */
3317 action_frame->len = len - DOT11_MGMT_HDR_LEN;
3318 WL_DBG(("action_frame->len: %d\n", action_frame->len));
3319
3320 /* Add the channel */
3321 af_params->channel =
3322 ieee80211_frequency_to_channel(channel->center_freq);
3323
3324 /* Add the dwell time
3325 * Dwell time to stay off-channel to wait for a response action frame
3326 * after transmitting an GO Negotiation action frame
3327 */
3328 af_params->dwell_time = WL_DWELL_TIME;
3329
3330 memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len);
3331
3332 act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data);
3333 WL_DBG(("action_frame->len: %d chan %d category %d subtype %d\n",
3334 action_frame->len, af_params->channel,
3335 act_frm->category, act_frm->subtype));
3336 if (wl->p2p->vif_created) {
3337 /*
3338 * To make sure to send successfully action frame, we have to turn off mpc
3339 */
3340 if ((act_frm->subtype == P2P_PAF_GON_REQ)||
3341 (act_frm->subtype == P2P_PAF_GON_RSP)) {
3342 wldev_iovar_setint(dev, "mpc", 0);
3343 } else if (act_frm->subtype == P2P_PAF_GON_CONF) {
3344 wldev_iovar_setint(dev, "mpc", 1);
3345 } else if (act_frm->subtype == P2P_PAF_DEVDIS_REQ) {
3346 af_params->dwell_time = WL_LONG_DWELL_TIME;
3347 }
3348 }
3349
3350 ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true;
3351 cfg80211_mgmt_tx_status(dev, *cookie, buf, len, ack, GFP_KERNEL);
3352
3353 kfree(af_params);
3354exit:
3355 return err;
3356}
3357
3358
3359static void
3360wl_cfg80211_mgmt_frame_register(struct wiphy *wiphy, struct net_device *dev,
3361 u16 frame_type, bool reg)
3362{
3363
3364 WL_DBG(("%s: frame_type: %x, reg: %d\n", __func__, frame_type, reg));
3365
3366 if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
3367 return;
3368
3369 return;
3370}
3371
3372
3373static s32
3374wl_cfg80211_change_bss(struct wiphy *wiphy,
3375 struct net_device *dev,
3376 struct bss_parameters *params)
3377{
3378 if (params->use_cts_prot >= 0) {
3379 }
3380
3381 if (params->use_short_preamble >= 0) {
3382 }
3383
3384 if (params->use_short_slot_time >= 0) {
3385 }
3386
3387 if (params->basic_rates) {
3388 }
3389
3390 if (params->ap_isolate >= 0) {
3391 }
3392
3393 if (params->ht_opmode >= 0) {
3394 }
3395
3396 return 0;
3397}
3398
3399static s32
3400wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
3401 struct ieee80211_channel *chan,
3402 enum nl80211_channel_type channel_type)
3403{
3404 s32 channel;
3405 s32 err = BCME_OK;
3406
3407 channel = ieee80211_frequency_to_channel(chan->center_freq);
3408 WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n",
3409 dev->ifindex, channel_type, channel));
3410 err = wldev_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel), true);
3411 if (err < 0) {
3412 WL_ERR(("WLC_SET_CHANNEL error %d chip may not be supporting this channel\n", err));
3413 }
3414 return err;
3415}
3416
3417static s32
3418wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx)
3419{
3420 s32 len = 0;
3421 s32 err = BCME_OK;
3422 u16 auth = 0; /* d11 open authentication */
3423 u16 count;
3424 u32 wsec;
3425 u32 pval = 0;
3426 u32 gval = 0;
3427 u32 wpa_auth = 0;
3428 u8* tmp;
3429 wpa_suite_mcast_t *mcast;
3430 wpa_suite_ucast_t *ucast;
3431 wpa_suite_auth_key_mgmt_t *mgmt;
3432 if (wpa2ie == NULL)
3433 goto exit;
3434
3435 WL_DBG(("Enter \n"));
3436 len = wpa2ie->len;
3437 /* check the mcast cipher */
3438 mcast = (wpa_suite_mcast_t *)&wpa2ie->data[WPA2_VERSION_LEN];
3439 tmp = mcast->oui;
3440 switch (tmp[DOT11_OUI_LEN]) {
3441 case WPA_CIPHER_NONE:
3442 gval = 0;
3443 break;
3444 case WPA_CIPHER_WEP_40:
3445 case WPA_CIPHER_WEP_104:
3446 gval = WEP_ENABLED;
3447 break;
3448 case WPA_CIPHER_TKIP:
3449 gval = TKIP_ENABLED;
3450 break;
3451 case WPA_CIPHER_AES_CCM:
3452 gval = AES_ENABLED;
3453 break;
3454 default:
3455 WL_ERR(("No Security Info\n"));
3456 break;
3457 }
3458 len -= WPA_SUITE_LEN;
3459 /* check the unicast cipher */
3460 ucast = (wpa_suite_ucast_t *)&mcast[1];
3461 count = ltoh16_ua(&ucast->count);
3462 tmp = ucast->list[0].oui;
3463 switch (tmp[DOT11_OUI_LEN]) {
3464 case WPA_CIPHER_NONE:
3465 pval = 0;
3466 break;
3467 case WPA_CIPHER_WEP_40:
3468 case WPA_CIPHER_WEP_104:
3469 pval = WEP_ENABLED;
3470 break;
3471 case WPA_CIPHER_TKIP:
3472 pval = TKIP_ENABLED;
3473 break;
3474 case WPA_CIPHER_AES_CCM:
3475 pval = AES_ENABLED;
3476 break;
3477 default:
3478 WL_ERR(("No Security Info\n"));
3479 }
3480 /* FOR WPS , set SEC_OW_ENABLED */
3481 wsec = (pval | gval | SES_OW_ENABLED);
3482 /* check the AKM */
3483 mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[1];
3484 count = ltoh16_ua(&mgmt->count);
3485 tmp = (u8 *)&mgmt->list[0];
3486 switch (tmp[DOT11_OUI_LEN]) {
3487 case RSN_AKM_NONE:
3488 wpa_auth = WPA_AUTH_NONE;
3489 break;
3490 case RSN_AKM_UNSPECIFIED:
3491 wpa_auth = WPA2_AUTH_UNSPECIFIED;
3492 break;
3493 case RSN_AKM_PSK:
3494 wpa_auth = WPA2_AUTH_PSK;
3495 break;
3496 default:
3497 WL_ERR(("No Key Mgmt Info\n"));
3498 }
3499 /* set auth */
3500 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
3501 if (err < 0) {
3502 WL_ERR(("auth error %d\n", err));
3503 return BCME_ERROR;
3504 }
3505 /* set wsec */
3506 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
3507 if (err < 0) {
3508 WL_ERR(("wsec error %d\n", err));
3509 return BCME_ERROR;
3510 }
3511 /* set upper-layer auth */
3512 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
3513 if (err < 0) {
3514 WL_ERR(("wpa_auth error %d\n", err));
3515 return BCME_ERROR;
3516 }
3517exit:
3518 return 0;
3519}
3520
3521static s32
3522wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx)
3523{
3524 wpa_suite_mcast_t *mcast;
3525 wpa_suite_ucast_t *ucast;
3526 wpa_suite_auth_key_mgmt_t *mgmt;
3527 u16 auth = 0; /* d11 open authentication */
3528 u16 count;
3529 s32 err = BCME_OK;
3530 s32 len = 0;
3531 u32 i;
3532 u32 wsec;
3533 u32 pval = 0;
3534 u32 gval = 0;
3535 u32 wpa_auth = 0;
3536 u32 tmp = 0;
3537
3538 if (wpaie == NULL)
3539 goto exit;
3540 WL_DBG(("Enter \n"));
3541 len = wpaie->length; /* value length */
3542 len -= WPA_IE_TAG_FIXED_LEN;
3543 /* check for multicast cipher suite */
3544 if (len < WPA_SUITE_LEN) {
3545 WL_INFO(("no multicast cipher suite\n"));
3546 goto exit;
3547 }
3548
3549 /* pick up multicast cipher */
3550 mcast = (wpa_suite_mcast_t *)&wpaie[1];
3551 len -= WPA_SUITE_LEN;
3552 if (!bcmp(mcast->oui, WPA_OUI, WPA_OUI_LEN)) {
3553 if (IS_WPA_CIPHER(mcast->type)) {
3554 tmp = 0;
3555 switch (mcast->type) {
3556 case WPA_CIPHER_NONE:
3557 tmp = 0;
3558 break;
3559 case WPA_CIPHER_WEP_40:
3560 case WPA_CIPHER_WEP_104:
3561 tmp = WEP_ENABLED;
3562 break;
3563 case WPA_CIPHER_TKIP:
3564 tmp = TKIP_ENABLED;
3565 break;
3566 case WPA_CIPHER_AES_CCM:
3567 tmp = AES_ENABLED;
3568 break;
3569 default:
3570 WL_ERR(("No Security Info\n"));
3571 }
3572 gval |= tmp;
3573 }
3574 }
3575 /* Check for unicast suite(s) */
3576 if (len < WPA_IE_SUITE_COUNT_LEN) {
3577 WL_INFO(("no unicast suite\n"));
3578 goto exit;
3579 }
3580 /* walk thru unicast cipher list and pick up what we recognize */
3581 ucast = (wpa_suite_ucast_t *)&mcast[1];
3582 count = ltoh16_ua(&ucast->count);
3583 len -= WPA_IE_SUITE_COUNT_LEN;
3584 for (i = 0; i < count && len >= WPA_SUITE_LEN;
3585 i++, len -= WPA_SUITE_LEN) {
3586 if (!bcmp(ucast->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
3587 if (IS_WPA_CIPHER(ucast->list[i].type)) {
3588 tmp = 0;
3589 switch (ucast->list[i].type) {
3590 case WPA_CIPHER_NONE:
3591 tmp = 0;
3592 break;
3593 case WPA_CIPHER_WEP_40:
3594 case WPA_CIPHER_WEP_104:
3595 tmp = WEP_ENABLED;
3596 break;
3597 case WPA_CIPHER_TKIP:
3598 tmp = TKIP_ENABLED;
3599 break;
3600 case WPA_CIPHER_AES_CCM:
3601 tmp = AES_ENABLED;
3602 break;
3603 default:
3604 WL_ERR(("No Security Info\n"));
3605 }
3606 pval |= tmp;
3607 }
3608 }
3609 }
3610 len -= (count - i) * WPA_SUITE_LEN;
3611 /* Check for auth key management suite(s) */
3612 if (len < WPA_IE_SUITE_COUNT_LEN) {
3613 WL_INFO((" no auth key mgmt suite\n"));
3614 goto exit;
3615 }
3616 /* walk thru auth management suite list and pick up what we recognize */
3617 mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[count];
3618 count = ltoh16_ua(&mgmt->count);
3619 len -= WPA_IE_SUITE_COUNT_LEN;
3620 for (i = 0; i < count && len >= WPA_SUITE_LEN;
3621 i++, len -= WPA_SUITE_LEN) {
3622 if (!bcmp(mgmt->list[i].oui, WPA_OUI, WPA_OUI_LEN)) {
3623 if (IS_WPA_AKM(mgmt->list[i].type)) {
3624 tmp = 0;
3625 switch (mgmt->list[i].type) {
3626 case RSN_AKM_NONE:
3627 tmp = WPA_AUTH_NONE;
3628 break;
3629 case RSN_AKM_UNSPECIFIED:
3630 tmp = WPA_AUTH_UNSPECIFIED;
3631 break;
3632 case RSN_AKM_PSK:
3633 tmp = WPA_AUTH_PSK;
3634 break;
3635 default:
3636 WL_ERR(("No Key Mgmt Info\n"));
3637 }
3638 wpa_auth |= tmp;
3639 }
3640 }
3641
3642 }
3643 /* FOR WPS , set SEC_OW_ENABLED */
3644 wsec = (pval | gval | SES_OW_ENABLED);
3645 /* set auth */
3646 err = wldev_iovar_setint_bsscfg(dev, "auth", auth, bssidx);
3647 if (err < 0) {
3648 WL_ERR(("auth error %d\n", err));
3649 return BCME_ERROR;
3650 }
3651 /* set wsec */
3652 err = wldev_iovar_setint_bsscfg(dev, "wsec", wsec, bssidx);
3653 if (err < 0) {
3654 WL_ERR(("wsec error %d\n", err));
3655 return BCME_ERROR;
3656 }
3657 /* set upper-layer auth */
3658 err = wldev_iovar_setint_bsscfg(dev, "wpa_auth", wpa_auth, bssidx);
3659 if (err < 0) {
3660 WL_ERR(("wpa_auth error %d\n", err));
3661 return BCME_ERROR;
3662 }
3663exit:
3664 return 0;
3665}
3666
3667static s32
3668wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev,
3669 struct beacon_parameters *info)
3670{
3671 s32 err = BCME_OK;
3672 bcm_tlv_t *ssid_ie;
3673 wlc_ssid_t ssid;
3674 struct wl_priv *wl = wiphy_priv(wiphy);
3675 struct wl_join_params join_params;
3676 wpa_ie_fixed_t *wps_ie;
3677 wpa_ie_fixed_t *wpa_ie;
3678 bcm_tlv_t *wpa2_ie;
3679 wifi_p2p_ie_t *p2p_ie;
3680 bool is_bssup = false;
3681 bool update_bss = false;
3682 bool pbc = false;
3683 u16 wpsie_len = 0;
3684 u16 p2pie_len = 0;
3685 u8 beacon_ie[IE_MAX_LEN];
3686 s32 ie_offset = 0;
3687 s32 bssidx = wl_cfgp2p_find_idx(wl, dev);
3688 s32 infra = 1;
3689 s32 join_params_size = 0;
3690 s32 ap = 0;
3691 WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n",
3692 info->interval, info->dtim_period, info->head_len, info->tail_len));
3693 if (wl->p2p_supported && p2p_on(wl) &&
3694 (bssidx == wl_to_p2p_bss_bssidx(wl,
3695 P2PAPI_BSSCFG_CONNECTION))) {
3696 memset(beacon_ie, 0, sizeof(beacon_ie));
3697 /* We don't need to set beacon for P2P_GO,
3698 * but need to parse ssid from beacon_parameters
3699 * because there is no way to set ssid
3700 */
3701 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3702 /* find the SSID */
3703 if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
3704 info->head_len - ie_offset,
3705 DOT11_MNG_SSID_ID)) != NULL) {
3706 memcpy(wl->p2p->ssid.SSID, ssid_ie->data, ssid_ie->len);
3707 wl->p2p->ssid.SSID_len = ssid_ie->len;
3708 WL_DBG(("SSID (%s) in Head \n", ssid_ie->data));
3709
3710 } else {
3711 WL_ERR(("No SSID in beacon \n"));
3712 }
3713
3714 /* find the WPSIE */
3715 if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) {
3716 wpsie_len = wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
3717 /*
3718 * Should be compared with saved ie before saving it
3719 */
3720 wl_validate_wps_ie((char *) wps_ie, &pbc);
3721 memcpy(beacon_ie, wps_ie, wpsie_len);
3722 } else {
3723 WL_ERR(("No WPSIE in beacon \n"));
3724 }
3725
3726
3727 /* find the P2PIE */
3728 if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)info->tail, info->tail_len)) != NULL) {
3729 /* Total length of P2P Information Element */
3730 p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id);
3731 #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */
3732 /* Have to change device address in dev_id attribute because Supplicant
3733 * use primary eth0 address
3734 */
3735 wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, P2P_SEID_DEV_ID);
3736 #endif
3737 memcpy(&beacon_ie[wpsie_len], p2p_ie, p2pie_len);
3738
3739 } else {
3740 WL_ERR(("No P2PIE in beacon \n"));
3741 }
3742 /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
3743 wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
3744 wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
3745 beacon_ie, wpsie_len + p2pie_len);
3746
3747 /* find the RSN_IE */
3748 if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
3749 DOT11_MNG_RSN_ID)) != NULL) {
3750 WL_DBG((" WPA2 IE is found\n"));
3751 }
3752 is_bssup = wl_cfgp2p_bss_isup(dev, bssidx);
3753
3754 if (!is_bssup && (wpa2_ie != NULL)) {
3755 wldev_iovar_setint(dev, "mpc", 0);
3756 if ((err = wl_validate_wpa2ie(dev, wpa2_ie, bssidx)) < 0) {
3757 WL_ERR(("WPA2 IE parsing error"));
3758 goto exit;
3759 }
3760 err = wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
3761 if (err < 0) {
3762 WL_ERR(("SET INFRA error %d\n", err));
3763 goto exit;
3764 }
3765 err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid,
3766 sizeof(wl->p2p->ssid), ioctlbuf, sizeof(ioctlbuf), bssidx);
3767 if (err < 0) {
3768 WL_ERR(("GO SSID setting error %d\n", err));
3769 goto exit;
3770 }
3771 if ((err = wl_cfgp2p_bss(dev, bssidx, 1)) < 0) {
3772 WL_ERR(("GO Bring up error %d\n", err));
3773 goto exit;
3774 }
3775 }
3776 } else if (wl_get_drv_status(wl, AP_CREATING)) {
3777 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
3778 ap = 1;
3779 /* find the SSID */
3780 if ((ssid_ie = bcm_parse_tlvs((u8 *)&info->head[ie_offset],
3781 info->head_len - ie_offset,
3782 DOT11_MNG_SSID_ID)) != NULL) {
3783 memset(&ssid, 0, sizeof(wlc_ssid_t));
3784 memcpy(ssid.SSID, ssid_ie->data, ssid_ie->len);
3785 WL_DBG(("SSID is (%s) in Head \n", ssid.SSID));
3786 ssid.SSID_len = ssid_ie->len;
3787 wldev_iovar_setint(dev, "mpc", 0);
3788 wldev_ioctl(dev, WLC_DOWN, &ap, sizeof(s32), true);
3789 wldev_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(s32), true);
3790 if ((err = wldev_ioctl(dev, WLC_SET_AP, &ap, sizeof(s32), true)) < 0) {
3791 WL_ERR(("setting AP mode failed %d \n", err));
3792 return err;
3793 }
3794 /* find the RSN_IE */
3795 if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
3796 DOT11_MNG_RSN_ID)) != NULL) {
3797 WL_DBG((" WPA2 IE is found\n"));
3798 }
3799 /* find the WPA_IE */
3800 if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)info->tail,
3801 info->tail_len)) != NULL) {
3802 WL_DBG((" WPA IE is found\n"));
3803 }
3804 if ((wpa_ie != NULL || wpa2_ie != NULL)) {
3805 if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 ||
3806 wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) {
3807 wl->ap_info->security_mode = false;
3808 return BCME_ERROR;
3809 }
3810 wl->ap_info->security_mode = true;
3811 if (wl->ap_info->rsn_ie) {
3812 kfree(wl->ap_info->rsn_ie);
3813 wl->ap_info->rsn_ie = NULL;
3814 }
3815 if (wl->ap_info->wpa_ie) {
3816 kfree(wl->ap_info->wpa_ie);
3817 wl->ap_info->wpa_ie = NULL;
3818 }
3819 if (wl->ap_info->wps_ie) {
3820 kfree(wl->ap_info->wps_ie);
3821 wl->ap_info->wps_ie = NULL;
3822 }
3823 if (wpa_ie != NULL) {
3824 /* WPAIE */
3825 wl->ap_info->rsn_ie = NULL;
3826 wl->ap_info->wpa_ie = kmemdup(wpa_ie,
3827 wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
3828 GFP_KERNEL);
3829 } else {
3830 /* RSNIE */
3831 wl->ap_info->wpa_ie = NULL;
3832 wl->ap_info->rsn_ie = kmemdup(wpa2_ie,
3833 wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
3834 GFP_KERNEL);
3835 }
3836 } else
3837 wl->ap_info->security_mode = false;
3838 /* find the WPSIE */
3839 if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail,
3840 info->tail_len)) != NULL) {
3841 wpsie_len = wps_ie->length +WPA_RSN_IE_TAG_FIXED_LEN;
3842 /*
3843 * Should be compared with saved ie before saving it
3844 */
3845 wl_validate_wps_ie((char *) wps_ie, &pbc);
3846 memcpy(beacon_ie, wps_ie, wpsie_len);
3847 wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
3848 beacon_ie, wpsie_len);
3849 wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
3850 /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
3851 wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
3852 } else {
3853 WL_DBG(("No WPSIE in beacon \n"));
3854 }
3855 if (info->interval) {
3856 if ((err = wldev_ioctl(dev, WLC_SET_BCNPRD,
3857 &info->interval, sizeof(s32), true)) < 0) {
3858 WL_ERR(("Beacon Interval Set Error, %d\n", err));
3859 return err;
3860 }
3861 }
3862 if (info->dtim_period) {
3863 if ((err = wldev_ioctl(dev, WLC_SET_DTIMPRD,
3864 &info->dtim_period, sizeof(s32), true)) < 0) {
3865 WL_ERR(("DTIM Interval Set Error, %d\n", err));
3866 return err;
3867 }
3868 }
3869 err = wldev_ioctl(dev, WLC_UP, &ap, sizeof(s32), true);
3870 if (unlikely(err)) {
3871 WL_ERR(("WLC_UP error (%d)\n", err));
3872 return err;
3873 }
3874 memset(&join_params, 0, sizeof(join_params));
3875 /* join parameters starts with ssid */
3876 join_params_size = sizeof(join_params.ssid);
3877 memcpy(join_params.ssid.SSID, ssid.SSID, ssid.SSID_len);
3878 join_params.ssid.SSID_len = htod32(ssid.SSID_len);
3879 /* create softap */
3880 if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params,
3881 join_params_size, true)) == 0) {
3882 wl_clr_drv_status(wl, AP_CREATING);
3883 wl_set_drv_status(wl, AP_CREATED);
3884 }
3885 }
3886 } else if (wl_get_drv_status(wl, AP_CREATED)) {
3887 ap = 1;
3888 /* find the WPSIE */
3889 if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) {
3890 wpsie_len = wps_ie->length + WPA_RSN_IE_TAG_FIXED_LEN;
3891 /*
3892 * Should be compared with saved ie before saving it
3893 */
3894 wl_validate_wps_ie((char *) wps_ie, &pbc);
3895 memcpy(beacon_ie, wps_ie, wpsie_len);
3896 wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG,
3897 beacon_ie, wpsie_len);
3898 if (wl->ap_info->wps_ie &&
3899 memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) {
3900 WL_DBG((" WPS IE is changed\n"));
3901 kfree(wl->ap_info->wps_ie);
3902 wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
3903 /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
3904 wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
3905 } else if (wl->ap_info->wps_ie == NULL) {
3906 WL_DBG((" WPS IE is added\n"));
3907 wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL);
3908 /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */
3909 wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc);
3910 }
3911 /* find the RSN_IE */
3912 if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len,
3913 DOT11_MNG_RSN_ID)) != NULL) {
3914 WL_DBG((" WPA2 IE is found\n"));
3915 }
3916 /* find the WPA_IE */
3917 if ((wpa_ie = wl_cfgp2p_find_wpaie((u8 *)info->tail,
3918 info->tail_len)) != NULL) {
3919 WL_DBG((" WPA IE is found\n"));
3920 }
3921 if ((wpa_ie != NULL || wpa2_ie != NULL)) {
3922 if (!wl->ap_info->security_mode) {
3923 /* change from open mode to security mode */
3924 update_bss = true;
3925 if (wpa_ie != NULL) {
3926 wl->ap_info->wpa_ie = kmemdup(wpa_ie,
3927 wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
3928 GFP_KERNEL);
3929 } else {
3930 wl->ap_info->rsn_ie = kmemdup(wpa2_ie,
3931 wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
3932 GFP_KERNEL);
3933 }
3934 } else if (wl->ap_info->wpa_ie) {
3935 /* change from WPA mode to WPA2 mode */
3936 if (wpa2_ie != NULL) {
3937 update_bss = true;
3938 kfree(wl->ap_info->wpa_ie);
3939 wl->ap_info->rsn_ie = kmemdup(wpa2_ie,
3940 wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
3941 GFP_KERNEL);
3942 wl->ap_info->wpa_ie = NULL;
3943 }
3944 else if (memcmp(wl->ap_info->wpa_ie,
3945 wpa_ie, wpa_ie->length +
3946 WPA_RSN_IE_TAG_FIXED_LEN)) {
3947 kfree(wl->ap_info->wpa_ie);
3948 update_bss = true;
3949 wl->ap_info->wpa_ie = kmemdup(wpa_ie,
3950 wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
3951 GFP_KERNEL);
3952 wl->ap_info->rsn_ie = NULL;
3953 }
3954 } else {
3955 /* change from WPA2 mode to WPA mode */
3956 if (wpa_ie != NULL) {
3957 update_bss = true;
3958 kfree(wl->ap_info->rsn_ie);
3959 wl->ap_info->rsn_ie = NULL;
3960 wl->ap_info->wpa_ie = kmemdup(wpa_ie,
3961 wpa_ie->length + WPA_RSN_IE_TAG_FIXED_LEN,
3962 GFP_KERNEL);
3963 } else if (memcmp(wl->ap_info->rsn_ie,
3964 wpa2_ie, wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN)) {
3965 update_bss = true;
3966 kfree(wl->ap_info->rsn_ie);
3967 wl->ap_info->rsn_ie = kmemdup(wpa2_ie,
3968 wpa2_ie->len + WPA_RSN_IE_TAG_FIXED_LEN,
3969 GFP_KERNEL);
3970 wl->ap_info->wpa_ie = NULL;
3971 }
3972 }
3973 if (update_bss) {
3974 wl->ap_info->security_mode = true;
3975 wl_cfgp2p_bss(dev, bssidx, 0);
3976 if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 ||
3977 wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) {
3978 return BCME_ERROR;
3979 }
3980 wl_cfgp2p_bss(dev, bssidx, 1);
3981 }
3982 }
3983 } else {
3984 WL_ERR(("No WPSIE in beacon \n"));
3985 }
3986 }
3987exit:
3988 if (err)
3989 wldev_iovar_setint(dev, "mpc", 1);
3990 return err;
3991}
3992
3993static struct cfg80211_ops wl_cfg80211_ops = {
3994 .add_virtual_intf = wl_cfg80211_add_virtual_iface,
3995 .del_virtual_intf = wl_cfg80211_del_virtual_iface,
3996 .change_virtual_intf = wl_cfg80211_change_virtual_iface,
3997 .scan = wl_cfg80211_scan,
3998 .set_wiphy_params = wl_cfg80211_set_wiphy_params,
3999 .join_ibss = wl_cfg80211_join_ibss,
4000 .leave_ibss = wl_cfg80211_leave_ibss,
4001 .get_station = wl_cfg80211_get_station,
4002 .set_tx_power = wl_cfg80211_set_tx_power,
4003 .get_tx_power = wl_cfg80211_get_tx_power,
4004 .add_key = wl_cfg80211_add_key,
4005 .del_key = wl_cfg80211_del_key,
4006 .get_key = wl_cfg80211_get_key,
4007 .set_default_key = wl_cfg80211_config_default_key,
4008 .set_default_mgmt_key = wl_cfg80211_config_default_mgmt_key,
4009 .set_power_mgmt = wl_cfg80211_set_power_mgmt,
4010 .connect = wl_cfg80211_connect,
4011 .disconnect = wl_cfg80211_disconnect,
4012 .suspend = wl_cfg80211_suspend,
4013 .resume = wl_cfg80211_resume,
4014 .set_pmksa = wl_cfg80211_set_pmksa,
4015 .del_pmksa = wl_cfg80211_del_pmksa,
4016 .flush_pmksa = wl_cfg80211_flush_pmksa,
4017 .remain_on_channel = wl_cfg80211_remain_on_channel,
4018 .cancel_remain_on_channel = wl_cfg80211_cancel_remain_on_channel,
4019 .mgmt_tx = wl_cfg80211_mgmt_tx,
4020 .mgmt_frame_register = wl_cfg80211_mgmt_frame_register,
4021 .change_bss = wl_cfg80211_change_bss,
4022 .set_channel = wl_cfg80211_set_channel,
4023 .set_beacon = wl_cfg80211_add_set_beacon,
4024 .add_beacon = wl_cfg80211_add_set_beacon,
4025};
4026
4027static s32 wl_mode_to_nl80211_iftype(s32 mode)
4028{
4029 s32 err = 0;
4030
4031 switch (mode) {
4032 case WL_MODE_BSS:
4033 return NL80211_IFTYPE_STATION;
4034 case WL_MODE_IBSS:
4035 return NL80211_IFTYPE_ADHOC;
4036 case WL_MODE_AP:
4037 return NL80211_IFTYPE_AP;
4038 default:
4039 return NL80211_IFTYPE_UNSPECIFIED;
4040 }
4041
4042 return err;
4043}
4044
4045static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev)
4046{
4047 struct wireless_dev *wdev;
4048 s32 err = 0;
4049 wdev = kzalloc(sizeof(*wdev), GFP_KERNEL);
4050 if (unlikely(!wdev)) {
4051 WL_ERR(("Could not allocate wireless device\n"));
4052 return ERR_PTR(-ENOMEM);
4053 }
4054 wdev->wiphy =
4055 wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv));
4056 if (unlikely(!wdev->wiphy)) {
4057 WL_ERR(("Couldn not allocate wiphy device\n"));
4058 err = -ENOMEM;
4059 goto wiphy_new_out;
4060 }
4061 set_wiphy_dev(wdev->wiphy, sdiofunc_dev);
4062 wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX;
4063 /* Report how many SSIDs Driver can support per Scan request */
4064 wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX;
4065 wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX;
4066 wdev->wiphy->interface_modes =
4067 BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC)
4068 | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR);
4069
4070 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz;
4071 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a;
4072 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
4073 wdev->wiphy->cipher_suites = __wl_cipher_suites;
4074 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
4075 wdev->wiphy->max_remain_on_channel_duration = 5000;
4076 wdev->wiphy->mgmt_stypes = wl_cfg80211_default_mgmt_stypes;
4077#ifndef WL_POWERSAVE_DISABLED
4078 wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
4079#else
4080 wdev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
4081#endif /* !WL_POWERSAVE_DISABLED */
4082 wdev->wiphy->flags |= WIPHY_FLAG_NETNS_OK |
4083 WIPHY_FLAG_4ADDR_AP |
4084#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)
4085 WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS |
4086#endif
4087 WIPHY_FLAG_4ADDR_STATION;
4088
4089 WL_DBG(("Registering custom regulatory)\n"));
4090 wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
4091 wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom);
4092 /* Now we can register wiphy with cfg80211 module */
4093 err = wiphy_register(wdev->wiphy);
4094 if (unlikely(err < 0)) {
4095 WL_ERR(("Couldn not register wiphy device (%d)\n", err));
4096 goto wiphy_register_out;
4097 }
4098 return wdev;
4099
4100wiphy_register_out:
4101 wiphy_free(wdev->wiphy);
4102
4103wiphy_new_out:
4104 kfree(wdev);
4105
4106 return ERR_PTR(err);
4107}
4108
4109static void wl_free_wdev(struct wl_priv *wl)
4110{
4111 int i;
4112 struct wireless_dev *wdev = wl->wdev;
4113
4114 if (unlikely(!wdev)) {
4115 WL_ERR(("wdev is invalid\n"));
4116 return;
4117 }
4118
4119 for (i = 0; i < VWDEV_CNT; i++) {
4120 if ((wl->vwdev[i] != NULL)) {
4121 kfree(wl->vwdev[i]);
4122 wl->vwdev[i] = NULL;
4123 }
4124 }
4125 wiphy_unregister(wdev->wiphy);
4126 wdev->wiphy->dev.parent = NULL;
4127 wiphy_free(wdev->wiphy);
4128 kfree(wdev);
4129}
4130
4131static s32 wl_inform_bss(struct wl_priv *wl)
4132{
4133 struct wl_scan_results *bss_list;
4134 struct wl_bss_info *bi = NULL; /* must be initialized */
4135 s32 err = 0;
4136 s32 i;
4137
4138 bss_list = wl->bss_list;
4139 WL_DBG(("scanned AP count (%d)\n", bss_list->count));
4140 bi = next_bss(bss_list, bi);
4141 for_each_bss(bss_list, bi, i) {
4142 err = wl_inform_single_bss(wl, bi);
4143 if (unlikely(err))
4144 break;
4145 }
4146 return err;
4147}
4148
4149static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi)
4150{
4151 struct wiphy *wiphy = wiphy_from_scan(wl);
4152 struct ieee80211_mgmt *mgmt;
4153 struct ieee80211_channel *channel;
4154 struct ieee80211_supported_band *band;
4155 struct wl_cfg80211_bss_info *notif_bss_info;
4156 struct wl_scan_req *sr = wl_to_sr(wl);
4157 struct beacon_proberesp *beacon_proberesp;
4158 s32 mgmt_type;
4159 s32 signal;
4160 u32 freq;
4161 s32 err = 0;
4162
4163 if (unlikely(dtoh32(bi->length) > WL_BSS_INFO_MAX)) {
4164 WL_DBG(("Beacon is larger than buffer. Discarding\n"));
4165 return err;
4166 }
4167 notif_bss_info = kzalloc(sizeof(*notif_bss_info) + sizeof(*mgmt)
4168 - sizeof(u8) + WL_BSS_INFO_MAX, GFP_KERNEL);
4169 if (unlikely(!notif_bss_info)) {
4170 WL_ERR(("notif_bss_info alloc failed\n"));
4171 return -ENOMEM;
4172 }
4173 mgmt = (struct ieee80211_mgmt *)notif_bss_info->frame_buf;
4174 notif_bss_info->channel =
4175 bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(bi->chanspec);
4176
4177 if (notif_bss_info->channel <= CH_MAX_2G_CHANNEL)
4178 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4179 else
4180 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4181 notif_bss_info->rssi = dtoh16(bi->RSSI);
4182 memcpy(mgmt->bssid, &bi->BSSID, ETHER_ADDR_LEN);
4183 mgmt_type = wl->active_scan ?
4184 IEEE80211_STYPE_PROBE_RESP : IEEE80211_STYPE_BEACON;
4185 if (!memcmp(bi->SSID, sr->ssid.SSID, bi->SSID_len)) {
4186 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | mgmt_type);
4187 }
4188 beacon_proberesp = wl->active_scan ?
4189 (struct beacon_proberesp *)&mgmt->u.probe_resp :
4190 (struct beacon_proberesp *)&mgmt->u.beacon;
4191 beacon_proberesp->timestamp = 0;
4192 beacon_proberesp->beacon_int = cpu_to_le16(bi->beacon_period);
4193 beacon_proberesp->capab_info = cpu_to_le16(bi->capability);
4194 wl_rst_ie(wl);
4195
4196 wl_mrg_ie(wl, ((u8 *) bi) + bi->ie_offset, bi->ie_length);
4197 wl_cp_ie(wl, beacon_proberesp->variable, WL_BSS_INFO_MAX -
4198 offsetof(struct wl_cfg80211_bss_info, frame_buf));
4199 notif_bss_info->frame_len = offsetof(struct ieee80211_mgmt,
4200 u.beacon.variable) + wl_get_ielen(wl);
4201#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
4202 freq = ieee80211_channel_to_frequency(notif_bss_info->channel);
4203#else
4204 freq = ieee80211_channel_to_frequency(notif_bss_info->channel, band->band);
4205#endif
4206 channel = ieee80211_get_channel(wiphy, freq);
4207
4208 WL_DBG(("SSID : \"%s\", rssi %d, channel %d, capability : 0x04%x, bssid %pM"
4209 "mgmt_type %d frame_len %d\n", bi->SSID,
4210 notif_bss_info->rssi, notif_bss_info->channel,
4211 mgmt->u.beacon.capab_info, &bi->BSSID, mgmt_type,
4212 notif_bss_info->frame_len));
4213
4214 signal = notif_bss_info->rssi * 100;
4215
4216 if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
4217 le16_to_cpu(notif_bss_info->frame_len),
4218 signal, GFP_KERNEL))) {
4219 WL_ERR(("cfg80211_inform_bss_frame error\n"));
4220 kfree(notif_bss_info);
4221 return -EINVAL;
4222 }
4223 kfree(notif_bss_info);
4224
4225 return err;
4226}
4227
4228static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev)
4229{
4230 u32 event = ntoh32(e->event_type);
4231 u32 status = ntoh32(e->status);
4232 u16 flags = ntoh16(e->flags);
4233
4234 WL_DBG(("event %d, status %d\n", event, status));
4235 if (event == WLC_E_SET_SSID) {
4236 if (status == WLC_E_STATUS_SUCCESS) {
4237 if (!wl_is_ibssmode(wl, ndev))
4238 return true;
4239 }
4240 } else if (event == WLC_E_LINK) {
4241 if (flags & WLC_EVENT_MSG_LINK)
4242 return true;
4243 }
4244
4245 WL_DBG(("wl_is_linkup false\n"));
4246 return false;
4247}
4248
4249static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e)
4250{
4251 u32 event = ntoh32(e->event_type);
4252 u16 flags = ntoh16(e->flags);
4253
4254 if (event == WLC_E_DEAUTH_IND ||
4255 event == WLC_E_DISASSOC_IND ||
4256 event == WLC_E_DISASSOC ||
4257 event == WLC_E_DEAUTH) {
4258 return true;
4259 } else if (event == WLC_E_LINK) {
4260 if (!(flags & WLC_EVENT_MSG_LINK))
4261 return true;
4262 }
4263
4264 return false;
4265}
4266
4267static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e)
4268{
4269 u32 event = ntoh32(e->event_type);
4270 u32 status = ntoh32(e->status);
4271
4272 if (event == WLC_E_LINK && status == WLC_E_STATUS_NO_NETWORKS)
4273 return true;
4274 if (event == WLC_E_SET_SSID && status != WLC_E_STATUS_SUCCESS)
4275 return true;
4276
4277 return false;
4278}
4279
4280static s32
4281wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev,
4282 const wl_event_msg_t *e, void *data)
4283{
4284 bool act;
4285 bool isfree = false;
4286 s32 err = 0;
4287 s32 freq;
4288 s32 channel;
4289 u8 body[200];
4290 u32 event = ntoh32(e->event_type);
4291 u32 reason = ntoh32(e->reason);
4292 u32 len = ntoh32(e->datalen);
4293 u16 fc = 0;
4294 u8 *mgmt_frame;
4295 u8 bsscfgidx = e->bsscfgidx;
4296 struct ieee80211_supported_band *band;
4297 struct ether_addr da;
4298 struct ether_addr bssid;
4299 struct wiphy *wiphy = wl_to_wiphy(wl);
4300 channel_info_t ci;
4301
4302 memset(body, 0, sizeof(body));
4303 memset(&bssid, 0, ETHER_ADDR_LEN);
4304 WL_DBG(("Enter \n"));
4305
4306 if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
4307 memcpy(body, data, len);
4308 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
4309 NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
4310 memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
4311 err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
4312 switch (event) {
4313 case WLC_E_ASSOC_IND:
4314 fc = FC_ASSOC_REQ;
4315 break;
4316 case WLC_E_REASSOC_IND:
4317 fc = FC_REASSOC_REQ;
4318 break;
4319 case WLC_E_DISASSOC_IND:
4320 fc = FC_DISASSOC;
4321 break;
4322 case WLC_E_DEAUTH_IND:
4323 fc = FC_DISASSOC;
4324 break;
4325 case WLC_E_DEAUTH:
4326 fc = FC_DISASSOC;
4327 break;
4328 default:
4329 fc = 0;
4330 goto exit;
4331 }
4332 if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false)))
4333 return err;
4334
4335 channel = dtoh32(ci.hw_channel);
4336 if (channel <= CH_MAX_2G_CHANNEL)
4337 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4338 else
4339 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4340
4341#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
4342 freq = ieee80211_channel_to_frequency(channel);
4343#else
4344 freq = ieee80211_channel_to_frequency(channel, band->band);
4345#endif
4346
4347 err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid,
4348 &mgmt_frame, &len, body);
4349 if (err < 0)
4350 goto exit;
4351 isfree = true;
4352
4353 if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) {
4354 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
4355 } else if (event == WLC_E_DISASSOC_IND) {
4356 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
4357 } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) {
4358 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC);
4359 }
4360
4361 } else {
4362 WL_DBG(("wl_notify_connect_status : event %d status : %d \n",
4363 ntoh32(e->event_type), ntoh32(e->status)));
4364 if (wl_is_linkup(wl, e, ndev)) {
4365 wl_link_up(wl);
4366 act = true;
4367 wl_update_prof(wl, e, &act, WL_PROF_ACT);
4368 wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
4369 if (wl_is_ibssmode(wl, ndev)) {
4370 printk("cfg80211_ibss_joined\n");
4371 cfg80211_ibss_joined(ndev, (s8 *)&e->addr,
4372 GFP_KERNEL);
4373 WL_DBG(("joined in IBSS network\n"));
4374 } else {
4375 if (!wl_get_drv_status(wl, DISCONNECTING)) {
4376 printk("wl_bss_connect_done succeeded status=(0x%x)\n",
4377 (int)wl->status);
4378 wl_bss_connect_done(wl, ndev, e, data, true);
4379 WL_DBG(("joined in BSS network \"%s\"\n",
4380 ((struct wlc_ssid *)
4381 wl_read_prof(wl, WL_PROF_SSID))->SSID));
4382 }
4383 }
4384
4385 } else if (wl_is_linkdown(wl, e)) {
4386 if (wl->scan_request) {
4387 del_timer_sync(&wl->scan_timeout);
4388 if (wl->escan_on) {
4389 wl_notify_escan_complete(wl, true);
4390 } else
4391 wl_iscan_aborted(wl);
4392 }
4393 if (wl_get_drv_status(wl, CONNECTED)) {
4394 scb_val_t scbval;
4395 u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID);
4396 printk("link down, call cfg80211_disconnected\n");
4397 wl_clr_drv_status(wl, CONNECTED);
4398 /* To make sure disconnect, explictly send dissassoc
4399 * for BSSID 00:00:00:00:00:00 issue
4400 */
4401 scbval.val = WLAN_REASON_DEAUTH_LEAVING;
4402
4403 memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN);
4404 scbval.val = htod32(scbval.val);
4405 wldev_ioctl(ndev, WLC_DISASSOC, &scbval,
4406 sizeof(scb_val_t), true);
4407 cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL);
4408 wl_link_down(wl);
4409 wl_init_prof(wl);
4410 } else if (wl_get_drv_status(wl, CONNECTING)) {
4411 printk("link down, during connecting\n");
4412 wl_bss_connect_done(wl, ndev, e, data, false);
4413 }
4414 wl_clr_drv_status(wl, DISCONNECTING);
4415
4416 } else if (wl_is_nonetwork(wl, e)) {
4417 printk("connect failed event=%d e->status 0x%x\n",
4418 event, (int)ntoh32(e->status));
4419 /* Clean up any pending scan request */
4420 if (wl->scan_request) {
4421 del_timer_sync(&wl->scan_timeout);
4422 if (wl->escan_on) {
4423 wl_notify_escan_complete(wl, true);
4424 } else
4425 wl_iscan_aborted(wl);
4426 }
4427 if (wl_get_drv_status(wl, CONNECTING))
4428 wl_bss_connect_done(wl, ndev, e, data, false);
4429 } else {
4430 printk("%s nothing\n", __FUNCTION__);
4431 }
4432 }
4433exit:
4434 if (isfree)
4435 kfree(mgmt_frame);
4436 return err;
4437}
4438
4439static s32
4440wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev,
4441 const wl_event_msg_t *e, void *data)
4442{
4443 bool act;
4444 s32 err = 0;
4445 u32 event = be32_to_cpu(e->event_type);
4446 u32 status = be32_to_cpu(e->status);
4447 WL_DBG(("Enter \n"));
4448 if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) {
4449 if (wl_get_drv_status(wl, CONNECTED))
4450 wl_bss_roaming_done(wl, ndev, e, data);
4451 else
4452 wl_bss_connect_done(wl, ndev, e, data, true);
4453 act = true;
4454 wl_update_prof(wl, e, &act, WL_PROF_ACT);
4455 wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
4456 }
4457 return err;
4458}
4459
4460static __used s32
4461wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len)
4462{
4463 struct wl_priv *wl = wlcfg_drv_priv;
4464 u32 buflen;
4465
4466 buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
4467 BUG_ON(unlikely(!buflen));
4468
4469 return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, true);
4470}
4471
4472static s32
4473wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf,
4474 s32 buf_len)
4475{
4476 struct wl_priv *wl = wlcfg_drv_priv;
4477 u32 len;
4478 s32 err = 0;
4479
4480 len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX);
4481 BUG_ON(unlikely(!len));
4482 err = wldev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf,
4483 WL_IOCTL_LEN_MAX, false);
4484 if (unlikely(err)) {
4485 WL_ERR(("error (%d)\n", err));
4486 return err;
4487 }
4488 memcpy(buf, wl->ioctl_buf, buf_len);
4489
4490 return err;
4491}
4492
4493static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev)
4494{
4495 wl_assoc_info_t assoc_info;
4496 struct wl_connect_info *conn_info = wl_to_conn(wl);
4497 s32 err = 0;
4498
4499 WL_DBG(("Enter \n"));
4500 err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf,
4501 WL_ASSOC_INFO_MAX);
4502 if (unlikely(err)) {
4503 WL_ERR(("could not get assoc info (%d)\n", err));
4504 return err;
4505 }
4506 memcpy(&assoc_info, wl->extra_buf, sizeof(wl_assoc_info_t));
4507 assoc_info.req_len = htod32(assoc_info.req_len);
4508 assoc_info.resp_len = htod32(assoc_info.resp_len);
4509 assoc_info.flags = htod32(assoc_info.flags);
4510 if (conn_info->req_ie_len) {
4511 conn_info->req_ie_len = 0;
4512 bzero(conn_info->req_ie, sizeof(conn_info->req_ie));
4513 }
4514 if (conn_info->resp_ie_len) {
4515 conn_info->resp_ie_len = 0;
4516 bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie));
4517 }
4518 if (assoc_info.req_len) {
4519 err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf,
4520 WL_ASSOC_INFO_MAX);
4521 if (unlikely(err)) {
4522 WL_ERR(("could not get assoc req (%d)\n", err));
4523 return err;
4524 }
4525 conn_info->req_ie_len = assoc_info.req_len - sizeof(struct dot11_assoc_req);
4526 if (assoc_info.flags & WLC_ASSOC_REQ_IS_REASSOC) {
4527 conn_info->req_ie_len -= ETHER_ADDR_LEN;
4528 }
4529 if (conn_info->req_ie_len <= MAX_REQ_LINE)
4530 memcpy(conn_info->req_ie, wl->extra_buf, conn_info->req_ie_len);
4531 else {
4532 WL_ERR(("%s IE size %d above max %d size \n",
4533 __FUNCTION__, conn_info->req_ie_len, MAX_REQ_LINE));
4534 return err;
4535 }
4536 } else {
4537 conn_info->req_ie_len = 0;
4538 }
4539 if (assoc_info.resp_len) {
4540 err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf,
4541 WL_ASSOC_INFO_MAX);
4542 if (unlikely(err)) {
4543 WL_ERR(("could not get assoc resp (%d)\n", err));
4544 return err;
4545 }
4546 conn_info->resp_ie_len = assoc_info.resp_len -sizeof(struct dot11_assoc_resp);
4547 if (conn_info->resp_ie_len <= MAX_REQ_LINE)
4548 memcpy(conn_info->resp_ie, wl->extra_buf, conn_info->resp_ie_len);
4549 else {
4550 WL_ERR(("%s IE size %d above max %d size \n",
4551 __FUNCTION__, conn_info->resp_ie_len, MAX_REQ_LINE));
4552 return err;
4553 }
4554 } else {
4555 conn_info->resp_ie_len = 0;
4556 }
4557 WL_DBG(("req len (%d) resp len (%d)\n", conn_info->req_ie_len,
4558 conn_info->resp_ie_len));
4559
4560 return err;
4561}
4562
4563static void wl_ch_to_chanspec(int ch, struct wl_join_params *join_params,
4564 size_t *join_params_size)
4565{
4566 chanspec_t chanspec = 0;
4567
4568 if (ch != 0) {
4569 join_params->params.chanspec_num = 1;
4570 join_params->params.chanspec_list[0] = ch;
4571
4572 if (join_params->params.chanspec_list[0] <= CH_MAX_2G_CHANNEL)
4573 chanspec |= WL_CHANSPEC_BAND_2G;
4574 else
4575 chanspec |= WL_CHANSPEC_BAND_5G;
4576
4577 chanspec |= WL_CHANSPEC_BW_20;
4578 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
4579
4580 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
4581 join_params->params.chanspec_num * sizeof(chanspec_t);
4582
4583 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
4584 join_params->params.chanspec_list[0] |= chanspec;
4585 join_params->params.chanspec_list[0] =
4586 htodchanspec(join_params->params.chanspec_list[0]);
4587
4588 join_params->params.chanspec_num =
4589 htod32(join_params->params.chanspec_num);
4590
4591 WL_DBG(("%s join_params->params.chanspec_list[0]= %X\n",
4592 __FUNCTION__, join_params->params.chanspec_list[0]));
4593
4594 }
4595}
4596
4597static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev)
4598{
4599 struct cfg80211_bss *bss;
4600 struct wl_bss_info *bi;
4601 struct wlc_ssid *ssid;
4602 struct bcm_tlv *tim;
4603 u16 beacon_interval;
4604 u8 dtim_period;
4605 size_t ie_len;
4606 u8 *ie;
4607 u8 *curbssid;
4608 s32 err = 0;
4609 struct wiphy *wiphy;
4610 wiphy = wl_to_wiphy(wl);
4611
4612 if (wl_is_ibssmode(wl, ndev))
4613 return err;
4614
4615 ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID);
4616 curbssid = wl_read_prof(wl, WL_PROF_BSSID);
4617 bss = cfg80211_get_bss(wiphy, NULL, curbssid,
4618 ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS,
4619 WLAN_CAPABILITY_ESS);
4620
4621 mutex_lock(&wl->usr_sync);
4622 if (unlikely(!bss)) {
4623 WL_DBG(("Could not find the AP\n"));
4624 *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX);
4625 err = wldev_ioctl(ndev, WLC_GET_BSS_INFO,
4626 wl->extra_buf, WL_EXTRA_BUF_MAX, false);
4627 if (unlikely(err)) {
4628 WL_ERR(("Could not get bss info %d\n", err));
4629 goto update_bss_info_out;
4630 }
4631 bi = (struct wl_bss_info *)(wl->extra_buf + 4);
4632 if (memcmp(bi->BSSID.octet, curbssid, ETHER_ADDR_LEN)) {
4633 err = -EIO;
4634 goto update_bss_info_out;
4635 }
4636 err = wl_inform_single_bss(wl, bi);
4637 if (unlikely(err))
4638 goto update_bss_info_out;
4639
4640 ie = ((u8 *)bi) + bi->ie_offset;
4641 ie_len = bi->ie_length;
4642 beacon_interval = cpu_to_le16(bi->beacon_period);
4643 } else {
4644 WL_DBG(("Found the AP in the list - BSSID %pM\n", bss->bssid));
4645 ie = bss->information_elements;
4646 ie_len = bss->len_information_elements;
4647 beacon_interval = bss->beacon_interval;
4648 cfg80211_put_bss(bss);
4649 }
4650
4651 tim = bcm_parse_tlvs(ie, ie_len, WLAN_EID_TIM);
4652 if (tim) {
4653 dtim_period = tim->data[1];
4654 } else {
4655 /*
4656 * active scan was done so we could not get dtim
4657 * information out of probe response.
4658 * so we speficially query dtim information to dongle.
4659 */
4660 err = wldev_ioctl(ndev, WLC_GET_DTIMPRD,
4661 &dtim_period, sizeof(dtim_period), false);
4662 if (unlikely(err)) {
4663 WL_ERR(("WLC_GET_DTIMPRD error (%d)\n", err));
4664 goto update_bss_info_out;
4665 }
4666 }
4667
4668 wl_update_prof(wl, NULL, &beacon_interval, WL_PROF_BEACONINT);
4669 wl_update_prof(wl, NULL, &dtim_period, WL_PROF_DTIMPERIOD);
4670
4671update_bss_info_out:
4672 mutex_unlock(&wl->usr_sync);
4673 return err;
4674}
4675
4676static s32
4677wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev,
4678 const wl_event_msg_t *e, void *data)
4679{
4680 struct wl_connect_info *conn_info = wl_to_conn(wl);
4681 s32 err = 0;
4682 u8 *curbssid;
4683
4684 wl_get_assoc_ies(wl, ndev);
4685 wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
4686 curbssid = wl_read_prof(wl, WL_PROF_BSSID);
4687 wl_update_bss_info(wl, ndev);
4688 wl_update_pmklist(ndev, wl->pmk_list, err);
4689 cfg80211_roamed(ndev,
4690#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
4691 NULL,
4692#endif
4693 curbssid,
4694 conn_info->req_ie, conn_info->req_ie_len,
4695 conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
4696 WL_DBG(("Report roaming result\n"));
4697
4698 wl_set_drv_status(wl, CONNECTED);
4699
4700 return err;
4701}
4702
4703static s32
4704wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev,
4705 const wl_event_msg_t *e, void *data, bool completed)
4706{
4707 struct wl_connect_info *conn_info = wl_to_conn(wl);
4708 s32 err = 0;
4709 u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID);
4710 WL_DBG((" enter\n"));
4711 if (wl->scan_request) {
4712 wl_cfg80211_scan_abort(wl, ndev);
4713 }
4714 if (wl_get_drv_status(wl, CONNECTING)) {
4715 wl_clr_drv_status(wl, CONNECTING);
4716 if (completed) {
4717 wl_get_assoc_ies(wl, ndev);
4718 wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID);
4719 curbssid = wl_read_prof(wl, WL_PROF_BSSID);
4720 wl_update_bss_info(wl, ndev);
4721 wl_update_pmklist(ndev, wl->pmk_list, err);
4722 wl_set_drv_status(wl, CONNECTED);
4723 }
4724 cfg80211_connect_result(ndev,
4725 curbssid,
4726 conn_info->req_ie,
4727 conn_info->req_ie_len,
4728 conn_info->resp_ie,
4729 conn_info->resp_ie_len,
4730 completed ? WLAN_STATUS_SUCCESS : WLAN_STATUS_AUTH_TIMEOUT,
4731 GFP_KERNEL);
4732 if (completed)
4733 WL_INFO(("Report connect result - connection succeeded\n"));
4734 else
4735 WL_ERR(("Report connect result - connection failed\n"));
4736 }
4737 return err;
4738}
4739
4740static s32
4741wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev,
4742 const wl_event_msg_t *e, void *data)
4743{
4744 u16 flags = ntoh16(e->flags);
4745 enum nl80211_key_type key_type;
4746
4747 mutex_lock(&wl->usr_sync);
4748 if (flags & WLC_EVENT_MSG_GROUP)
4749 key_type = NL80211_KEYTYPE_GROUP;
4750 else
4751 key_type = NL80211_KEYTYPE_PAIRWISE;
4752
4753 cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1,
4754 NULL, GFP_KERNEL);
4755 mutex_unlock(&wl->usr_sync);
4756
4757 return 0;
4758}
4759
4760static s32
4761wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev,
4762 const wl_event_msg_t *e, void *data)
4763{
4764 struct channel_info channel_inform;
4765 struct wl_scan_results *bss_list;
4766 u32 len = WL_SCAN_BUF_MAX;
4767 s32 err = 0;
4768 unsigned long flags;
4769
4770 WL_DBG(("Enter \n"));
4771 if (wl->iscan_on && wl->iscan_kickstart)
4772 return wl_wakeup_iscan(wl_to_iscan(wl));
4773
4774 mutex_lock(&wl->usr_sync);
4775 wl_clr_drv_status(wl, SCANNING);
4776 err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform,
4777 sizeof(channel_inform), false);
4778 if (unlikely(err)) {
4779 WL_ERR(("scan busy (%d)\n", err));
4780 goto scan_done_out;
4781 }
4782 channel_inform.scan_channel = dtoh32(channel_inform.scan_channel);
4783 if (unlikely(channel_inform.scan_channel)) {
4784
4785 WL_DBG(("channel_inform.scan_channel (%d)\n",
4786 channel_inform.scan_channel));
4787 }
4788 wl->bss_list = wl->scan_results;
4789 bss_list = wl->bss_list;
4790 memset(bss_list, 0, len);
4791 bss_list->buflen = htod32(len);
4792 err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false);
4793 if (unlikely(err)) {
4794 WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err));
4795 err = -EINVAL;
4796 goto scan_done_out;
4797 }
4798 bss_list->buflen = dtoh32(bss_list->buflen);
4799 bss_list->version = dtoh32(bss_list->version);
4800 bss_list->count = dtoh32(bss_list->count);
4801
4802 err = wl_inform_bss(wl);
4803
4804scan_done_out:
4805 del_timer_sync(&wl->scan_timeout);
4806 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
4807 if (wl->scan_request) {
4808 WL_DBG(("cfg80211_scan_done\n"));
4809 cfg80211_scan_done(wl->scan_request, false);
4810 wl->scan_request = NULL;
4811 }
4812 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
4813 mutex_unlock(&wl->usr_sync);
4814 return err;
4815}
4816static s32
4817wl_frame_get_mgmt(u16 fc, const struct ether_addr *da,
4818 const struct ether_addr *sa, const struct ether_addr *bssid,
4819 u8 **pheader, u32 *body_len, u8 *pbody)
4820{
4821 struct dot11_management_header *hdr;
4822 u32 totlen = 0;
4823 s32 err = 0;
4824 u8 *offset;
4825 u32 prebody_len = *body_len;
4826 switch (fc) {
4827 case FC_ASSOC_REQ:
4828 /* capability , listen interval */
4829 totlen = DOT11_ASSOC_REQ_FIXED_LEN;
4830 *body_len += DOT11_ASSOC_REQ_FIXED_LEN;
4831 break;
4832
4833 case FC_REASSOC_REQ:
4834 /* capability, listen inteval, ap address */
4835 totlen = DOT11_REASSOC_REQ_FIXED_LEN;
4836 *body_len += DOT11_REASSOC_REQ_FIXED_LEN;
4837 break;
4838 }
4839 totlen += DOT11_MGMT_HDR_LEN + prebody_len;
4840 *pheader = kzalloc(totlen, GFP_KERNEL);
4841 if (*pheader == NULL) {
4842 WL_ERR(("memory alloc failed \n"));
4843 return -ENOMEM;
4844 }
4845 hdr = (struct dot11_management_header *) (*pheader);
4846 hdr->fc = htol16(fc);
4847 hdr->durid = 0;
4848 hdr->seq = 0;
4849 offset = (u8*)(hdr + 1) + (totlen - DOT11_MGMT_HDR_LEN - prebody_len);
4850 bcopy((const char*)da, (u8*)&hdr->da, ETHER_ADDR_LEN);
4851 bcopy((const char*)sa, (u8*)&hdr->sa, ETHER_ADDR_LEN);
4852 bcopy((const char*)bssid, (u8*)&hdr->bssid, ETHER_ADDR_LEN);
4853 bcopy((const char*)pbody, offset, prebody_len);
4854 *body_len = totlen;
4855 return err;
4856}
4857static s32
4858wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev,
4859 const wl_event_msg_t *e, void *data)
4860{
4861 struct ieee80211_supported_band *band;
4862 struct wiphy *wiphy = wl_to_wiphy(wl);
4863 struct ether_addr da;
4864 struct ether_addr bssid;
4865 bool isfree = false;
4866 s32 err = 0;
4867 s32 freq;
4868 wifi_p2p_pub_act_frame_t *act_frm;
4869 wl_event_rx_frame_data_t *rxframe =
4870 (wl_event_rx_frame_data_t*)data;
4871 u32 event = ntoh32(e->event_type);
4872 u8 *mgmt_frame;
4873 u8 bsscfgidx = e->bsscfgidx;
4874 u32 mgmt_frame_len = ntoh32(e->datalen) - sizeof(wl_event_rx_frame_data_t);
4875 u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK));
4876
4877 memset(&bssid, 0, ETHER_ADDR_LEN);
4878 if (channel <= CH_MAX_2G_CHANNEL)
4879 band = wiphy->bands[IEEE80211_BAND_2GHZ];
4880 else
4881 band = wiphy->bands[IEEE80211_BAND_5GHZ];
4882
4883#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS)
4884 freq = ieee80211_channel_to_frequency(channel);
4885#else
4886 freq = ieee80211_channel_to_frequency(channel, band->band);
4887#endif
4888 if (event == WLC_E_ACTION_FRAME_RX) {
4889 wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr",
4890 NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx);
4891
4892 wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false);
4893 memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN);
4894 err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid,
4895 &mgmt_frame, &mgmt_frame_len,
4896 (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1));
4897 if (err < 0) {
4898 WL_ERR(("%s: Error in receiving action frame len %d channel %d freq %d\n",
4899 __func__, mgmt_frame_len, channel, freq));
4900 goto exit;
4901 }
4902 isfree = true;
4903 act_frm =
4904 (wifi_p2p_pub_act_frame_t *) (&mgmt_frame[DOT11_MGMT_HDR_LEN]);
4905 /*
4906 * After complete GO Negotiation, roll back to mpc mode
4907 */
4908 if (act_frm->subtype == P2P_PAF_GON_CONF) {
4909 wldev_iovar_setint(ndev, "mpc", 1);
4910 }
4911 } else {
4912 mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1);
4913 }
4914
4915 cfg80211_rx_mgmt(ndev, freq, mgmt_frame, mgmt_frame_len, GFP_ATOMIC);
4916
4917 WL_DBG(("%s: mgmt_frame_len (%d) , e->datalen (%d), channel (%d), freq (%d)\n", __func__,
4918 mgmt_frame_len, ntoh32(e->datalen), channel, freq));
4919
4920 if (isfree)
4921 kfree(mgmt_frame);
4922exit:
4923 return 0;
4924}
4925
4926static void wl_init_conf(struct wl_conf *conf)
4927{
4928 s32 i = 0;
4929 WL_DBG(("Enter \n"));
4930 for (i = 0; i <= VWDEV_CNT; i++) {
4931 conf->mode[i].type = -1;
4932 conf->mode[i].ndev = NULL;
4933 }
4934 conf->frag_threshold = (u32)-1;
4935 conf->rts_threshold = (u32)-1;
4936 conf->retry_short = (u32)-1;
4937 conf->retry_long = (u32)-1;
4938 conf->tx_power = -1;
4939}
4940
4941static void wl_init_prof(struct wl_priv *wl)
4942{
4943 unsigned long flags;
4944
4945 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
4946 memset(wl->profile, 0, sizeof(struct wl_profile));
4947 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
4948}
4949
4950static void wl_init_event_handler(struct wl_priv *wl)
4951{
4952 memset(wl->evt_handler, 0, sizeof(wl->evt_handler));
4953
4954 wl->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status;
4955 wl->evt_handler[WLC_E_LINK] = wl_notify_connect_status;
4956 wl->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status;
4957 wl->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status;
4958 wl->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status;
4959 wl->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status;
4960 wl->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status;
4961 wl->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status;
4962 wl->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status;
4963 wl->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status;
4964 wl->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame;
4965 wl->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
4966 wl->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame;
4967 wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete;
4968 wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete;
4969 wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete;
4970
4971}
4972
4973static s32 wl_init_priv_mem(struct wl_priv *wl)
4974{
4975 WL_DBG(("Enter \n"));
4976 wl->scan_results = (void *)kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
4977 if (unlikely(!wl->scan_results)) {
4978 WL_ERR(("Scan results alloc failed\n"));
4979 goto init_priv_mem_out;
4980 }
4981 wl->conf = (void *)kzalloc(sizeof(*wl->conf), GFP_KERNEL);
4982 if (unlikely(!wl->conf)) {
4983 WL_ERR(("wl_conf alloc failed\n"));
4984 goto init_priv_mem_out;
4985 }
4986 wl->profile = (void *)kzalloc(sizeof(*wl->profile), GFP_KERNEL);
4987 if (unlikely(!wl->profile)) {
4988 WL_ERR(("wl_profile alloc failed\n"));
4989 goto init_priv_mem_out;
4990 }
4991 wl->bss_info = (void *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
4992 if (unlikely(!wl->bss_info)) {
4993 WL_ERR(("Bss information alloc failed\n"));
4994 goto init_priv_mem_out;
4995 }
4996 wl->scan_req_int =
4997 (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL);
4998 if (unlikely(!wl->scan_req_int)) {
4999 WL_ERR(("Scan req alloc failed\n"));
5000 goto init_priv_mem_out;
5001 }
5002 wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL);
5003 if (unlikely(!wl->ioctl_buf)) {
5004 WL_ERR(("Ioctl buf alloc failed\n"));
5005 goto init_priv_mem_out;
5006 }
5007 wl->escan_ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL);
5008 if (unlikely(!wl->escan_ioctl_buf)) {
5009 WL_ERR(("Ioctl buf alloc failed\n"));
5010 goto init_priv_mem_out;
5011 }
5012 wl->extra_buf = (void *)kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
5013 if (unlikely(!wl->extra_buf)) {
5014 WL_ERR(("Extra buf alloc failed\n"));
5015 goto init_priv_mem_out;
5016 }
5017 wl->iscan = (void *)kzalloc(sizeof(*wl->iscan), GFP_KERNEL);
5018 if (unlikely(!wl->iscan)) {
5019 WL_ERR(("Iscan buf alloc failed\n"));
5020 goto init_priv_mem_out;
5021 }
5022 wl->fw = (void *)kzalloc(sizeof(*wl->fw), GFP_KERNEL);
5023 if (unlikely(!wl->fw)) {
5024 WL_ERR(("fw object alloc failed\n"));
5025 goto init_priv_mem_out;
5026 }
5027 wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL);
5028 if (unlikely(!wl->pmk_list)) {
5029 WL_ERR(("pmk list alloc failed\n"));
5030 goto init_priv_mem_out;
5031 }
5032 wl->sta_info = (void *)kzalloc(sizeof(*wl->sta_info), GFP_KERNEL);
5033 if (unlikely(!wl->sta_info)) {
5034 WL_ERR(("sta info alloc failed\n"));
5035 goto init_priv_mem_out;
5036 }
5037 return 0;
5038
5039init_priv_mem_out:
5040 wl_deinit_priv_mem(wl);
5041
5042 return -ENOMEM;
5043}
5044
5045static void wl_deinit_priv_mem(struct wl_priv *wl)
5046{
5047 kfree(wl->scan_results);
5048 wl->scan_results = NULL;
5049 kfree(wl->bss_info);
5050 wl->bss_info = NULL;
5051 kfree(wl->conf);
5052 wl->conf = NULL;
5053 kfree(wl->profile);
5054 wl->profile = NULL;
5055 kfree(wl->scan_req_int);
5056 wl->scan_req_int = NULL;
5057 kfree(wl->ioctl_buf);
5058 wl->ioctl_buf = NULL;
5059 kfree(wl->escan_ioctl_buf);
5060 wl->escan_ioctl_buf = NULL;
5061 kfree(wl->extra_buf);
5062 wl->extra_buf = NULL;
5063 kfree(wl->iscan);
5064 wl->iscan = NULL;
5065 kfree(wl->fw);
5066 wl->fw = NULL;
5067 kfree(wl->pmk_list);
5068 wl->pmk_list = NULL;
5069 kfree(wl->sta_info);
5070 wl->sta_info = NULL;
5071 if (wl->ap_info) {
5072 kfree(wl->ap_info->wpa_ie);
5073 kfree(wl->ap_info->rsn_ie);
5074 kfree(wl->ap_info->wps_ie);
5075 kfree(wl->ap_info);
5076 wl->ap_info = NULL;
5077 }
5078}
5079
5080static s32 wl_create_event_handler(struct wl_priv *wl)
5081{
5082 int ret = 0;
5083 WL_DBG(("Enter \n"));
5084
5085 wl->event_tsk.thr_pid = DHD_PID_KT_INVALID;
5086 PROC_START(wl_event_handler, wl, &wl->event_tsk, 0);
5087 if (wl->event_tsk.thr_pid < 0)
5088 ret = -ENOMEM;
5089 return ret;
5090}
5091
5092static void wl_destroy_event_handler(struct wl_priv *wl)
5093{
5094 if (wl->event_tsk.thr_pid >= 0)
5095 PROC_STOP(&wl->event_tsk);
5096}
5097
5098static void wl_term_iscan(struct wl_priv *wl)
5099{
5100 struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
5101 WL_TRACE(("In\n"));
5102 if (wl->iscan_on && iscan->tsk) {
5103 iscan->state = WL_ISCAN_STATE_IDLE;
5104 WL_INFO(("SIGTERM\n"));
5105 send_sig(SIGTERM, iscan->tsk, 1);
5106 WL_DBG(("kthread_stop\n"));
5107 kthread_stop(iscan->tsk);
5108 iscan->tsk = NULL;
5109 }
5110}
5111
5112static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted)
5113{
5114 struct wl_priv *wl = iscan_to_wl(iscan);
5115 unsigned long flags;
5116
5117 WL_DBG(("Enter \n"));
5118 if (unlikely(!wl_get_drv_status(wl, SCANNING))) {
5119 wl_clr_drv_status(wl, SCANNING);
5120 WL_ERR(("Scan complete while device not scanning\n"));
5121 return;
5122 }
5123 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
5124 wl_clr_drv_status(wl, SCANNING);
5125 if (likely(wl->scan_request)) {
5126 cfg80211_scan_done(wl->scan_request, aborted);
5127 wl->scan_request = NULL;
5128 }
5129 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
5130 wl->iscan_kickstart = false;
5131}
5132
5133static s32 wl_wakeup_iscan(struct wl_iscan_ctrl *iscan)
5134{
5135 if (likely(iscan->state != WL_ISCAN_STATE_IDLE)) {
5136 WL_DBG(("wake up iscan\n"));
5137 up(&iscan->sync);
5138 return 0;
5139 }
5140
5141 return -EIO;
5142}
5143
5144static s32
5145wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status,
5146 struct wl_scan_results **bss_list)
5147{
5148 struct wl_iscan_results list;
5149 struct wl_scan_results *results;
5150 struct wl_iscan_results *list_buf;
5151 s32 err = 0;
5152
5153 WL_DBG(("Enter \n"));
5154 memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX);
5155 list_buf = (struct wl_iscan_results *)iscan->scan_buf;
5156 results = &list_buf->results;
5157 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
5158 results->version = 0;
5159 results->count = 0;
5160
5161 memset(&list, 0, sizeof(list));
5162 list.results.buflen = htod32(WL_ISCAN_BUF_MAX);
5163 err = wldev_iovar_getbuf(iscan->dev, "iscanresults", &list,
5164 WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf,
5165 WL_ISCAN_BUF_MAX);
5166 if (unlikely(err)) {
5167 WL_ERR(("error (%d)\n", err));
5168 return err;
5169 }
5170 results->buflen = dtoh32(results->buflen);
5171 results->version = dtoh32(results->version);
5172 results->count = dtoh32(results->count);
5173 WL_DBG(("results->count = %d\n", results->count));
5174 WL_DBG(("results->buflen = %d\n", results->buflen));
5175 *status = dtoh32(list_buf->status);
5176 *bss_list = results;
5177
5178 return err;
5179}
5180
5181static s32 wl_iscan_done(struct wl_priv *wl)
5182{
5183 struct wl_iscan_ctrl *iscan = wl->iscan;
5184 s32 err = 0;
5185
5186 iscan->state = WL_ISCAN_STATE_IDLE;
5187 mutex_lock(&wl->usr_sync);
5188 wl_inform_bss(wl);
5189 wl_notify_iscan_complete(iscan, false);
5190 mutex_unlock(&wl->usr_sync);
5191
5192 return err;
5193}
5194
5195static s32 wl_iscan_pending(struct wl_priv *wl)
5196{
5197 struct wl_iscan_ctrl *iscan = wl->iscan;
5198 s32 err = 0;
5199
5200 /* Reschedule the timer */
5201 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
5202 iscan->timer_on = 1;
5203
5204 return err;
5205}
5206
5207static s32 wl_iscan_inprogress(struct wl_priv *wl)
5208{
5209 struct wl_iscan_ctrl *iscan = wl->iscan;
5210 s32 err = 0;
5211
5212 mutex_lock(&wl->usr_sync);
5213 wl_inform_bss(wl);
5214 wl_run_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
5215 mutex_unlock(&wl->usr_sync);
5216 /* Reschedule the timer */
5217 mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
5218 iscan->timer_on = 1;
5219
5220 return err;
5221}
5222
5223static s32 wl_iscan_aborted(struct wl_priv *wl)
5224{
5225 struct wl_iscan_ctrl *iscan = wl->iscan;
5226 s32 err = 0;
5227
5228 iscan->state = WL_ISCAN_STATE_IDLE;
5229 mutex_lock(&wl->usr_sync);
5230 wl_notify_iscan_complete(iscan, true);
5231 mutex_unlock(&wl->usr_sync);
5232
5233 return err;
5234}
5235
5236static s32 wl_iscan_thread(void *data)
5237{
5238 struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 };
5239 struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
5240 struct wl_priv *wl = iscan_to_wl(iscan);
5241 u32 status;
5242 int err = 0;
5243
5244 sched_setscheduler(current, SCHED_FIFO, &param);
5245 allow_signal(SIGTERM);
5246 status = WL_SCAN_RESULTS_PARTIAL;
5247 while (likely(!down_interruptible(&iscan->sync))) {
5248 if (kthread_should_stop())
5249 break;
5250 if (iscan->timer_on) {
5251 del_timer_sync(&iscan->timer);
5252 iscan->timer_on = 0;
5253 }
5254 mutex_lock(&wl->usr_sync);
5255 err = wl_get_iscan_results(iscan, &status, &wl->bss_list);
5256 if (unlikely(err)) {
5257 status = WL_SCAN_RESULTS_ABORTED;
5258 WL_ERR(("Abort iscan\n"));
5259 }
5260 mutex_unlock(&wl->usr_sync);
5261 iscan->iscan_handler[status] (wl);
5262 }
5263 if (iscan->timer_on) {
5264 del_timer_sync(&iscan->timer);
5265 iscan->timer_on = 0;
5266 }
5267 WL_DBG(("%s was terminated\n", __func__));
5268
5269 return 0;
5270}
5271
5272static void wl_scan_timeout(unsigned long data)
5273{
5274 struct wl_priv *wl = (struct wl_priv *)data;
5275
5276 if (wl->scan_request) {
5277 WL_ERR(("timer expired\n"));
5278 if (wl->escan_on)
5279 wl_notify_escan_complete(wl, true);
5280 else
5281 wl_notify_iscan_complete(wl_to_iscan(wl), true);
5282 }
5283}
5284
5285static void wl_iscan_timer(unsigned long data)
5286{
5287 struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data;
5288
5289 if (iscan) {
5290 iscan->timer_on = 0;
5291 WL_DBG(("timer expired\n"));
5292 wl_wakeup_iscan(iscan);
5293 }
5294}
5295
5296static s32 wl_invoke_iscan(struct wl_priv *wl)
5297{
5298 struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
5299 int err = 0;
5300
5301 if (wl->iscan_on && !iscan->tsk) {
5302 iscan->state = WL_ISCAN_STATE_IDLE;
5303 sema_init(&iscan->sync, 0);
5304 iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan");
5305 if (IS_ERR(iscan->tsk)) {
5306 WL_ERR(("Could not create iscan thread\n"));
5307 iscan->tsk = NULL;
5308 return -ENOMEM;
5309 }
5310 }
5311
5312 return err;
5313}
5314
5315static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan)
5316{
5317 memset(iscan->iscan_handler, 0, sizeof(iscan->iscan_handler));
5318 iscan->iscan_handler[WL_SCAN_RESULTS_SUCCESS] = wl_iscan_done;
5319 iscan->iscan_handler[WL_SCAN_RESULTS_PARTIAL] = wl_iscan_inprogress;
5320 iscan->iscan_handler[WL_SCAN_RESULTS_PENDING] = wl_iscan_pending;
5321 iscan->iscan_handler[WL_SCAN_RESULTS_ABORTED] = wl_iscan_aborted;
5322 iscan->iscan_handler[WL_SCAN_RESULTS_NO_MEM] = wl_iscan_aborted;
5323}
5324
5325static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted)
5326{
5327 unsigned long flags;
5328
5329 WL_DBG(("Enter \n"));
5330 wl_clr_drv_status(wl, SCANNING);
5331 if (wl->p2p_supported && p2p_on(wl))
5332 wl_clr_p2p_status(wl, SCANNING);
5333
5334 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
5335 if (likely(wl->scan_request)) {
5336 cfg80211_scan_done(wl->scan_request, aborted);
5337 wl->scan_request = NULL;
5338 }
5339 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
5340}
5341
5342static s32 wl_escan_handler(struct wl_priv *wl,
5343 struct net_device *ndev,
5344 const wl_event_msg_t *e, void *data)
5345{
5346 s32 err = BCME_OK;
5347 s32 status = ntoh32(e->status);
5348 wl_bss_info_t *bi;
5349 wl_escan_result_t *escan_result;
5350 wl_bss_info_t *bss = NULL;
5351 wl_scan_results_t *list;
5352 u32 bi_length;
5353 u32 i;
5354 WL_DBG((" enter event type : %d, status : %d \n",
5355 ntoh32(e->event_type), ntoh32(e->status)));
5356 if (!wl->escan_on &&
5357 !wl_get_drv_status(wl, SCANNING)) {
5358 WL_ERR(("escan is not ready \n"));
5359 return err;
5360 }
5361
5362 if (status == WLC_E_STATUS_PARTIAL) {
5363 WL_INFO(("WLC_E_STATUS_PARTIAL \n"));
5364 escan_result = (wl_escan_result_t *) data;
5365 if (!escan_result) {
5366 WL_ERR(("Invalid escan result (NULL pointer)\n"));
5367 goto exit;
5368 }
5369 if (dtoh16(escan_result->bss_count) != 1) {
5370 WL_ERR(("Invalid bss_count %d: ignoring\n", escan_result->bss_count));
5371 goto exit;
5372 }
5373 bi = escan_result->bss_info;
5374 if (!bi) {
5375 WL_ERR(("Invalid escan bss info (NULL pointer)\n"));
5376 goto exit;
5377 }
5378 bi_length = dtoh32(bi->length);
5379 if (bi_length != (dtoh32(escan_result->buflen) - WL_ESCAN_RESULTS_FIXED_SIZE)) {
5380 WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length));
5381 goto exit;
5382 }
5383 list = (wl_scan_results_t *)wl->escan_info.escan_buf;
5384 if (bi_length > ESCAN_BUF_SIZE - list->buflen) {
5385 WL_ERR(("Buffer is too small: ignoring\n"));
5386 goto exit;
5387 }
5388#define WLC_BSS_RSSI_ON_CHANNEL 0x0002
5389 for (i = 0; i < list->count; i++) {
5390 bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length))
5391 : list->bss_info;
5392
5393 if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) &&
5394 CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) &&
5395 bi->SSID_len == bss->SSID_len &&
5396 !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) {
5397 if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) ==
5398 (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) {
5399 /* preserve max RSSI if the measurements are
5400 * both on-channel or both off-channel
5401 */
5402 bss->RSSI = MAX(bss->RSSI, bi->RSSI);
5403 } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) &&
5404 (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) {
5405 /* preserve the on-channel rssi measurement
5406 * if the new measurement is off channel
5407 */
5408 bss->RSSI = bi->RSSI;
5409 bss->flags |= WLC_BSS_RSSI_ON_CHANNEL;
5410 }
5411
5412 goto exit;
5413 }
5414 }
5415 memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length);
5416 list->version = dtoh32(bi->version);
5417 list->buflen += bi_length;
5418 list->count++;
5419
5420 }
5421 else if (status == WLC_E_STATUS_SUCCESS) {
5422 wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
5423 if (likely(wl->scan_request)) {
5424 mutex_lock(&wl->usr_sync);
5425 del_timer_sync(&wl->scan_timeout);
5426 WL_INFO(("ESCAN COMPLETED\n"));
5427 wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
5428 wl_inform_bss(wl);
5429 wl_notify_escan_complete(wl, false);
5430 mutex_unlock(&wl->usr_sync);
5431 }
5432 }
5433 else if (status == WLC_E_STATUS_ABORT) {
5434 wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
5435 if (likely(wl->scan_request)) {
5436 mutex_lock(&wl->usr_sync);
5437 del_timer_sync(&wl->scan_timeout);
5438 WL_INFO(("ESCAN ABORTED\n"));
5439 wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
5440 wl_inform_bss(wl);
5441 wl_notify_escan_complete(wl, true);
5442 mutex_unlock(&wl->usr_sync);
5443 }
5444 }
5445 else {
5446 WL_ERR(("unexpected Escan Event %d : abort\n", status));
5447 wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
5448 if (likely(wl->scan_request)) {
5449 mutex_lock(&wl->usr_sync);
5450 del_timer_sync(&wl->scan_timeout);
5451 wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf;
5452 wl_inform_bss(wl);
5453 wl_notify_escan_complete(wl, true);
5454 mutex_unlock(&wl->usr_sync);
5455 }
5456 }
5457exit:
5458 return err;
5459}
5460
5461static s32 wl_init_scan(struct wl_priv *wl)
5462{
5463 struct wl_iscan_ctrl *iscan = wl_to_iscan(wl);
5464 int err = 0;
5465
5466 if (wl->iscan_on) {
5467 iscan->dev = wl_to_prmry_ndev(wl);
5468 iscan->state = WL_ISCAN_STATE_IDLE;
5469 wl_init_iscan_handler(iscan);
5470 iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS;
5471 init_timer(&iscan->timer);
5472 iscan->timer.data = (unsigned long) iscan;
5473 iscan->timer.function = wl_iscan_timer;
5474 sema_init(&iscan->sync, 0);
5475 iscan->tsk = kthread_run(wl_iscan_thread, iscan, "wl_iscan");
5476 if (IS_ERR(iscan->tsk)) {
5477 WL_ERR(("Could not create iscan thread\n"));
5478 iscan->tsk = NULL;
5479 return -ENOMEM;
5480 }
5481 iscan->data = wl;
5482 } else if (wl->escan_on) {
5483 wl->evt_handler[WLC_E_ESCAN_RESULT] = wl_escan_handler;
5484 wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
5485 }
5486 /* Init scan_timeout timer */
5487 init_timer(&wl->scan_timeout);
5488 wl->scan_timeout.data = (unsigned long) wl;
5489 wl->scan_timeout.function = wl_scan_timeout;
5490
5491 return err;
5492}
5493
5494static void wl_init_fw(struct wl_fw_ctrl *fw)
5495{
5496 fw->status = 0;
5497}
5498
5499static s32 wl_init_priv(struct wl_priv *wl)
5500{
5501 struct wiphy *wiphy = wl_to_wiphy(wl);
5502 s32 err = 0;
5503 s32 i = 0;
5504
5505 wl->scan_request = NULL;
5506 wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT);
5507 wl->iscan_on = false;
5508 wl->escan_on = true;
5509 wl->roam_on = false;
5510 wl->iscan_kickstart = false;
5511 wl->active_scan = true;
5512 wl->dongle_up = false;
5513 wl->rf_blocked = false;
5514
5515 for (i = 0; i < VWDEV_CNT; i++)
5516 wl->vwdev[i] = NULL;
5517
5518 init_waitqueue_head(&wl->dongle_event_wait);
5519 wl_init_eq(wl);
5520 err = wl_init_priv_mem(wl);
5521 if (unlikely(err))
5522 return err;
5523 if (unlikely(wl_create_event_handler(wl)))
5524 return -ENOMEM;
5525 wl_init_event_handler(wl);
5526 mutex_init(&wl->usr_sync);
5527 err = wl_init_scan(wl);
5528 if (unlikely(err))
5529 return err;
5530 wl_init_fw(wl->fw);
5531 wl_init_conf(wl->conf);
5532 wl_init_prof(wl);
5533 wl_link_down(wl);
5534
5535 return err;
5536}
5537
5538static void wl_deinit_priv(struct wl_priv *wl)
5539{
5540 wl_destroy_event_handler(wl);
5541 wl->dongle_up = false; /* dongle down */
5542 wl_flush_eq(wl);
5543 wl_link_down(wl);
5544 del_timer_sync(&wl->scan_timeout);
5545 wl_term_iscan(wl);
5546 wl_deinit_priv_mem(wl);
5547}
5548
5549#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
5550s32 wl_cfg80211_sysctl_export_devaddr(void *data)
5551{
5552 /* Export the p2p_dev_addr via sysctl interface
5553 * so that wpa_supplicant can access it
5554 */
5555 dhd_pub_t *dhd = (dhd_pub_t *)data;
5556 struct wl_priv *wl = wlcfg_drv_priv;
5557
5558 wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr);
5559
5560 sprintf((char *)&wl_sysctl_macstring[0], MACSTR, MAC2STR(wl->p2p->dev_addr.octet));
5561 sprintf((char *)&wl_sysctl_macstring[1], MACSTR, MAC2STR(wl->p2p->int_addr.octet));
5562
5563 return 0;
5564}
5565#endif /* CONFIG_SYSCTL */
5566
5567s32 wl_cfg80211_attach_post(struct net_device *ndev)
5568{
5569 struct wl_priv * wl = NULL;
5570 s32 err = 0;
5571 WL_TRACE(("In\n"));
5572 if (unlikely(!ndev)) {
5573 WL_ERR(("ndev is invaild\n"));
5574 return -ENODEV;
5575 }
5576 wl = wlcfg_drv_priv;
5577 if (wl && !wl_get_drv_status(wl, READY)) {
5578 if (wl->wdev &&
5579 wl_cfgp2p_supported(wl, ndev)) {
5580 wl->wdev->wiphy->interface_modes |=
5581 (BIT(NL80211_IFTYPE_P2P_CLIENT)|
5582 BIT(NL80211_IFTYPE_P2P_GO));
5583 if ((err = wl_cfgp2p_init_priv(wl)) != 0)
5584 goto fail;
5585#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
5586 wl_cfg80211_sysctl_export_devaddr(wl->pub);
5587#endif
5588 wl->p2p_supported = true;
5589 }
5590 } else
5591 return -ENODEV;
5592
5593 wl_set_drv_status(wl, READY);
5594fail:
5595 return err;
5596}
5597s32 wl_cfg80211_attach(struct net_device *ndev, void *data)
5598{
5599 struct wireless_dev *wdev;
5600 struct wl_priv *wl;
5601 s32 err = 0;
5602
5603 WL_TRACE(("In\n"));
5604 if (unlikely(!ndev)) {
5605 WL_ERR(("ndev is invaild\n"));
5606 return -ENODEV;
5607 }
5608 WL_DBG(("func %p\n", wl_cfg80211_get_sdio_func()));
5609 wdev = wl_alloc_wdev(&wl_cfg80211_get_sdio_func()->dev);
5610 if (unlikely(IS_ERR(wdev)))
5611 return -ENOMEM;
5612
5613 wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS);
5614 wl = (struct wl_priv *)wiphy_priv(wdev->wiphy);
5615 wl->wdev = wdev;
5616 wl->pub = data;
5617
5618 ndev->ieee80211_ptr = wdev;
5619 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
5620 wdev->netdev = ndev;
5621
5622 err = wl_init_priv(wl);
5623 if (unlikely(err)) {
5624 WL_ERR(("Failed to init iwm_priv (%d)\n", err));
5625 goto cfg80211_attach_out;
5626 }
5627
5628 err = wl_setup_rfkill(wl, TRUE);
5629 if (unlikely(err)) {
5630 WL_ERR(("Failed to setup rfkill %d\n", err));
5631 goto cfg80211_attach_out;
5632 }
5633
5634#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
5635 if (!(wl_sysctl_hdr = register_sysctl_table(wl_sysctl_table))) {
5636 WL_ERR(("%s: sysctl register failed!! \n", __func__));
5637 goto cfg80211_attach_out;
5638 }
5639#endif
5640#if defined(COEX_DHCP)
5641 if (wl_cfg80211_btcoex_init(wl))
5642 goto cfg80211_attach_out;
5643#endif /* COEX_DHCP */
5644
5645 wlcfg_drv_priv = wl;
5646 return err;
5647
5648cfg80211_attach_out:
5649 err = wl_setup_rfkill(wl, FALSE);
5650 wl_free_wdev(wl);
5651 return err;
5652}
5653
5654void wl_cfg80211_detach(void)
5655{
5656 struct wl_priv *wl;
5657
5658 wl = wlcfg_drv_priv;
5659
5660 WL_TRACE(("In\n"));
5661
5662#if defined(COEX_DHCP)
5663 wl_cfg80211_btcoex_deinit(wl);
5664#endif /* COEX_DHCP */
5665
5666#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL)
5667 if (wl_sysctl_hdr)
5668 unregister_sysctl_table(wl_sysctl_hdr);
5669#endif
5670 wl_setup_rfkill(wl, FALSE);
5671 if (wl->p2p_supported)
5672 wl_cfgp2p_deinit_priv(wl);
5673 wl_deinit_priv(wl);
5674 wlcfg_drv_priv = NULL;
5675 wl_clear_sdio_func();
5676 wl_free_wdev(wl);
5677}
5678
5679static void wl_wakeup_event(struct wl_priv *wl)
5680{
5681 if (wl->event_tsk.thr_pid >= 0) {
5682 DHD_OS_WAKE_LOCK(wl->pub);
5683 up(&wl->event_tsk.sema);
5684 }
5685}
5686
5687static s32 wl_event_handler(void *data)
5688{
5689 struct net_device *netdev;
5690 struct wl_priv *wl = NULL;
5691 struct wl_event_q *e;
5692 tsk_ctl_t *tsk = (tsk_ctl_t *)data;
5693
5694 wl = (struct wl_priv *)tsk->parent;
5695 complete(&tsk->completed);
5696
5697 while (down_interruptible (&tsk->sema) == 0) {
5698 SMP_RD_BARRIER_DEPENDS();
5699 if (tsk->terminated)
5700 break;
5701 while ((e = wl_deq_event(wl))) {
5702 WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx));
5703 netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx);
5704 if (!netdev)
5705 netdev = wl_to_prmry_ndev(wl);
5706 if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) {
5707 wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata);
5708 } else {
5709 WL_DBG(("Unknown Event (%d): ignoring\n", e->etype));
5710 }
5711 wl_put_event(e);
5712 }
5713 DHD_OS_WAKE_UNLOCK(wl->pub);
5714 }
5715 WL_DBG(("%s was terminated\n", __func__));
5716 complete_and_exit(&tsk->completed, 0);
5717 return 0;
5718}
5719
5720void
5721wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data)
5722{
5723 u32 event_type = ntoh32(e->event_type);
5724 struct wl_priv *wl = wlcfg_drv_priv;
5725
5726#if (WL_DBG_LEVEL > 0)
5727 s8 *estr = (event_type <= sizeof(wl_dbg_estr) / WL_DBG_ESTR_MAX - 1) ?
5728 wl_dbg_estr[event_type] : (s8 *) "Unknown";
5729 WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr));
5730#endif /* (WL_DBG_LEVEL > 0) */
5731
5732 if (event_type == WLC_E_PFN_NET_FOUND)
5733 WL_ERR((" PNO Event\n"));
5734
5735 if (likely(!wl_enq_event(wl, ndev, event_type, e, data)))
5736 wl_wakeup_event(wl);
5737}
5738
5739static void wl_init_eq(struct wl_priv *wl)
5740{
5741 wl_init_eq_lock(wl);
5742 INIT_LIST_HEAD(&wl->eq_list);
5743}
5744
5745static void wl_flush_eq(struct wl_priv *wl)
5746{
5747 struct wl_event_q *e;
5748 unsigned long flags;
5749
5750 flags = wl_lock_eq(wl);
5751 while (!list_empty(&wl->eq_list)) {
5752 e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list);
5753 list_del(&e->eq_list);
5754 kfree(e);
5755 }
5756 wl_unlock_eq(wl, flags);
5757}
5758
5759/*
5760* retrieve first queued event from head
5761*/
5762
5763static struct wl_event_q *wl_deq_event(struct wl_priv *wl)
5764{
5765 struct wl_event_q *e = NULL;
5766 unsigned long flags;
5767
5768 flags = wl_lock_eq(wl);
5769 if (likely(!list_empty(&wl->eq_list))) {
5770 e = list_first_entry(&wl->eq_list, struct wl_event_q, eq_list);
5771 list_del(&e->eq_list);
5772 }
5773 wl_unlock_eq(wl, flags);
5774
5775 return e;
5776}
5777
5778/*
5779 * push event to tail of the queue
5780 */
5781
5782static s32
5783wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 event, const wl_event_msg_t *msg,
5784 void *data)
5785{
5786 struct wl_event_q *e;
5787 s32 err = 0;
5788 uint32 evtq_size;
5789 uint32 data_len;
5790 unsigned long flags;
5791 gfp_t aflags;
5792
5793 data_len = 0;
5794 if (data)
5795 data_len = ntoh32(msg->datalen);
5796 evtq_size = sizeof(struct wl_event_q) + data_len;
5797 aflags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
5798 e = kzalloc(evtq_size, aflags);
5799 if (unlikely(!e)) {
5800 WL_ERR(("event alloc failed\n"));
5801 return -ENOMEM;
5802 }
5803 e->etype = event;
5804 memcpy(&e->emsg, msg, sizeof(wl_event_msg_t));
5805 if (data)
5806 memcpy(e->edata, data, data_len);
5807 flags = wl_lock_eq(wl);
5808 list_add_tail(&e->eq_list, &wl->eq_list);
5809 wl_unlock_eq(wl, flags);
5810
5811 return err;
5812}
5813
5814static void wl_put_event(struct wl_event_q *e)
5815{
5816 kfree(e);
5817}
5818
5819void wl_cfg80211_set_sdio_func(void *func)
5820{
5821 cfg80211_sdio_func = (struct sdio_func *)func;
5822}
5823
5824static void wl_clear_sdio_func(void)
5825{
5826 cfg80211_sdio_func = NULL;
5827}
5828
5829struct sdio_func *wl_cfg80211_get_sdio_func(void)
5830{
5831 return cfg80211_sdio_func;
5832}
5833
5834static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype)
5835{
5836 s32 infra = 0;
5837 s32 err = 0;
5838 s32 mode = 0;
5839 switch (iftype) {
5840 case NL80211_IFTYPE_MONITOR:
5841 case NL80211_IFTYPE_WDS:
5842 WL_ERR(("type (%d) : currently we do not support this mode\n",
5843 iftype));
5844 err = -EINVAL;
5845 return err;
5846 case NL80211_IFTYPE_ADHOC:
5847 mode = WL_MODE_IBSS;
5848 break;
5849 case NL80211_IFTYPE_STATION:
5850 case NL80211_IFTYPE_P2P_CLIENT:
5851 mode = WL_MODE_BSS;
5852 infra = 1;
5853 break;
5854 case NL80211_IFTYPE_AP:
5855 case NL80211_IFTYPE_P2P_GO:
5856 mode = WL_MODE_AP;
5857 infra = 1;
5858 break;
5859 default:
5860 err = -EINVAL;
5861 WL_ERR(("invalid type (%d)\n", iftype));
5862 return err;
5863 }
5864 infra = htod32(infra);
5865 err = wldev_ioctl(ndev, WLC_SET_INFRA, &infra, sizeof(infra), true);
5866 if (unlikely(err)) {
5867 WL_ERR(("WLC_SET_INFRA error (%d)\n", err));
5868 return err;
5869 }
5870
5871 set_mode_by_netdev(wl, ndev, mode);
5872
5873 return 0;
5874}
5875static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add)
5876{
5877 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
5878
5879 s8 eventmask[WL_EVENTING_MASK_LEN];
5880 s32 err = 0;
5881
5882 /* Setup event_msgs */
5883 bcm_mkiovar("event_msgs", NULL, 0, iovbuf,
5884 sizeof(iovbuf));
5885 err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false);
5886 if (unlikely(err)) {
5887 WL_ERR(("Get event_msgs error (%d)\n", err));
5888 goto dongle_eventmsg_out;
5889 }
5890 memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN);
5891 if (add) {
5892 setbit(eventmask, event);
5893 } else {
5894 clrbit(eventmask, event);
5895 }
5896 bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf,
5897 sizeof(iovbuf));
5898 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
5899 if (unlikely(err)) {
5900 WL_ERR(("Set event_msgs error (%d)\n", err));
5901 goto dongle_eventmsg_out;
5902 }
5903
5904dongle_eventmsg_out:
5905 return err;
5906
5907}
5908
5909
5910#ifndef EMBEDDED_PLATFORM
5911static s32 wl_dongle_country(struct net_device *ndev, u8 ccode)
5912{
5913
5914 s32 err = 0;
5915
5916 return err;
5917}
5918
5919static s32 wl_dongle_up(struct net_device *ndev, u32 up)
5920{
5921 s32 err = 0;
5922
5923 err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true);
5924 if (unlikely(err)) {
5925 WL_ERR(("WLC_UP error (%d)\n", err));
5926 }
5927 return err;
5928}
5929
5930static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode)
5931{
5932 s32 err = 0;
5933
5934 WL_TRACE(("In\n"));
5935 err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), true);
5936 if (unlikely(err)) {
5937 WL_ERR(("WLC_SET_PM error (%d)\n", err));
5938 }
5939 return err;
5940}
5941
5942static s32
5943wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align)
5944{
5945 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
5946
5947 s32 err = 0;
5948
5949 /* Match Host and Dongle rx alignment */
5950 bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
5951 sizeof(iovbuf));
5952 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
5953 if (unlikely(err)) {
5954 WL_ERR(("txglomalign error (%d)\n", err));
5955 goto dongle_glom_out;
5956 }
5957 /* disable glom option per default */
5958 bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
5959 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
5960 if (unlikely(err)) {
5961 WL_ERR(("txglom error (%d)\n", err));
5962 goto dongle_glom_out;
5963 }
5964dongle_glom_out:
5965 return err;
5966}
5967
5968static s32
5969wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
5970{
5971 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
5972
5973 s32 err = 0;
5974
5975 /* Setup timeout if Beacons are lost and roam is off to report link down */
5976 if (roamvar) {
5977 bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
5978 sizeof(iovbuf));
5979 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
5980 if (unlikely(err)) {
5981 WL_ERR(("bcn_timeout error (%d)\n", err));
5982 goto dongle_rom_out;
5983 }
5984 }
5985 /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */
5986 bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
5987 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
5988 if (unlikely(err)) {
5989 WL_ERR(("roam_off error (%d)\n", err));
5990 goto dongle_rom_out;
5991 }
5992dongle_rom_out:
5993 return err;
5994}
5995
5996static s32
5997wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time,
5998 s32 scan_unassoc_time)
5999{
6000 s32 err = 0;
6001
6002 err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time,
6003 sizeof(scan_assoc_time), true);
6004 if (err) {
6005 if (err == -EOPNOTSUPP) {
6006 WL_INFO(("Scan assoc time is not supported\n"));
6007 } else {
6008 WL_ERR(("Scan assoc time error (%d)\n", err));
6009 }
6010 goto dongle_scantime_out;
6011 }
6012 err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time,
6013 sizeof(scan_unassoc_time), true);
6014 if (err) {
6015 if (err == -EOPNOTSUPP) {
6016 WL_INFO(("Scan unassoc time is not supported\n"));
6017 } else {
6018 WL_ERR(("Scan unassoc time error (%d)\n", err));
6019 }
6020 goto dongle_scantime_out;
6021 }
6022
6023dongle_scantime_out:
6024 return err;
6025}
6026
6027static s32
6028wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol)
6029{
6030 /* Room for "event_msgs" + '\0' + bitvec */
6031 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
6032
6033 s32 err = 0;
6034
6035 /* Set ARP offload */
6036 bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf));
6037 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
6038 if (err) {
6039 if (err == -EOPNOTSUPP)
6040 WL_INFO(("arpoe is not supported\n"));
6041 else
6042 WL_ERR(("arpoe error (%d)\n", err));
6043
6044 goto dongle_offload_out;
6045 }
6046 bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf));
6047 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
6048 if (err) {
6049 if (err == -EOPNOTSUPP)
6050 WL_INFO(("arp_ol is not supported\n"));
6051 else
6052 WL_ERR(("arp_ol error (%d)\n", err));
6053
6054 goto dongle_offload_out;
6055 }
6056
6057dongle_offload_out:
6058 return err;
6059}
6060
6061static s32 wl_pattern_atoh(s8 *src, s8 *dst)
6062{
6063 int i;
6064 if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
6065 WL_ERR(("Mask invalid format. Needs to start with 0x\n"));
6066 return -1;
6067 }
6068 src = src + 2; /* Skip past 0x */
6069 if (strlen(src) % 2 != 0) {
6070 WL_ERR(("Mask invalid format. Needs to be of even length\n"));
6071 return -1;
6072 }
6073 for (i = 0; *src != '\0'; i++) {
6074 char num[3];
6075 strncpy(num, src, 2);
6076 num[2] = '\0';
6077 dst[i] = (u8) simple_strtoul(num, NULL, 16);
6078 src += 2;
6079 }
6080 return i;
6081}
6082
6083static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode)
6084{
6085 /* Room for "event_msgs" + '\0' + bitvec */
6086 s8 iovbuf[WL_EVENTING_MASK_LEN + 12];
6087
6088 const s8 *str;
6089 struct wl_pkt_filter pkt_filter;
6090 struct wl_pkt_filter *pkt_filterp;
6091 s32 buf_len;
6092 s32 str_len;
6093 u32 mask_size;
6094 u32 pattern_size;
6095 s8 buf[256];
6096 s32 err = 0;
6097
6098 /* add a default packet filter pattern */
6099 str = "pkt_filter_add";
6100 str_len = strlen(str);
6101 strncpy(buf, str, str_len);
6102 buf[str_len] = '\0';
6103 buf_len = str_len + 1;
6104
6105 pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1);
6106
6107 /* Parse packet filter id. */
6108 pkt_filter.id = htod32(100);
6109
6110 /* Parse filter polarity. */
6111 pkt_filter.negate_match = htod32(0);
6112
6113 /* Parse filter type. */
6114 pkt_filter.type = htod32(0);
6115
6116 /* Parse pattern filter offset. */
6117 pkt_filter.u.pattern.offset = htod32(0);
6118
6119 /* Parse pattern filter mask. */
6120 mask_size = htod32(wl_pattern_atoh("0xff",
6121 (char *)pkt_filterp->u.pattern.
6122 mask_and_pattern));
6123
6124 /* Parse pattern filter pattern. */
6125 pattern_size = htod32(wl_pattern_atoh("0x00",
6126 (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
6127
6128 if (mask_size != pattern_size) {
6129 WL_ERR(("Mask and pattern not the same size\n"));
6130 err = -EINVAL;
6131 goto dongle_filter_out;
6132 }
6133
6134 pkt_filter.u.pattern.size_bytes = mask_size;
6135 buf_len += WL_PKT_FILTER_FIXED_LEN;
6136 buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
6137
6138 /* Keep-alive attributes are set in local
6139 * variable (keep_alive_pkt), and
6140 * then memcpy'ed into buffer (keep_alive_pktp) since there is no
6141 * guarantee that the buffer is properly aligned.
6142 */
6143 memcpy((char *)pkt_filterp, &pkt_filter,
6144 WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
6145
6146 err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true);
6147 if (err) {
6148 if (err == -EOPNOTSUPP) {
6149 WL_INFO(("filter not supported\n"));
6150 } else {
6151 WL_ERR(("filter (%d)\n", err));
6152 }
6153 goto dongle_filter_out;
6154 }
6155
6156 /* set mode to allow pattern */
6157 bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf,
6158 sizeof(iovbuf));
6159 err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true);
6160 if (err) {
6161 if (err == -EOPNOTSUPP) {
6162 WL_INFO(("filter_mode not supported\n"));
6163 } else {
6164 WL_ERR(("filter_mode (%d)\n", err));
6165 }
6166 goto dongle_filter_out;
6167 }
6168
6169dongle_filter_out:
6170 return err;
6171}
6172#endif /* !EMBEDDED_PLATFORM */
6173
6174s32 wl_config_dongle(struct wl_priv *wl, bool need_lock)
6175{
6176#ifndef DHD_SDALIGN
6177#define DHD_SDALIGN 32
6178#endif
6179 struct net_device *ndev;
6180 struct wireless_dev *wdev;
6181 s32 err = 0;
6182
6183 WL_TRACE(("In\n"));
6184 if (wl->dongle_up) {
6185 WL_ERR(("Dongle is already up\n"));
6186 return err;
6187 }
6188
6189 ndev = wl_to_prmry_ndev(wl);
6190 wdev = ndev->ieee80211_ptr;
6191 if (need_lock)
6192 rtnl_lock();
6193#ifndef EMBEDDED_PLATFORM
6194 err = wl_dongle_up(ndev, 0);
6195 if (unlikely(err)) {
6196 WL_ERR(("wl_dongle_up failed\n"));
6197 goto default_conf_out;
6198 }
6199 err = wl_dongle_country(ndev, 0);
6200 if (unlikely(err)) {
6201 WL_ERR(("wl_dongle_country failed\n"));
6202 goto default_conf_out;
6203 }
6204 err = wl_dongle_power(ndev, PM_FAST);
6205 if (unlikely(err)) {
6206 WL_ERR(("wl_dongle_power failed\n"));
6207 goto default_conf_out;
6208 }
6209 err = wl_dongle_glom(ndev, 0, DHD_SDALIGN);
6210 if (unlikely(err)) {
6211 WL_ERR(("wl_dongle_glom failed\n"));
6212 goto default_conf_out;
6213 }
6214 err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3);
6215 if (unlikely(err)) {
6216 WL_ERR(("wl_dongle_roam failed\n"));
6217 goto default_conf_out;
6218 }
6219 wl_dongle_scantime(ndev, 40, 80);
6220 wl_dongle_offload(ndev, 1, 0xf);
6221 wl_dongle_filter(ndev, 1);
6222#endif /* !EMBEDDED_PLATFORM */
6223
6224 err = wl_dongle_mode(wl, ndev, wdev->iftype);
6225 if (unlikely(err && err != -EINPROGRESS)) {
6226 WL_ERR(("wl_dongle_mode failed\n"));
6227 goto default_conf_out;
6228 }
6229 err = wl_dongle_probecap(wl);
6230 if (unlikely(err)) {
6231 WL_ERR(("wl_dongle_probecap failed\n"));
6232 goto default_conf_out;
6233 }
6234
6235 /* -EINPROGRESS: Call commit handler */
6236
6237default_conf_out:
6238 if (need_lock)
6239 rtnl_unlock();
6240
6241 wl->dongle_up = true;
6242
6243 return err;
6244
6245}
6246
6247static s32 wl_update_wiphybands(struct wl_priv *wl)
6248{
6249 struct wiphy *wiphy;
6250 s8 phylist_buf[128];
6251 s8 *phy;
6252 s32 err = 0;
6253
6254 err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, phylist_buf,
6255 sizeof(phylist_buf), false);
6256 if (unlikely(err)) {
6257 WL_ERR(("error (%d)\n", err));
6258 return err;
6259 }
6260 phy = phylist_buf;
6261 for (; *phy; phy++) {
6262 if (*phy == 'a' || *phy == 'n') {
6263 wiphy = wl_to_wiphy(wl);
6264 wiphy->bands[IEEE80211_BAND_5GHZ] =
6265 &__wl_band_5ghz_a;
6266 }
6267 }
6268 return err;
6269}
6270
6271static s32 __wl_cfg80211_up(struct wl_priv *wl)
6272{
6273 s32 err = 0;
6274
6275 WL_TRACE(("In\n"));
6276 wl_debugfs_add_netdev_params(wl);
6277
6278 err = wl_config_dongle(wl, false);
6279 if (unlikely(err))
6280 return err;
6281 dhd_monitor_init(wl->pub);
6282 wl_invoke_iscan(wl);
6283 wl_set_drv_status(wl, READY);
6284 return err;
6285}
6286
6287static s32 __wl_cfg80211_down(struct wl_priv *wl)
6288{
6289 s32 err = 0;
6290 unsigned long flags;
6291
6292 WL_TRACE(("In\n"));
6293 /* Check if cfg80211 interface is already down */
6294 if (!wl_get_drv_status(wl, READY))
6295 return err; /* it is even not ready */
6296
6297 wl_set_drv_status(wl, SCAN_ABORTING);
6298
6299 wl_term_iscan(wl);
6300 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
6301 if (wl->scan_request) {
6302 cfg80211_scan_done(wl->scan_request, true);
6303 wl->scan_request = NULL;
6304 }
6305 wl_clr_drv_status(wl, READY);
6306 wl_clr_drv_status(wl, SCANNING);
6307 wl_clr_drv_status(wl, SCAN_ABORTING);
6308 wl_clr_drv_status(wl, CONNECTING);
6309 wl_clr_drv_status(wl, CONNECTED);
6310 wl_clr_drv_status(wl, DISCONNECTING);
6311 if (wl_get_drv_status(wl, AP_CREATED)) {
6312 wl_clr_drv_status(wl, AP_CREATED);
6313 wl_clr_drv_status(wl, AP_CREATING);
6314 }
6315 wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype =
6316 NL80211_IFTYPE_STATION;
6317 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
6318
6319 wl->dongle_up = false;
6320 wl_flush_eq(wl);
6321 wl_link_down(wl);
6322 if (wl->p2p_supported)
6323 wl_cfgp2p_down(wl);
6324 dhd_monitor_uninit();
6325
6326 wl_debugfs_remove_netdev(wl);
6327
6328 return err;
6329}
6330
6331s32 wl_cfg80211_up(void)
6332{
6333 struct wl_priv *wl;
6334 s32 err = 0;
6335
6336 WL_TRACE(("In\n"));
6337 wl = wlcfg_drv_priv;
6338 mutex_lock(&wl->usr_sync);
6339 wl_cfg80211_attach_post(wl_to_prmry_ndev(wl));
6340 err = __wl_cfg80211_up(wl);
6341 if (err)
6342 WL_ERR(("__wl_cfg80211_up failed\n"));
6343 mutex_unlock(&wl->usr_sync);
6344
6345 return err;
6346}
6347
6348/* Private Event to Supplicant with indication that FW hangs */
6349int wl_cfg80211_hang(struct net_device *dev, u16 reason)
6350{
6351 struct wl_priv *wl;
6352 wl = wlcfg_drv_priv;
6353
6354 WL_ERR(("In : FW crash Eventing\n"));
6355 cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL);
6356 if (wl != NULL) {
6357 wl_link_down(wl);
6358 }
6359 return 0;
6360}
6361
6362s32 wl_cfg80211_down(void)
6363{
6364 struct wl_priv *wl;
6365 s32 err = 0;
6366
6367 WL_TRACE(("In\n"));
6368 wl = wlcfg_drv_priv;
6369 mutex_lock(&wl->usr_sync);
6370 err = __wl_cfg80211_down(wl);
6371 mutex_unlock(&wl->usr_sync);
6372
6373 return err;
6374}
6375
6376static s32 wl_dongle_probecap(struct wl_priv *wl)
6377{
6378 s32 err = 0;
6379
6380 err = wl_update_wiphybands(wl);
6381 if (unlikely(err))
6382 return err;
6383
6384 return err;
6385}
6386
6387static void *wl_read_prof(struct wl_priv *wl, s32 item)
6388{
6389 unsigned long flags;
6390 void *rptr = NULL;
6391
6392 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
6393 switch (item) {
6394 case WL_PROF_SEC:
6395 rptr = &wl->profile->sec;
6396 break;
6397 case WL_PROF_ACT:
6398 rptr = &wl->profile->active;
6399 break;
6400 case WL_PROF_BSSID:
6401 rptr = &wl->profile->bssid;
6402 break;
6403 case WL_PROF_SSID:
6404 rptr = &wl->profile->ssid;
6405 break;
6406 }
6407 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
6408 if (!rptr)
6409 WL_ERR(("invalid item (%d)\n", item));
6410 return rptr;
6411}
6412
6413static s32
6414wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data,
6415 s32 item)
6416{
6417 s32 err = 0;
6418 struct wlc_ssid *ssid;
6419 unsigned long flags;
6420
6421 flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub));
6422 switch (item) {
6423 case WL_PROF_SSID:
6424 ssid = (wlc_ssid_t *) data;
6425 memset(wl->profile->ssid.SSID, 0,
6426 sizeof(wl->profile->ssid.SSID));
6427 memcpy(wl->profile->ssid.SSID, ssid->SSID, ssid->SSID_len);
6428 wl->profile->ssid.SSID_len = ssid->SSID_len;
6429 break;
6430 case WL_PROF_BSSID:
6431 if (data)
6432 memcpy(wl->profile->bssid, data, ETHER_ADDR_LEN);
6433 else
6434 memset(wl->profile->bssid, 0, ETHER_ADDR_LEN);
6435 break;
6436 case WL_PROF_SEC:
6437 memcpy(&wl->profile->sec, data, sizeof(wl->profile->sec));
6438 break;
6439 case WL_PROF_ACT:
6440 wl->profile->active = *(bool *)data;
6441 break;
6442 case WL_PROF_BEACONINT:
6443 wl->profile->beacon_interval = *(u16 *)data;
6444 break;
6445 case WL_PROF_DTIMPERIOD:
6446 wl->profile->dtim_period = *(u8 *)data;
6447 break;
6448 default:
6449 WL_ERR(("unsupported item (%d)\n", item));
6450 err = -EOPNOTSUPP;
6451 break;
6452 }
6453 dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags);
6454 return err;
6455}
6456
6457void wl_cfg80211_dbg_level(u32 level)
6458{
6459 /*
6460 * prohibit to change debug level
6461 * by insmod parameter.
6462 * eventually debug level will be configured
6463 * in compile time by using CONFIG_XXX
6464 */
6465 /* wl_dbg_level = level; */
6466}
6467
6468static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev)
6469{
6470 return get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS;
6471}
6472
6473static __used bool wl_is_ibssstarter(struct wl_priv *wl)
6474{
6475 return wl->ibss_starter;
6476}
6477
6478static void wl_rst_ie(struct wl_priv *wl)
6479{
6480 struct wl_ie *ie = wl_to_ie(wl);
6481
6482 ie->offset = 0;
6483}
6484
6485static __used s32 wl_add_ie(struct wl_priv *wl, u8 t, u8 l, u8 *v)
6486{
6487 struct wl_ie *ie = wl_to_ie(wl);
6488 s32 err = 0;
6489
6490 if (unlikely(ie->offset + l + 2 > WL_TLV_INFO_MAX)) {
6491 WL_ERR(("ei crosses buffer boundary\n"));
6492 return -ENOSPC;
6493 }
6494 ie->buf[ie->offset] = t;
6495 ie->buf[ie->offset + 1] = l;
6496 memcpy(&ie->buf[ie->offset + 2], v, l);
6497 ie->offset += l + 2;
6498
6499 return err;
6500}
6501
6502static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size)
6503{
6504 struct wl_ie *ie = wl_to_ie(wl);
6505 s32 err = 0;
6506
6507 if (unlikely(ie->offset + ie_size > WL_TLV_INFO_MAX)) {
6508 WL_ERR(("ei_stream crosses buffer boundary\n"));
6509 return -ENOSPC;
6510 }
6511 memcpy(&ie->buf[ie->offset], ie_stream, ie_size);
6512 ie->offset += ie_size;
6513
6514 return err;
6515}
6516
6517static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size)
6518{
6519 struct wl_ie *ie = wl_to_ie(wl);
6520 s32 err = 0;
6521
6522 if (unlikely(ie->offset > dst_size)) {
6523 WL_ERR(("dst_size is not enough\n"));
6524 return -ENOSPC;
6525 }
6526 memcpy(dst, &ie->buf[0], ie->offset);
6527
6528 return err;
6529}
6530
6531static u32 wl_get_ielen(struct wl_priv *wl)
6532{
6533 struct wl_ie *ie = wl_to_ie(wl);
6534
6535 return ie->offset;
6536}
6537
6538static void wl_link_up(struct wl_priv *wl)
6539{
6540 wl->link_up = true;
6541}
6542
6543static void wl_link_down(struct wl_priv *wl)
6544{
6545 struct wl_connect_info *conn_info = wl_to_conn(wl);
6546
6547 WL_DBG(("In\n"));
6548 wl->link_up = false;
6549 conn_info->req_ie_len = 0;
6550 conn_info->resp_ie_len = 0;
6551}
6552
6553static unsigned long wl_lock_eq(struct wl_priv *wl)
6554{
6555 unsigned long flags;
6556
6557 spin_lock_irqsave(&wl->eq_lock, flags);
6558 return flags;
6559}
6560
6561static void wl_unlock_eq(struct wl_priv *wl, unsigned long flags)
6562{
6563 spin_unlock_irqrestore(&wl->eq_lock, flags);
6564}
6565
6566static void wl_init_eq_lock(struct wl_priv *wl)
6567{
6568 spin_lock_init(&wl->eq_lock);
6569}
6570
6571static void wl_delay(u32 ms)
6572{
6573 if (ms < 1000 / HZ) {
6574 cond_resched();
6575 mdelay(ms);
6576 } else {
6577 msleep(ms);
6578 }
6579}
6580
6581s32 wl_cfg80211_read_fw(s8 *buf, u32 size)
6582{
6583 const struct firmware *fw_entry;
6584 struct wl_priv *wl;
6585
6586 wl = wlcfg_drv_priv;
6587
6588 fw_entry = wl->fw->fw_entry;
6589
6590 if (fw_entry->size < wl->fw->ptr + size)
6591 size = fw_entry->size - wl->fw->ptr;
6592
6593 memcpy(buf, &fw_entry->data[wl->fw->ptr], size);
6594 wl->fw->ptr += size;
6595 return size;
6596}
6597
6598void wl_cfg80211_release_fw(void)
6599{
6600 struct wl_priv *wl;
6601
6602 wl = wlcfg_drv_priv;
6603 release_firmware(wl->fw->fw_entry);
6604 wl->fw->ptr = 0;
6605}
6606
6607void *wl_cfg80211_request_fw(s8 *file_name)
6608{
6609 struct wl_priv *wl;
6610 const struct firmware *fw_entry = NULL;
6611 s32 err = 0;
6612
6613 WL_TRACE(("In\n"));
6614 WL_DBG(("file name : \"%s\"\n", file_name));
6615 wl = wlcfg_drv_priv;
6616
6617 if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) {
6618 err = request_firmware(&wl->fw->fw_entry, file_name,
6619 &wl_cfg80211_get_sdio_func()->dev);
6620 if (unlikely(err)) {
6621 WL_ERR(("Could not download fw (%d)\n", err));
6622 goto req_fw_out;
6623 }
6624 set_bit(WL_FW_LOADING_DONE, &wl->fw->status);
6625 fw_entry = wl->fw->fw_entry;
6626 if (fw_entry) {
6627 WL_DBG(("fw size (%zd), data (%p)\n", fw_entry->size,
6628 fw_entry->data));
6629 }
6630 } else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) {
6631 err = request_firmware(&wl->fw->fw_entry, file_name,
6632 &wl_cfg80211_get_sdio_func()->dev);
6633 if (unlikely(err)) {
6634 WL_ERR(("Could not download nvram (%d)\n", err));
6635 goto req_fw_out;
6636 }
6637 set_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status);
6638 fw_entry = wl->fw->fw_entry;
6639 if (fw_entry) {
6640 WL_DBG(("nvram size (%zd), data (%p)\n", fw_entry->size,
6641 fw_entry->data));
6642 }
6643 } else {
6644 WL_DBG(("Downloading already done. Nothing to do more\n"));
6645 err = -EPERM;
6646 }
6647
6648req_fw_out:
6649 if (unlikely(err)) {
6650 return NULL;
6651 }
6652 wl->fw->ptr = 0;
6653 return (void *)fw_entry->data;
6654}
6655
6656s8 *wl_cfg80211_get_fwname(void)
6657{
6658 struct wl_priv *wl;
6659
6660 wl = wlcfg_drv_priv;
6661 strcpy(wl->fw->fw_name, WL_4329_FW_FILE);
6662 return wl->fw->fw_name;
6663}
6664
6665s8 *wl_cfg80211_get_nvramname(void)
6666{
6667 struct wl_priv *wl;
6668
6669 wl = wlcfg_drv_priv;
6670 strcpy(wl->fw->nvram_name, WL_4329_NVRAM_FILE);
6671 return wl->fw->nvram_name;
6672}
6673
6674s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
6675{
6676 struct wl_priv *wl;
6677 dhd_pub_t *dhd_pub;
6678 struct ether_addr p2pif_addr;
6679
6680 wl = wlcfg_drv_priv;
6681 dhd_pub = (dhd_pub_t *)wl->pub;
6682 wl_cfgp2p_generate_bss_mac(&dhd_pub->mac, p2pdev_addr, &p2pif_addr);
6683
6684 return 0;
6685}
6686s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
6687{
6688 struct wl_priv *wl;
6689 wl = wlcfg_drv_priv;
6690
6691 return wl_cfgp2p_set_p2p_noa(wl, net, buf, len);
6692}
6693
6694s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
6695{
6696 struct wl_priv *wl;
6697 wl = wlcfg_drv_priv;
6698
6699 return wl_cfgp2p_get_p2p_noa(wl, net, buf, len);
6700}
6701
6702s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
6703{
6704 struct wl_priv *wl;
6705 wl = wlcfg_drv_priv;
6706
6707 return wl_cfgp2p_set_p2p_ps(wl, net, buf, len);
6708}
6709
6710s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
6711 enum wl_management_type type)
6712{
6713 struct wl_priv *wl;
6714 struct net_device *ndev = NULL;
6715 s32 ret = 0;
6716 s32 bssidx = 0;
6717 s32 pktflag = 0;
6718 wl = wlcfg_drv_priv;
6719 if (wl->p2p && wl->p2p->vif_created) {
6720 ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
6721 bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION);
6722 } else if (wl_get_drv_status(wl, AP_CREATING) ||
6723 wl_get_drv_status(wl, AP_CREATED)) {
6724 ndev = net;
6725 bssidx = 0;
6726 }
6727 if (ndev != NULL) {
6728 switch (type) {
6729 case WL_BEACON:
6730 pktflag = VNDR_IE_BEACON_FLAG;
6731 break;
6732 case WL_PROBE_RESP:
6733 pktflag = VNDR_IE_PRBRSP_FLAG;
6734 break;
6735 case WL_ASSOC_RESP:
6736 pktflag = VNDR_IE_ASSOCRSP_FLAG;
6737 break;
6738 }
6739 if (pktflag)
6740 ret = wl_cfgp2p_set_management_ie(wl, ndev, bssidx, pktflag, buf, len);
6741 }
6742
6743 return ret;
6744}
6745
6746static __used void wl_dongle_poweron(struct wl_priv *wl)
6747{
6748 WL_DBG(("Enter \n"));
6749 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
6750
6751#if defined(BCMLXSDMMC)
6752 sdioh_start(NULL, 0);
6753#endif
6754#if defined(BCMLXSDMMC)
6755 sdioh_start(NULL, 1);
6756#endif
6757 wl_cfg80211_resume(wl_to_wiphy(wl));
6758}
6759
6760static __used void wl_dongle_poweroff(struct wl_priv *wl)
6761{
6762 WL_DBG(("Enter \n"));
6763#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)
6764 wl_cfg80211_suspend(wl_to_wiphy(wl), NULL);
6765#else
6766 wl_cfg80211_suspend(wl_to_wiphy(wl));
6767#endif
6768
6769#if defined(BCMLXSDMMC)
6770 sdioh_stop(NULL);
6771#endif
6772 /* clean up dtim_skip setting */
6773 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
6774}
6775
6776static int wl_debugfs_add_netdev_params(struct wl_priv *wl)
6777{
6778 char buf[10+IFNAMSIZ];
6779 struct dentry *fd;
6780 s32 err = 0;
6781
6782 WL_TRACE(("In\n"));
6783 sprintf(buf, "netdev:%s", wl_to_prmry_ndev(wl)->name);
6784 wl->debugfsdir = debugfs_create_dir(buf, wl_to_wiphy(wl)->debugfsdir);
6785
6786 fd = debugfs_create_u16("beacon_int", S_IRUGO, wl->debugfsdir,
6787 (u16 *)&wl->profile->beacon_interval);
6788 if (!fd) {
6789 err = -ENOMEM;
6790 goto err_out;
6791 }
6792
6793 fd = debugfs_create_u8("dtim_period", S_IRUGO, wl->debugfsdir,
6794 (u8 *)&wl->profile->dtim_period);
6795 if (!fd) {
6796 err = -ENOMEM;
6797 goto err_out;
6798 }
6799
6800err_out:
6801 return err;
6802}
6803
6804static void wl_debugfs_remove_netdev(struct wl_priv *wl)
6805{
6806 WL_DBG(("Enter \n"));
6807}
6808
6809static const struct rfkill_ops wl_rfkill_ops = {
6810 .set_block = wl_rfkill_set
6811};
6812
6813static int wl_rfkill_set(void *data, bool blocked)
6814{
6815 struct wl_priv *wl = (struct wl_priv *)data;
6816
6817 WL_DBG(("Enter \n"));
6818 WL_DBG(("RF %s\n", blocked ? "blocked" : "unblocked"));
6819
6820 if (!wl)
6821 return -EINVAL;
6822
6823 wl->rf_blocked = blocked;
6824
6825 return 0;
6826}
6827
6828static int wl_setup_rfkill(struct wl_priv *wl, bool setup)
6829{
6830 s32 err = 0;
6831
6832 WL_DBG(("Enter \n"));
6833 if (!wl)
6834 return -EINVAL;
6835 if (setup) {
6836 wl->rfkill = rfkill_alloc("brcmfmac-wifi",
6837 &wl_cfg80211_get_sdio_func()->dev,
6838 RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl);
6839
6840 if (!wl->rfkill) {
6841 err = -ENOMEM;
6842 goto err_out;
6843 }
6844
6845 err = rfkill_register(wl->rfkill);
6846
6847 if (err)
6848 rfkill_destroy(wl->rfkill);
6849 } else {
6850 if (!wl->rfkill) {
6851 err = -ENOMEM;
6852 goto err_out;
6853 }
6854
6855 rfkill_unregister(wl->rfkill);
6856 rfkill_destroy(wl->rfkill);
6857 }
6858
6859err_out:
6860 return err;
6861}
6862
6863#if defined(COEX_DHCP)
6864/*
6865 * get named driver variable to uint register value and return error indication
6866 * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, &reg_value)
6867 */
6868static int
6869dev_wlc_intvar_get_reg(struct net_device *dev, char *name,
6870 uint reg, int *retval)
6871{
6872 union {
6873 char buf[WLC_IOCTL_SMLEN];
6874 int val;
6875 } var;
6876 int error;
6877
6878 bcm_mkiovar(name, (char *)(&reg), sizeof(reg),
6879 (char *)(&var), sizeof(var.buf));
6880 error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false);
6881
6882 *retval = dtoh32(var.val);
6883 return (error);
6884}
6885
6886static int
6887dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len)
6888{
6889#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
6890 char ioctlbuf[1024];
6891#else
6892 static char ioctlbuf[1024];
6893#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */
6894
6895 bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
6896
6897 return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf, sizeof(ioctlbuf), true));
6898}
6899/*
6900get named driver variable to uint register value and return error indication
6901calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value)
6902*/
6903static int
6904dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val)
6905{
6906 char reg_addr[8];
6907
6908 memset(reg_addr, 0, sizeof(reg_addr));
6909 memcpy((char *)&reg_addr[0], (char *)addr, 4);
6910 memcpy((char *)&reg_addr[4], (char *)val, 4);
6911
6912 return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
6913}
6914
6915static bool btcoex_is_sco_active(struct net_device *dev)
6916{
6917 int ioc_res = 0;
6918 bool res = FALSE;
6919 int sco_id_cnt = 0;
6920 int param27;
6921 int i;
6922
6923 for (i = 0; i < 12; i++) {
6924
6925 ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
6926
6927 WL_TRACE(("%s, sample[%d], btc params: 27:%x\n",
6928 __FUNCTION__, i, param27));
6929
6930 if (ioc_res < 0) {
6931 WL_ERR(("%s ioc read btc params error\n", __FUNCTION__));
6932 break;
6933 }
6934
6935 if ((param27 & 0x6) == 2) { /* count both sco & esco */
6936 sco_id_cnt++;
6937 }
6938
6939 if (sco_id_cnt > 2) {
6940 WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n",
6941 __FUNCTION__, sco_id_cnt, i));
6942 res = TRUE;
6943 break;
6944 }
6945
6946 msleep(5);
6947 }
6948
6949 return res;
6950}
6951
6952#if defined(BT_DHCP_eSCO_FIX)
6953/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */
6954static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
6955{
6956 static bool saved_status = FALSE;
6957
6958 char buf_reg50va_dhcp_on[8] =
6959 { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
6960 char buf_reg51va_dhcp_on[8] =
6961 { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
6962 char buf_reg64va_dhcp_on[8] =
6963 { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
6964 char buf_reg65va_dhcp_on[8] =
6965 { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
6966 char buf_reg71va_dhcp_on[8] =
6967 { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
6968 uint32 regaddr;
6969 static uint32 saved_reg50;
6970 static uint32 saved_reg51;
6971 static uint32 saved_reg64;
6972 static uint32 saved_reg65;
6973 static uint32 saved_reg71;
6974
6975 if (trump_sco) {
6976 /* this should reduce eSCO agressive retransmit
6977 * w/o breaking it
6978 */
6979
6980 /* 1st save current */
6981 WL_TRACE(("Do new SCO/eSCO coex algo {save &"
6982 "override}\n"));
6983 if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
6984 (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
6985 (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
6986 (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
6987 (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
6988 saved_status = TRUE;
6989 WL_TRACE(("%s saved bt_params[50,51,64,65,71]:"
6990 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
6991 __FUNCTION__, saved_reg50, saved_reg51,
6992 saved_reg64, saved_reg65, saved_reg71));
6993 } else {
6994 WL_ERR((":%s: save btc_params failed\n",
6995 __FUNCTION__));
6996 saved_status = FALSE;
6997 return -1;
6998 }
6999
7000 WL_TRACE(("override with [50,51,64,65,71]:"
7001 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
7002 *(u32 *)(buf_reg50va_dhcp_on+4),
7003 *(u32 *)(buf_reg51va_dhcp_on+4),
7004 *(u32 *)(buf_reg64va_dhcp_on+4),
7005 *(u32 *)(buf_reg65va_dhcp_on+4),
7006 *(u32 *)(buf_reg71va_dhcp_on+4)));
7007
7008 dev_wlc_bufvar_set(dev, "btc_params",
7009 (char *)&buf_reg50va_dhcp_on[0], 8);
7010 dev_wlc_bufvar_set(dev, "btc_params",
7011 (char *)&buf_reg51va_dhcp_on[0], 8);
7012 dev_wlc_bufvar_set(dev, "btc_params",
7013 (char *)&buf_reg64va_dhcp_on[0], 8);
7014 dev_wlc_bufvar_set(dev, "btc_params",
7015 (char *)&buf_reg65va_dhcp_on[0], 8);
7016 dev_wlc_bufvar_set(dev, "btc_params",
7017 (char *)&buf_reg71va_dhcp_on[0], 8);
7018
7019 saved_status = TRUE;
7020 } else if (saved_status) {
7021 /* restore previously saved bt params */
7022 WL_TRACE(("Do new SCO/eSCO coex algo {save &"
7023 "override}\n"));
7024
7025 regaddr = 50;
7026 dev_wlc_intvar_set_reg(dev, "btc_params",
7027 (char *)&regaddr, (char *)&saved_reg50);
7028 regaddr = 51;
7029 dev_wlc_intvar_set_reg(dev, "btc_params",
7030 (char *)&regaddr, (char *)&saved_reg51);
7031 regaddr = 64;
7032 dev_wlc_intvar_set_reg(dev, "btc_params",
7033 (char *)&regaddr, (char *)&saved_reg64);
7034 regaddr = 65;
7035 dev_wlc_intvar_set_reg(dev, "btc_params",
7036 (char *)&regaddr, (char *)&saved_reg65);
7037 regaddr = 71;
7038 dev_wlc_intvar_set_reg(dev, "btc_params",
7039 (char *)&regaddr, (char *)&saved_reg71);
7040
7041 WL_TRACE(("restore bt_params[50,51,64,65,71]:"
7042 "0x%x 0x%x 0x%x 0x%x 0x%x\n",
7043 saved_reg50, saved_reg51, saved_reg64,
7044 saved_reg65, saved_reg71));
7045
7046 saved_status = FALSE;
7047 } else {
7048 WL_ERR((":%s att to restore not saved BTCOEX params\n",
7049 __FUNCTION__));
7050 return -1;
7051 }
7052 return 0;
7053}
7054#endif /* BT_DHCP_eSCO_FIX */
7055
7056static void
7057wl_cfg80211_bt_setflag(struct net_device *dev, bool set)
7058{
7059#if defined(BT_DHCP_USE_FLAGS)
7060 char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
7061 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
7062#endif
7063
7064#if defined(BT_DHCP_eSCO_FIX)
7065 /* set = 1, save & turn on 0 - off & restore prev settings */
7066 set_btc_esco_params(dev, set);
7067#endif
7068
7069#if defined(BT_DHCP_USE_FLAGS)
7070 WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set));
7071 if (set == TRUE)
7072 /* Forcing bt_flag7 */
7073 dev_wlc_bufvar_set(dev, "btc_flags",
7074 (char *)&buf_flag7_dhcp_on[0],
7075 sizeof(buf_flag7_dhcp_on));
7076 else
7077 /* Restoring default bt flag7 */
7078 dev_wlc_bufvar_set(dev, "btc_flags",
7079 (char *)&buf_flag7_default[0],
7080 sizeof(buf_flag7_default));
7081#endif
7082}
7083
7084static void wl_cfg80211_bt_timerfunc(ulong data)
7085{
7086 struct btcoex_info *bt_local = (struct btcoex_info *)data;
7087 WL_TRACE(("%s\n", __FUNCTION__));
7088 bt_local->timer_on = 0;
7089 schedule_work(&bt_local->work);
7090}
7091
7092static void wl_cfg80211_bt_handler(struct work_struct *work)
7093{
7094 struct btcoex_info *btcx_inf;
7095
7096 btcx_inf = container_of(work, struct btcoex_info, work);
7097
7098 if (btcx_inf->timer_on) {
7099 btcx_inf->timer_on = 0;
7100 del_timer_sync(&btcx_inf->timer);
7101 }
7102
7103 switch (btcx_inf->bt_state) {
7104 case BT_DHCP_START:
7105 /* DHCP started
7106 * provide OPPORTUNITY window to get DHCP address
7107 */
7108 WL_TRACE(("%s bt_dhcp stm: started \n",
7109 __FUNCTION__));
7110 btcx_inf->bt_state = BT_DHCP_OPPR_WIN;
7111 mod_timer(&btcx_inf->timer,
7112 jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000);
7113 btcx_inf->timer_on = 1;
7114 break;
7115
7116 case BT_DHCP_OPPR_WIN:
7117 if (btcx_inf->dhcp_done) {
7118 WL_TRACE(("%s DHCP Done before T1 expiration\n",
7119 __FUNCTION__));
7120 goto btc_coex_idle;
7121 }
7122
7123 /* DHCP is not over yet, start lowering BT priority
7124 * enforce btc_params + flags if necessary
7125 */
7126 WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__,
7127 BT_DHCP_OPPR_WIN_TIME));
7128 if (btcx_inf->dev)
7129 wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE);
7130 btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
7131 mod_timer(&btcx_inf->timer,
7132 jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
7133 btcx_inf->timer_on = 1;
7134 break;
7135
7136 case BT_DHCP_FLAG_FORCE_TIMEOUT:
7137 if (btcx_inf->dhcp_done) {
7138 WL_TRACE(("%s DHCP Done before T2 expiration\n",
7139 __FUNCTION__));
7140 } else {
7141 /* Noo dhcp during T1+T2, restore BT priority */
7142 WL_TRACE(("%s DHCP wait interval T2:%d"
7143 "msec expired\n", __FUNCTION__,
7144 BT_DHCP_FLAG_FORCE_TIME));
7145 }
7146
7147 /* Restoring default bt priority */
7148 if (btcx_inf->dev)
7149 wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
7150btc_coex_idle:
7151 btcx_inf->bt_state = BT_DHCP_IDLE;
7152 btcx_inf->timer_on = 0;
7153 break;
7154
7155 default:
7156 WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__,
7157 btcx_inf->bt_state));
7158 if (btcx_inf->dev)
7159 wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE);
7160 btcx_inf->bt_state = BT_DHCP_IDLE;
7161 btcx_inf->timer_on = 0;
7162 break;
7163 }
7164
7165 net_os_wake_unlock(btcx_inf->dev);
7166}
7167
7168static int wl_cfg80211_btcoex_init(struct wl_priv *wl)
7169{
7170 struct btcoex_info *btco_inf = NULL;
7171
7172 btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL);
7173 if (!btco_inf)
7174 return -ENOMEM;
7175
7176 btco_inf->bt_state = BT_DHCP_IDLE;
7177 btco_inf->ts_dhcp_start = 0;
7178 btco_inf->ts_dhcp_ok = 0;
7179 /* Set up timer for BT */
7180 btco_inf->timer_ms = 10;
7181 init_timer(&btco_inf->timer);
7182 btco_inf->timer.data = (ulong)btco_inf;
7183 btco_inf->timer.function = wl_cfg80211_bt_timerfunc;
7184
7185 btco_inf->dev = wl->wdev->netdev;
7186
7187 INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler);
7188
7189 wl->btcoex_info = btco_inf;
7190 return 0;
7191}
7192
7193static void
7194wl_cfg80211_btcoex_deinit(struct wl_priv *wl)
7195{
7196 if (!wl->btcoex_info)
7197 return;
7198
7199 if (!wl->btcoex_info->timer_on) {
7200 wl->btcoex_info->timer_on = 0;
7201 del_timer_sync(&wl->btcoex_info->timer);
7202 }
7203
7204 cancel_work_sync(&wl->btcoex_info->work);
7205
7206 kfree(wl->btcoex_info);
7207 wl->btcoex_info = NULL;
7208}
7209#endif /* COEX_DHCP */
7210
7211int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command)
7212{
7213 char powermode_val = 0;
7214 char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
7215 char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
7216 char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
7217
7218 uint32 regaddr;
7219 static uint32 saved_reg66;
7220 static uint32 saved_reg41;
7221 static uint32 saved_reg68;
7222 static bool saved_status = FALSE;
7223
7224#ifdef COEX_DHCP
7225 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
7226 struct btcoex_info *btco_inf = wlcfg_drv_priv->btcoex_info;
7227#endif /* COEX_DHCP */
7228
7229 /* Figure out powermode 1 or o command */
7230 strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1);
7231
7232 if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
7233
7234 WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
7235
7236 /* Retrieve and saved orig regs value */
7237 if ((saved_status == FALSE) &&
7238 (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
7239 (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
7240 (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
7241 saved_status = TRUE;
7242 WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
7243 saved_reg66, saved_reg41, saved_reg68));
7244
7245 /* Disable PM mode during dhpc session */
7246
7247 /* Disable PM mode during dhpc session */
7248#ifdef COEX_DHCP
7249 /* Start BT timer only for SCO connection */
7250 if (btcoex_is_sco_active(dev)) {
7251 /* btc_params 66 */
7252 dev_wlc_bufvar_set(dev, "btc_params",
7253 (char *)&buf_reg66va_dhcp_on[0],
7254 sizeof(buf_reg66va_dhcp_on));
7255 /* btc_params 41 0x33 */
7256 dev_wlc_bufvar_set(dev, "btc_params",
7257 (char *)&buf_reg41va_dhcp_on[0],
7258 sizeof(buf_reg41va_dhcp_on));
7259 /* btc_params 68 0x190 */
7260 dev_wlc_bufvar_set(dev, "btc_params",
7261 (char *)&buf_reg68va_dhcp_on[0],
7262 sizeof(buf_reg68va_dhcp_on));
7263 saved_status = TRUE;
7264
7265 btco_inf->bt_state = BT_DHCP_START;
7266 btco_inf->timer_on = 1;
7267 mod_timer(&btco_inf->timer, btco_inf->timer.expires);
7268 WL_TRACE(("%s enable BT DHCP Timer\n",
7269 __FUNCTION__));
7270 }
7271#endif /* COEX_DHCP */
7272 }
7273 else if (saved_status == TRUE) {
7274 WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
7275 }
7276 }
7277 else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
7278
7279
7280 /* Restoring PM mode */
7281
7282#ifdef COEX_DHCP
7283 /* Stop any bt timer because DHCP session is done */
7284 WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
7285 if (btco_inf->timer_on) {
7286 btco_inf->timer_on = 0;
7287 del_timer_sync(&btco_inf->timer);
7288
7289 if (btco_inf->bt_state != BT_DHCP_IDLE) {
7290 /* need to restore original btc flags & extra btc params */
7291 WL_TRACE(("%s bt->bt_state:%d\n",
7292 __FUNCTION__, btco_inf->bt_state));
7293 /* wake up btcoex thread to restore btlags+params */
7294 schedule_work(&btco_inf->work);
7295 }
7296 }
7297
7298 /* Restoring btc_flag paramter anyway */
7299 if (saved_status == TRUE)
7300 dev_wlc_bufvar_set(dev, "btc_flags",
7301 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
7302#endif /* COEX_DHCP */
7303
7304 /* Restore original values */
7305 if (saved_status == TRUE) {
7306 regaddr = 66;
7307 dev_wlc_intvar_set_reg(dev, "btc_params",
7308 (char *)&regaddr, (char *)&saved_reg66);
7309 regaddr = 41;
7310 dev_wlc_intvar_set_reg(dev, "btc_params",
7311 (char *)&regaddr, (char *)&saved_reg41);
7312 regaddr = 68;
7313 dev_wlc_intvar_set_reg(dev, "btc_params",
7314 (char *)&regaddr, (char *)&saved_reg68);
7315
7316 WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
7317 saved_reg66, saved_reg41, saved_reg68));
7318 }
7319 saved_status = FALSE;
7320
7321 }
7322 else {
7323 WL_ERR(("%s Unkwown yet power setting, ignored\n",
7324 __FUNCTION__));
7325 }
7326
7327 snprintf(command, 3, "OK");
7328
7329 return (strlen("OK"));
7330}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
new file mode 100644
index 00000000000..262335ef99c
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h
@@ -0,0 +1,558 @@
1/*
2 * Linux cfg80211 driver
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wl_cfg80211.h,v 1.1.4.1.2.8 2011/02/09 01:37:52 Exp $
25 */
26
27#ifndef _wl_cfg80211_h_
28#define _wl_cfg80211_h_
29
30#include <linux/wireless.h>
31#include <typedefs.h>
32#include <proto/ethernet.h>
33#include <wlioctl.h>
34#include <linux/wireless.h>
35#include <net/cfg80211.h>
36#include <linux/rfkill.h>
37
38#include <wl_cfgp2p.h>
39
40struct wl_conf;
41struct wl_iface;
42struct wl_priv;
43struct wl_security;
44struct wl_ibss;
45
46
47#define htod32(i) i
48#define htod16(i) i
49#define dtoh32(i) i
50#define dtoh16(i) i
51#define htodchanspec(i) i
52#define dtohchanspec(i) i
53
54#define WL_DBG_NONE 0
55#define WL_DBG_TRACE (1 << 4)
56#define WL_DBG_SCAN (1 << 3)
57#define WL_DBG_DBG (1 << 2)
58#define WL_DBG_INFO (1 << 1)
59#define WL_DBG_ERR (1 << 0)
60
61/* 0 invalidates all debug messages. default is 1 */
62#define WL_DBG_LEVEL 0xFF
63
64#define WL_ERR(args) \
65do { \
66 if (wl_dbg_level & WL_DBG_ERR) { \
67 printk(KERN_ERR "CFG80211-ERROR) %s : ", __func__); \
68 printk args; \
69 } \
70} while (0)
71#define WL_INFO(args) \
72do { \
73 if (wl_dbg_level & WL_DBG_INFO) { \
74 printk(KERN_ERR "CFG80211-INFO) %s : ", __func__); \
75 printk args; \
76 } \
77} while (0)
78#define WL_SCAN(args) \
79do { \
80 if (wl_dbg_level & WL_DBG_SCAN) { \
81 printk(KERN_ERR "CFG80211-SCAN) %s :", __func__); \
82 printk args; \
83 } \
84} while (0)
85#define WL_TRACE(args) \
86do { \
87 if (wl_dbg_level & WL_DBG_TRACE) { \
88 printk(KERN_ERR "CFG80211-TRACE) %s :", __func__); \
89 printk args; \
90 } \
91} while (0)
92#if (WL_DBG_LEVEL > 0)
93#define WL_DBG(args) \
94do { \
95 if (wl_dbg_level & WL_DBG_DBG) { \
96 printk(KERN_ERR "CFG80211-DEBUG) %s :", __func__); \
97 printk args; \
98 } \
99} while (0)
100#else /* !(WL_DBG_LEVEL > 0) */
101#define WL_DBG(args)
102#endif /* (WL_DBG_LEVEL > 0) */
103
104
105#define WL_SCAN_RETRY_MAX 3 /* used for ibss scan */
106#define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used
107 * for 2.6.33 kernel
108 * or later
109 */
110#define WL_SCAN_BUF_MAX (1024 * 8)
111#define WL_TLV_INFO_MAX 1024
112#define WL_SCAN_IE_LEN_MAX 2048
113#define WL_BSS_INFO_MAX 2048
114#define WL_ASSOC_INFO_MAX 512 /*
115 * needs to grab assoc info from dongle to
116 * report it to cfg80211 through "connect"
117 * event
118 */
119#define WL_IOCTL_LEN_MAX 1024
120#define WL_EXTRA_BUF_MAX 2048
121#define WL_ISCAN_BUF_MAX 2048 /*
122 * the buf lengh can be WLC_IOCTL_MAXLEN (8K)
123 * to reduce iteration
124 */
125#define WL_ISCAN_TIMER_INTERVAL_MS 3000
126#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1)
127#define WL_AP_MAX 256 /* virtually unlimitted as long
128 * as kernel memory allows
129 */
130#define WL_FILE_NAME_MAX 256
131#define WL_DWELL_TIME 200
132#define WL_LONG_DWELL_TIME 1000
133#define VWDEV_CNT 3
134
135#define WL_SCAN_TIMER_INTERVAL_MS 8000 /* Scan timeout */
136
137/* dongle status */
138enum wl_status {
139 WL_STATUS_READY = 0,
140 WL_STATUS_SCANNING,
141 WL_STATUS_SCAN_ABORTING,
142 WL_STATUS_CONNECTING,
143 WL_STATUS_CONNECTED,
144 WL_STATUS_DISCONNECTING,
145 WL_STATUS_AP_CREATING,
146 WL_STATUS_AP_CREATED
147};
148
149/* wi-fi mode */
150enum wl_mode {
151 WL_MODE_BSS,
152 WL_MODE_IBSS,
153 WL_MODE_AP
154};
155
156/* dongle profile list */
157enum wl_prof_list {
158 WL_PROF_MODE,
159 WL_PROF_SSID,
160 WL_PROF_SEC,
161 WL_PROF_IBSS,
162 WL_PROF_BAND,
163 WL_PROF_BSSID,
164 WL_PROF_ACT,
165 WL_PROF_BEACONINT,
166 WL_PROF_DTIMPERIOD
167};
168
169/* dongle iscan state */
170enum wl_iscan_state {
171 WL_ISCAN_STATE_IDLE,
172 WL_ISCAN_STATE_SCANING
173};
174
175/* donlge escan state */
176enum wl_escan_state {
177 WL_ESCAN_STATE_IDLE,
178 WL_ESCAN_STATE_SCANING
179};
180/* fw downloading status */
181enum wl_fw_status {
182 WL_FW_LOADING_DONE,
183 WL_NVRAM_LOADING_DONE
184};
185
186enum wl_management_type {
187 WL_BEACON = 0x1,
188 WL_PROBE_RESP = 0x2,
189 WL_ASSOC_RESP = 0x4
190};
191/* beacon / probe_response */
192struct beacon_proberesp {
193 __le64 timestamp;
194 __le16 beacon_int;
195 __le16 capab_info;
196 u8 variable[0];
197} __attribute__ ((packed));
198
199/* dongle configuration */
200struct wl_conf {
201 struct net_mode {
202 struct net_device *ndev;
203 s32 type;
204 } mode [VWDEV_CNT + 1]; /* adhoc , infrastructure or ap */
205 u32 frag_threshold;
206 u32 rts_threshold;
207 u32 retry_short;
208 u32 retry_long;
209 s32 tx_power;
210 struct ieee80211_channel channel;
211};
212
213typedef s32(*EVENT_HANDLER) (struct wl_priv *wl,
214 struct net_device *ndev, const wl_event_msg_t *e, void *data);
215
216/* bss inform structure for cfg80211 interface */
217struct wl_cfg80211_bss_info {
218 u16 band;
219 u16 channel;
220 s16 rssi;
221 u16 frame_len;
222 u8 frame_buf[1];
223};
224
225/* basic structure of scan request */
226struct wl_scan_req {
227 struct wlc_ssid ssid;
228};
229
230/* basic structure of information element */
231struct wl_ie {
232 u16 offset;
233 u8 buf[WL_TLV_INFO_MAX];
234};
235
236/* event queue for cfg80211 main event */
237struct wl_event_q {
238 struct list_head eq_list;
239 u32 etype;
240 wl_event_msg_t emsg;
241 s8 edata[1];
242};
243
244/* security information with currently associated ap */
245struct wl_security {
246 u32 wpa_versions;
247 u32 auth_type;
248 u32 cipher_pairwise;
249 u32 cipher_group;
250 u32 wpa_auth;
251};
252
253/* ibss information for currently joined ibss network */
254struct wl_ibss {
255 u8 beacon_interval; /* in millisecond */
256 u8 atim; /* in millisecond */
257 s8 join_only;
258 u8 band;
259 u8 channel;
260};
261
262/* dongle profile */
263struct wl_profile {
264 u32 mode;
265 struct wlc_ssid ssid;
266 u8 bssid[ETHER_ADDR_LEN];
267 u16 beacon_interval;
268 u8 dtim_period;
269 struct wl_security sec;
270 struct wl_ibss ibss;
271 s32 band;
272 bool active;
273};
274
275typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl);
276
277/* dongle iscan controller */
278struct wl_iscan_ctrl {
279 struct net_device *dev;
280 struct timer_list timer;
281 u32 timer_ms;
282 u32 timer_on;
283 s32 state;
284 struct task_struct *tsk;
285 struct semaphore sync;
286 ISCAN_HANDLER iscan_handler[WL_SCAN_ERSULTS_LAST];
287 void *data;
288 s8 ioctl_buf[WLC_IOCTL_SMLEN];
289 s8 scan_buf[WL_ISCAN_BUF_MAX];
290};
291
292/* association inform */
293#define MAX_REQ_LINE 1024
294struct wl_connect_info {
295 u8 req_ie[MAX_REQ_LINE];
296 s32 req_ie_len;
297 u8 resp_ie[MAX_REQ_LINE];
298 s32 resp_ie_len;
299};
300
301/* firmware /nvram downloading controller */
302struct wl_fw_ctrl {
303 const struct firmware *fw_entry;
304 unsigned long status;
305 u32 ptr;
306 s8 fw_name[WL_FILE_NAME_MAX];
307 s8 nvram_name[WL_FILE_NAME_MAX];
308};
309
310/* assoc ie length */
311struct wl_assoc_ielen {
312 u32 req_len;
313 u32 resp_len;
314};
315
316/* wpa2 pmk list */
317struct wl_pmk_list {
318 pmkid_list_t pmkids;
319 pmkid_t foo[MAXPMKID - 1];
320};
321
322
323#define ESCAN_BUF_SIZE (64 * 1024)
324
325struct escan_info {
326 u32 escan_state;
327 u8 escan_buf[ESCAN_BUF_SIZE];
328 struct wiphy *wiphy;
329};
330
331struct ap_info {
332/* Structure to hold WPS, WPA IEs for a AP */
333 u8 probe_res_ie[IE_MAX_LEN];
334 u8 beacon_ie[IE_MAX_LEN];
335 u32 probe_res_ie_len;
336 u32 beacon_ie_len;
337 u8 *wpa_ie;
338 u8 *rsn_ie;
339 u8 *wps_ie;
340 bool security_mode;
341};
342struct btcoex_info {
343 struct timer_list timer;
344 uint32 timer_ms;
345 uint32 timer_on;
346 uint32 ts_dhcp_start; /* ms ts ecord time stats */
347 uint32 ts_dhcp_ok; /* ms ts ecord time stats */
348 bool dhcp_done; /* flag, indicates that host done with
349 * dhcp before t1/t2 expiration
350 */
351 int bt_state;
352 struct work_struct work;
353 struct net_device *dev;
354};
355
356struct sta_info {
357 /* Structure to hold WPS IE for a STA */
358 u8 probe_req_ie[IE_MAX_LEN];
359 u8 assoc_req_ie[IE_MAX_LEN];
360 u32 probe_req_ie_len;
361 u32 assoc_req_ie_len;
362};
363/* dongle private data of cfg80211 interface */
364struct wl_priv {
365 struct wireless_dev *wdev; /* representing wl cfg80211 device */
366 struct wireless_dev *vwdev[VWDEV_CNT];
367 struct wl_conf *conf; /* dongle configuration */
368 struct cfg80211_scan_request *scan_request; /* scan request object */
369 EVENT_HANDLER evt_handler[WLC_E_LAST];
370 struct list_head eq_list; /* used for event queue */
371 spinlock_t eq_lock; /* for event queue synchronization */
372 struct mutex usr_sync; /* maily for dongle up/down synchronization */
373 struct wl_scan_results *bss_list;
374 struct wl_scan_results *scan_results;
375
376 /* scan request object for internal purpose */
377 struct wl_scan_req *scan_req_int;
378
379 /* bss information for cfg80211 layer */
380 struct wl_cfg80211_bss_info *bss_info;
381 /* information element object for internal purpose */
382 struct wl_ie ie;
383
384 /* for synchronization of main event thread */
385 struct wl_profile *profile; /* holding dongle profile */
386 struct wl_iscan_ctrl *iscan; /* iscan controller */
387
388 /* association information container */
389 struct wl_connect_info conn_info;
390
391 /* control firwmare and nvram paramter downloading */
392 struct wl_fw_ctrl *fw;
393 struct wl_pmk_list *pmk_list; /* wpa2 pmk list */
394 tsk_ctl_t event_tsk; /* task of main event handler thread */
395 unsigned long status; /* current dongle status */
396 void *pub;
397 u32 channel; /* current channel */
398 bool iscan_on; /* iscan on/off switch */
399 bool iscan_kickstart; /* indicate iscan already started */
400 bool escan_on; /* escan on/off switch */
401 struct escan_info escan_info; /* escan information */
402 bool active_scan; /* current scan mode */
403 bool ibss_starter; /* indicates this sta is ibss starter */
404 bool link_up; /* link/connection up flag */
405
406 /* indicate whether dongle to support power save mode */
407 bool pwr_save;
408 bool dongle_up; /* indicate whether dongle up or not */
409 bool roam_on; /* on/off switch for dongle self-roaming */
410 bool scan_tried; /* indicates if first scan attempted */
411 u8 *ioctl_buf; /* ioctl buffer */
412 u8 *escan_ioctl_buf;
413 u8 *extra_buf; /* maily to grab assoc information */
414 struct dentry *debugfsdir;
415 struct rfkill *rfkill;
416 bool rf_blocked;
417 struct ieee80211_channel remain_on_chan;
418 enum nl80211_channel_type remain_on_chan_type;
419 u64 cache_cookie;
420 wait_queue_head_t dongle_event_wait;
421 struct ap_info *ap_info;
422 struct sta_info *sta_info;
423 struct p2p_info *p2p;
424 bool p2p_supported;
425 struct btcoex_info *btcoex_info;
426 struct timer_list scan_timeout; /* Timer for catch scan event timeout */
427};
428
429#define wl_to_wiphy(w) (w->wdev->wiphy)
430#define wl_to_prmry_ndev(w) (w->wdev->netdev)
431#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr))
432#define wl_to_sr(w) (w->scan_req_int)
433#define wl_to_ie(w) (&w->ie)
434#define iscan_to_wl(i) ((struct wl_priv *)(i->data))
435#define wl_to_iscan(w) (w->iscan)
436#define wl_to_conn(w) (&w->conn_info)
437#define wiphy_from_scan(w) (w->escan_info.wiphy)
438#define wl_get_drv_status(wl, stat) (test_bit(WL_STATUS_ ## stat, &(wl)->status))
439#define wl_set_drv_status(wl, stat) (set_bit(WL_STATUS_ ## stat, &(wl)->status))
440#define wl_clr_drv_status(wl, stat) (clear_bit(WL_STATUS_ ## stat, &(wl)->status))
441#define wl_chg_drv_status(wl, stat) (change_bit(WL_STATUS_ ## stat, &(wl)->status))
442
443static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss)
444{
445 return bss = bss ?
446 (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info;
447}
448static inline s32 alloc_idx_vwdev(struct wl_priv *wl)
449{
450 s32 i = 0;
451 for (i = 0; i < VWDEV_CNT; i++) {
452 if (wl->vwdev[i] == NULL)
453 return i;
454 }
455 return -1;
456}
457
458static inline s32 get_idx_vwdev_by_netdev(struct wl_priv *wl, struct net_device *ndev)
459{
460 s32 i = 0;
461 for (i = 0; i < VWDEV_CNT; i++) {
462 if ((wl->vwdev[i] != NULL) && (wl->vwdev[i]->netdev == ndev))
463 return i;
464 }
465 return -1;
466}
467
468static inline s32 get_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev)
469{
470 s32 i = 0;
471 for (i = 0; i <= VWDEV_CNT; i++) {
472 if (wl->conf->mode[i].ndev != NULL && (wl->conf->mode[i].ndev == ndev))
473 return wl->conf->mode[i].type;
474 }
475 return -1;
476}
477static inline void set_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev, s32 type)
478{
479 s32 i = 0;
480 for (i = 0; i <= VWDEV_CNT; i++) {
481 if (type == -1) {
482 /* free the info of netdev */
483 if (wl->conf->mode[i].ndev == ndev) {
484 wl->conf->mode[i].ndev = NULL;
485 wl->conf->mode[i].type = -1;
486 break;
487 }
488
489 } else {
490 if ((wl->conf->mode[i].ndev != NULL)&&
491 (wl->conf->mode[i].ndev == ndev)) {
492 /* update type of ndev */
493 wl->conf->mode[i].type = type;
494 break;
495 }
496 else if ((wl->conf->mode[i].ndev == NULL)&&
497 (wl->conf->mode[i].type == -1)) {
498 wl->conf->mode[i].ndev = ndev;
499 wl->conf->mode[i].type = type;
500 break;
501 }
502 }
503 }
504}
505#define free_vwdev_by_index(wl, __i) do { \
506 if (wl->vwdev[__i] != NULL) \
507 kfree(wl->vwdev[__i]); \
508 wl->vwdev[__i] = NULL; \
509 } while (0)
510
511#define for_each_bss(list, bss, __i) \
512 for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss))
513
514/* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0.
515 * In addtion to that, wpa_version is WPA_VERSION_1
516 */
517#define is_wps_conn(_sme) \
518 ((_sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) && \
519 (!_sme->crypto.n_ciphers_pairwise) && \
520 (!_sme->crypto.cipher_group))
521extern s32 wl_cfg80211_attach(struct net_device *ndev, void *data);
522extern s32 wl_cfg80211_attach_post(struct net_device *ndev);
523extern void wl_cfg80211_detach(void);
524/* event handler from dongle */
525extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e,
526 void *data);
527extern void wl_cfg80211_set_sdio_func(void *func); /* set sdio function info */
528extern struct sdio_func *wl_cfg80211_get_sdio_func(void); /* set sdio function info */
529extern s32 wl_cfg80211_up(void); /* dongle up */
530extern s32 wl_cfg80211_down(void); /* dongle down */
531extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx,
532int (*_net_attach)(dhd_pub_t *dhdp, int ifidx));
533extern s32 wl_cfg80211_notify_ifdel(struct net_device *ndev);
534extern s32 wl_cfg80211_is_progress_ifadd(void);
535extern s32 wl_cfg80211_is_progress_ifchange(void);
536extern s32 wl_cfg80211_is_progress_ifadd(void);
537extern s32 wl_cfg80211_notify_ifchange(void);
538extern void wl_cfg80211_dbg_level(u32 level);
539extern void *wl_cfg80211_request_fw(s8 *file_name);
540extern s32 wl_cfg80211_read_fw(s8 *buf, u32 size);
541extern void wl_cfg80211_release_fw(void);
542extern s8 *wl_cfg80211_get_fwname(void);
543extern s8 *wl_cfg80211_get_nvramname(void);
544extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
545extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len);
546extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len);
547extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len,
548 enum wl_management_type type);
549extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len);
550extern int wl_cfg80211_hang(struct net_device *dev, u16 reason);
551
552/* do scan abort */
553extern s32
554wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev);
555
556extern s32
557wl_cfg80211_if_is_group_owner(void);
558#endif /* _wl_cfg80211_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
new file mode 100644
index 00000000000..4ee6557e17d
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c
@@ -0,0 +1,1469 @@
1/*
2 * Linux cfgp2p driver
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wl_cfgp2p.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
25 *
26 */
27#include <typedefs.h>
28#include <linuxver.h>
29#include <osl.h>
30#include <linux/kernel.h>
31#include <linux/kthread.h>
32#include <linux/netdevice.h>
33#include <linux/types.h>
34#include <linux/string.h>
35#include <linux/timer.h>
36#include <linux/if_arp.h>
37#include <asm/uaccess.h>
38
39#include <bcmutils.h>
40#include <bcmendian.h>
41#include <proto/ethernet.h>
42#include <dngl_stats.h>
43#include <dhd.h>
44#include <dhdioctl.h>
45#include <wlioctl.h>
46
47#include <wl_cfg80211.h>
48#include <wl_cfgp2p.h>
49#include <wldev_common.h>
50
51
52static s8 ioctlbuf[WLC_IOCTL_MAXLEN];
53static s8 scanparambuf[WLC_IOCTL_SMLEN];
54static s8 *smbuf = ioctlbuf;
55
56static bool
57wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type);
58
59static s32
60wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
61 s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete);
62/*
63 * Initialize variables related to P2P
64 *
65 */
66s32
67wl_cfgp2p_init_priv(struct wl_priv *wl)
68{
69 if (!(wl->p2p = kzalloc(sizeof(struct p2p_info), GFP_KERNEL))) {
70 CFGP2P_ERR(("struct p2p_info allocation failed\n"));
71 return -ENOMEM;
72 }
73#define INIT_IE(IE_TYPE, BSS_TYPE) \
74 do { \
75 memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
76 sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
77 wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
78 } while (0);
79
80 INIT_IE(probe_req, P2PAPI_BSSCFG_PRIMARY);
81 INIT_IE(probe_res, P2PAPI_BSSCFG_PRIMARY);
82 INIT_IE(assoc_req, P2PAPI_BSSCFG_PRIMARY);
83 INIT_IE(assoc_res, P2PAPI_BSSCFG_PRIMARY);
84 INIT_IE(beacon, P2PAPI_BSSCFG_PRIMARY);
85 INIT_IE(probe_req, P2PAPI_BSSCFG_DEVICE);
86 INIT_IE(probe_res, P2PAPI_BSSCFG_DEVICE);
87 INIT_IE(assoc_req, P2PAPI_BSSCFG_DEVICE);
88 INIT_IE(assoc_res, P2PAPI_BSSCFG_DEVICE);
89 INIT_IE(beacon, P2PAPI_BSSCFG_DEVICE);
90 INIT_IE(probe_req, P2PAPI_BSSCFG_CONNECTION);
91 INIT_IE(probe_res, P2PAPI_BSSCFG_CONNECTION);
92 INIT_IE(assoc_req, P2PAPI_BSSCFG_CONNECTION);
93 INIT_IE(assoc_res, P2PAPI_BSSCFG_CONNECTION);
94 INIT_IE(beacon, P2PAPI_BSSCFG_CONNECTION);
95#undef INIT_IE
96 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY) = wl_to_prmry_ndev(wl);
97 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY) = 0;
98 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
99 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
100 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION) = NULL;
101 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION) = 0;
102 spin_lock_init(&wl->p2p->timer_lock);
103 return BCME_OK;
104
105}
106/*
107 * Deinitialize variables related to P2P
108 *
109 */
110void
111wl_cfgp2p_deinit_priv(struct wl_priv *wl)
112{
113 if (wl->p2p) {
114 kfree(wl->p2p);
115 wl->p2p = NULL;
116 }
117 wl->p2p_supported = 0;
118}
119/*
120 * Set P2P functions into firmware
121 */
122s32
123wl_cfgp2p_set_firm_p2p(struct wl_priv *wl)
124{
125 struct net_device *ndev = wl_to_prmry_ndev(wl);
126 struct ether_addr null_eth_addr = { { 0, 0, 0, 0, 0, 0 } };
127 s32 ret = BCME_OK;
128 s32 val = 0;
129 /* Do we have to check whether APSTA is enabled or not ? */
130 wldev_iovar_getint(ndev, "apsta", &val);
131 if (val == 0) {
132 val = 1;
133 wldev_ioctl(ndev, WLC_DOWN, &val, sizeof(s32), true);
134 wldev_iovar_setint(ndev, "apsta", val);
135 wldev_ioctl(ndev, WLC_UP, &val, sizeof(s32), true);
136 }
137 val = 1;
138 /* Disable firmware roaming for P2P */
139 wldev_iovar_setint(ndev, "roam_off", val);
140 /* In case of COB type, firmware has default mac address
141 * After Initializing firmware, we have to set current mac address to
142 * firmware for P2P device address
143 */
144 ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr,
145 sizeof(null_eth_addr), ioctlbuf, sizeof(ioctlbuf), 0);
146 if (ret && ret != BCME_UNSUPPORTED) {
147 CFGP2P_ERR(("failed to update device address\n"));
148 }
149 return ret;
150}
151
152/* Create a new P2P BSS.
153 * Parameters:
154 * @mac : MAC address of the BSS to create
155 * @if_type : interface type: WL_P2P_IF_GO or WL_P2P_IF_CLIENT
156 * @chspec : chspec to use if creating a GO BSS.
157 * Returns 0 if success.
158 */
159s32
160wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
161 chanspec_t chspec)
162{
163 wl_p2p_if_t ifreq;
164 s32 err;
165 struct net_device *ndev = wl_to_prmry_ndev(wl);
166
167 ifreq.type = if_type;
168 ifreq.chspec = chspec;
169 memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
170
171 CFGP2P_INFO(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
172 ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2],
173 ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5],
174 (if_type == WL_P2P_IF_GO) ? "go" : "client",
175 (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
176
177 err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq),
178 ioctlbuf, sizeof(ioctlbuf));
179 return err;
180}
181
182/* Delete a P2P BSS.
183 * Parameters:
184 * @mac : MAC address of the BSS to create
185 * Returns 0 if success.
186 */
187s32
188wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac)
189{
190 s32 ret;
191 struct net_device *netdev = wl_to_prmry_ndev(wl);
192
193 CFGP2P_INFO(("------primary idx %d : wl p2p_ifdel %02x:%02x:%02x:%02x:%02x:%02x\n",
194 netdev->ifindex, mac->octet[0], mac->octet[1], mac->octet[2],
195 mac->octet[3], mac->octet[4], mac->octet[5]));
196 ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac),
197 ioctlbuf, sizeof(ioctlbuf));
198 if (unlikely(ret < 0)) {
199 printk("'wl p2p_ifdel' error %d\n", ret);
200 }
201 return ret;
202}
203
204/* Change a P2P Role.
205 * Parameters:
206 * @mac : MAC address of the BSS to change a role
207 * Returns 0 if success.
208 */
209s32
210wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
211 chanspec_t chspec)
212{
213 wl_p2p_if_t ifreq;
214 s32 err;
215 struct net_device *netdev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION);
216
217 ifreq.type = if_type;
218 ifreq.chspec = chspec;
219 memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet));
220
221 CFGP2P_INFO(("---wl p2p_ifchange %02x:%02x:%02x:%02x:%02x:%02x %s %u\n",
222 ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2],
223 ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5],
224 (if_type == WL_P2P_IF_GO) ? "go" : "client",
225 (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT));
226
227 err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq),
228 ioctlbuf, sizeof(ioctlbuf));
229
230 if (unlikely(err < 0)) {
231 printk("'wl p2p_ifupd' error %d\n", err);
232 }
233 return err;
234}
235
236
237/* Get the index of a created P2P BSS.
238 * Parameters:
239 * @mac : MAC address of the created BSS
240 * @index : output: index of created BSS
241 * Returns 0 if success.
242 */
243s32
244wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index)
245{
246 s32 ret;
247 u8 getbuf[64];
248 struct net_device *dev = wl_to_prmry_ndev(wl);
249
250 CFGP2P_INFO(("---wl p2p_if %02x:%02x:%02x:%02x:%02x:%02x\n",
251 mac->octet[0], mac->octet[1], mac->octet[2],
252 mac->octet[3], mac->octet[4], mac->octet[5]));
253
254 ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac),
255 getbuf, sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY));
256
257 if (ret == 0) {
258 memcpy(index, getbuf, sizeof(index));
259 CFGP2P_INFO(("---wl p2p_if ==> %d\n", *index));
260 }
261
262 return ret;
263}
264
265s32
266wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on)
267{
268 s32 ret = BCME_OK;
269 struct net_device *ndev = wl_to_prmry_ndev(wl);
270 CFGP2P_DBG(("enter\n"));
271
272 ret = wldev_iovar_setint(ndev, "p2p_disc", on);
273
274 if (unlikely(ret < 0)) {
275 CFGP2P_ERR(("p2p_disc %d error %d\n", on, ret));
276 }
277
278 return ret;
279}
280
281/* Set the WL driver's P2P mode.
282 * Parameters :
283 * @mode : is one of WL_P2P_DISC_ST_{SCAN,LISTEN,SEARCH}.
284 * @channel : the channel to listen
285 * @listen_ms : the time (milli seconds) to wait
286 * @bssidx : bss index for BSSCFG
287 * Returns 0 if success
288 */
289
290s32
291wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, int bssidx)
292{
293 wl_p2p_disc_st_t discovery_mode;
294 s32 ret;
295 struct net_device *dev;
296 CFGP2P_DBG(("enter\n"));
297
298 if (unlikely(bssidx >= P2PAPI_BSSCFG_MAX)) {
299 CFGP2P_ERR((" %d index out of range\n", bssidx));
300 return -1;
301 }
302
303 dev = wl_to_p2p_bss_ndev(wl, bssidx);
304 if (unlikely(dev == NULL)) {
305 CFGP2P_ERR(("bssidx %d is not assigned\n", bssidx));
306 return BCME_NOTFOUND;
307 }
308
309 /* Put the WL driver into P2P Listen Mode to respond to P2P probe reqs */
310 discovery_mode.state = mode;
311 discovery_mode.chspec = CH20MHZ_CHSPEC(channel);
312 discovery_mode.dwell = listen_ms;
313 ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode,
314 sizeof(discovery_mode), ioctlbuf, sizeof(ioctlbuf), bssidx);
315
316 return ret;
317}
318
319/* Get the index of the P2P Discovery BSS */
320s32
321wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index)
322{
323 s32 ret;
324 struct net_device *dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
325
326 ret = wldev_iovar_getint(dev, "p2p_dev", index);
327 CFGP2P_INFO(("p2p_dev bsscfg_idx=%d ret=%d\n", *index, ret));
328
329 if (unlikely(ret < 0)) {
330 CFGP2P_ERR(("'p2p_dev' error %d\n", ret));
331 return ret;
332 }
333 return ret;
334}
335
336s32
337wl_cfgp2p_init_discovery(struct wl_priv *wl)
338{
339
340 s32 index = 0;
341 s32 ret = BCME_OK;
342
343 CFGP2P_DBG(("enter\n"));
344
345 if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) != 0) {
346 CFGP2P_ERR(("do nothing, already initialized\n"));
347 return ret;
348 }
349
350 ret = wl_cfgp2p_set_discovery(wl, 1);
351 if (ret < 0) {
352 CFGP2P_ERR(("set discover error\n"));
353 return ret;
354 }
355 /* Enable P2P Discovery in the WL Driver */
356 ret = wl_cfgp2p_get_disc_idx(wl, &index);
357
358 if (ret < 0) {
359 return ret;
360 }
361 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) =
362 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
363 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = index;
364
365 /* Set the initial discovery state to SCAN */
366 ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
367 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
368
369 if (unlikely(ret != 0)) {
370 CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
371 wl_cfgp2p_set_discovery(wl, 0);
372 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
373 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
374 return 0;
375 }
376 return ret;
377}
378
379/* Deinitialize P2P Discovery
380 * Parameters :
381 * @wl : wl_private data
382 * Returns 0 if succes
383 */
384s32
385wl_cfgp2p_deinit_discovery(struct wl_priv *wl)
386{
387 s32 ret = BCME_OK;
388 CFGP2P_DBG(("enter\n"));
389
390 if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) {
391 CFGP2P_ERR(("do nothing, not initialized\n"));
392 return -1;
393 }
394 /* Set the discovery state to SCAN */
395 ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
396 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
397 /* Disable P2P discovery in the WL driver (deletes the discovery BSSCFG) */
398 ret = wl_cfgp2p_set_discovery(wl, 0);
399
400 /* Clear our saved WPS and P2P IEs for the discovery BSS. The driver
401 * deleted these IEs when wl_cfgp2p_set_discovery() deleted the discovery
402 * BSS.
403 */
404
405 /* Clear the saved bsscfg index of the discovery BSSCFG to indicate we
406 * have no discovery BSS.
407 */
408 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) = 0;
409 wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE) = NULL;
410
411 return ret;
412
413}
414/* Enable P2P Discovery
415 * Parameters:
416 * @wl : wl_private data
417 * @ie : probe request ie (WPS IE + P2P IE)
418 * @ie_len : probe request ie length
419 * Returns 0 if success.
420 */
421s32
422wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len)
423{
424 s32 ret = BCME_OK;
425 if (wl_get_p2p_status(wl, DISCOVERY_ON)) {
426 CFGP2P_INFO((" DISCOVERY is already initialized, we have nothing to do\n"));
427 goto set_ie;
428 }
429
430 wl_set_p2p_status(wl, DISCOVERY_ON);
431
432 CFGP2P_DBG(("enter\n"));
433
434 ret = wl_cfgp2p_init_discovery(wl);
435 if (unlikely(ret < 0)) {
436 CFGP2P_ERR((" init discovery error %d\n", ret));
437 goto exit;
438 }
439 /* Set wsec to any non-zero value in the discovery bsscfg to ensure our
440 * P2P probe responses have the privacy bit set in the 802.11 WPA IE.
441 * Some peer devices may not initiate WPS with us if this bit is not set.
442 */
443 ret = wldev_iovar_setint_bsscfg(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE),
444 "wsec", AES_ENABLED, wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
445 if (unlikely(ret < 0)) {
446 CFGP2P_ERR((" wsec error %d\n", ret));
447 }
448set_ie:
449 ret = wl_cfgp2p_set_management_ie(wl, dev,
450 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE),
451 VNDR_IE_PRBREQ_FLAG, ie, ie_len);
452
453 if (unlikely(ret < 0)) {
454 CFGP2P_ERR(("set probreq ie occurs error %d\n", ret));
455 goto exit;
456 }
457exit:
458 return ret;
459}
460
461/* Disable P2P Discovery
462 * Parameters:
463 * @wl : wl_private_data
464 * Returns 0 if success.
465 */
466s32
467wl_cfgp2p_disable_discovery(struct wl_priv *wl)
468{
469 s32 ret = BCME_OK;
470 CFGP2P_DBG((" enter\n"));
471 wl_clr_p2p_status(wl, DISCOVERY_ON);
472
473 if (wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE) == 0) {
474 CFGP2P_ERR((" do nothing, not initialized\n"));
475 goto exit;
476 }
477
478 ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
479 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
480
481 if (unlikely(ret < 0)) {
482
483 CFGP2P_ERR(("unable to set WL_P2P_DISC_ST_SCAN\n"));
484 }
485 /* Do a scan abort to stop the driver's scan engine in case it is still
486 * waiting out an action frame tx dwell time.
487 */
488#ifdef NOT_YET
489 if (wl_get_p2p_status(wl, SCANNING)) {
490 p2pwlu_scan_abort(hdl, FALSE);
491 }
492#endif
493 wl_clr_p2p_status(wl, DISCOVERY_ON);
494 ret = wl_cfgp2p_deinit_discovery(wl);
495
496exit:
497 return ret;
498}
499
500s32
501wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active,
502 u32 num_chans, u16 *channels,
503 s32 search_state, u16 action, u32 bssidx)
504{
505 s32 ret = BCME_OK;
506 s32 memsize;
507 s32 eparams_size;
508 u32 i;
509 s8 *memblk;
510 wl_p2p_scan_t *p2p_params;
511 wl_escan_params_t *eparams;
512 wlc_ssid_t ssid;
513 /* Scan parameters */
514#define P2PAPI_SCAN_NPROBES 4
515#define P2PAPI_SCAN_DWELL_TIME_MS 80
516#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 100
517#define P2PAPI_SCAN_HOME_TIME_MS 10
518 struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY);
519 wl_set_p2p_status(wl, SCANNING);
520 /* Allocate scan params which need space for 3 channels and 0 ssids */
521 eparams_size = (WL_SCAN_PARAMS_FIXED_SIZE +
522 OFFSETOF(wl_escan_params_t, params)) +
523 num_chans * sizeof(eparams->params.channel_list[0]);
524
525 memsize = sizeof(wl_p2p_scan_t) + eparams_size;
526 memblk = scanparambuf;
527 if (memsize > sizeof(scanparambuf)) {
528 CFGP2P_ERR((" scanpar buf too small (%u > %u)\n",
529 memsize, sizeof(scanparambuf)));
530 return -1;
531 }
532 memset(memblk, 0, memsize);
533 memset(ioctlbuf, 0, sizeof(ioctlbuf));
534 if (search_state == WL_P2P_DISC_ST_SEARCH) {
535 /*
536 * If we in SEARCH STATE, we don't need to set SSID explictly
537 * because dongle use P2P WILDCARD internally by default
538 */
539 wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SEARCH, 0, 0, bssidx);
540 ssid.SSID_len = htod32(0);
541
542 } else if (search_state == WL_P2P_DISC_ST_SCAN) {
543 /* SCAN STATE 802.11 SCAN
544 * WFD Supplicant has p2p_find command with (type=progressive, type= full)
545 * So if P2P_find command with type=progressive,
546 * we have to set ssid to P2P WILDCARD because
547 * we just do broadcast scan unless setting SSID
548 */
549 strcpy(ssid.SSID, WL_P2P_WILDCARD_SSID);
550 ssid.SSID_len = htod32(WL_P2P_WILDCARD_SSID_LEN);
551 wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0, bssidx);
552 }
553
554
555 /* Fill in the P2P scan structure at the start of the iovar param block */
556 p2p_params = (wl_p2p_scan_t*) memblk;
557 p2p_params->type = 'E';
558 /* Fill in the Scan structure that follows the P2P scan structure */
559 eparams = (wl_escan_params_t*) (p2p_params + 1);
560 eparams->params.bss_type = DOT11_BSSTYPE_ANY;
561 if (active)
562 eparams->params.scan_type = DOT11_SCANTYPE_ACTIVE;
563 else
564 eparams->params.scan_type = DOT11_SCANTYPE_PASSIVE;
565
566 memcpy(&eparams->params.bssid, &ether_bcast, ETHER_ADDR_LEN);
567 if (ssid.SSID_len)
568 memcpy(&eparams->params.ssid, &ssid, sizeof(wlc_ssid_t));
569
570 eparams->params.nprobes = htod32(P2PAPI_SCAN_NPROBES);
571 eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS);
572 if (wl_get_drv_status(wl, CONNECTED))
573 eparams->params.active_time = htod32(-1);
574 else if (num_chans == 3)
575 eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS);
576 else
577 eparams->params.active_time = htod32(P2PAPI_SCAN_DWELL_TIME_MS);
578 eparams->params.passive_time = htod32(-1);
579 eparams->params.channel_num = htod32((0 << WL_SCAN_PARAMS_NSSID_SHIFT) |
580 (num_chans & WL_SCAN_PARAMS_COUNT_MASK));
581
582 for (i = 0; i < num_chans; i++) {
583 eparams->params.channel_list[i] = htodchanspec(channels[i]);
584 }
585 eparams->version = htod32(ESCAN_REQ_VERSION);
586 eparams->action = htod16(action);
587 eparams->sync_id = htod16(0x1234);
588 CFGP2P_INFO(("SCAN CHANNELS : "));
589
590 for (i = 0; i < num_chans; i++) {
591 if (i == 0) CFGP2P_INFO(("%d", channels[i]));
592 else CFGP2P_INFO((",%d", channels[i]));
593 }
594
595 CFGP2P_INFO(("\n"));
596
597 ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan",
598 memblk, memsize, smbuf, sizeof(ioctlbuf), bssidx);
599 return ret;
600}
601/* Check whether pointed-to IE looks like WPA. */
602#define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
603 (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE)
604/* Check whether pointed-to IE looks like WPS. */
605#define wl_cfgp2p_is_wps_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
606 (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPS_OUI_TYPE)
607/* Check whether the given IE looks like WFA P2P IE. */
608#define wl_cfgp2p_is_p2p_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \
609 (const uint8 *)WFA_OUI, WFA_OUI_LEN, WFA_OUI_TYPE_P2P)
610/* Delete and Set a management vndr ie to firmware
611 * Parameters:
612 * @wl : wl_private data
613 * @ndev : net device for bssidx
614 * @bssidx : bssidx for BSS
615 * @pktflag : packet flag for IE (VNDR_IE_PRBREQ_FLAG,VNDR_IE_PRBRSP_FLAG, VNDR_IE_ASSOCRSP_FLAG,
616 * VNDR_IE_ASSOCREQ_FLAG)
617 * @ie : VNDR IE (such as P2P IE , WPS IE)
618 * @ie_len : VNDR IE Length
619 * Returns 0 if success.
620 */
621
622s32
623wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
624 s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len)
625{
626 /* Vendor-specific Information Element ID */
627#define VNDR_SPEC_ELEMENT_ID 0xdd
628 s32 ret = BCME_OK;
629 u32 pos;
630 u8 *ie_buf;
631 u8 *mgmt_ie_buf = NULL;
632 u32 mgmt_ie_buf_len = 0;
633 u32 *mgmt_ie_len = 0;
634 u8 ie_id, ie_len;
635 u8 delete = 0;
636#define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie)
637#define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len)
638 if (wl->p2p_supported && p2p_on(wl) && bssidx != -1) {
639 if (bssidx == P2PAPI_BSSCFG_PRIMARY)
640 bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
641 switch (pktflag) {
642 case VNDR_IE_PRBREQ_FLAG :
643 mgmt_ie_buf = IE_TYPE(probe_req, bssidx);
644 mgmt_ie_len = &IE_TYPE_LEN(probe_req, bssidx);
645 mgmt_ie_buf_len = sizeof(IE_TYPE(probe_req, bssidx));
646 break;
647 case VNDR_IE_PRBRSP_FLAG :
648 mgmt_ie_buf = IE_TYPE(probe_res, bssidx);
649 mgmt_ie_len = &IE_TYPE_LEN(probe_res, bssidx);
650 mgmt_ie_buf_len = sizeof(IE_TYPE(probe_res, bssidx));
651 break;
652 case VNDR_IE_ASSOCREQ_FLAG :
653 mgmt_ie_buf = IE_TYPE(assoc_req, bssidx);
654 mgmt_ie_len = &IE_TYPE_LEN(assoc_req, bssidx);
655 mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_req, bssidx));
656 break;
657 case VNDR_IE_ASSOCRSP_FLAG :
658 mgmt_ie_buf = IE_TYPE(assoc_res, bssidx);
659 mgmt_ie_len = &IE_TYPE_LEN(assoc_res, bssidx);
660 mgmt_ie_buf_len = sizeof(IE_TYPE(assoc_res, bssidx));
661 break;
662 case VNDR_IE_BEACON_FLAG :
663 mgmt_ie_buf = IE_TYPE(beacon, bssidx);
664 mgmt_ie_len = &IE_TYPE_LEN(beacon, bssidx);
665 mgmt_ie_buf_len = sizeof(IE_TYPE(beacon, bssidx));
666 break;
667 default:
668 mgmt_ie_buf = NULL;
669 mgmt_ie_len = NULL;
670 CFGP2P_ERR(("not suitable type\n"));
671 return -1;
672 }
673 } else if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) {
674 switch (pktflag) {
675 case VNDR_IE_PRBRSP_FLAG :
676 mgmt_ie_buf = wl->ap_info->probe_res_ie;
677 mgmt_ie_len = &wl->ap_info->probe_res_ie_len;
678 mgmt_ie_buf_len = sizeof(wl->ap_info->probe_res_ie);
679 break;
680 case VNDR_IE_BEACON_FLAG :
681 mgmt_ie_buf = wl->ap_info->beacon_ie;
682 mgmt_ie_len = &wl->ap_info->beacon_ie_len;
683 mgmt_ie_buf_len = sizeof(wl->ap_info->beacon_ie);
684 break;
685 default:
686 mgmt_ie_buf = NULL;
687 mgmt_ie_len = NULL;
688 CFGP2P_ERR(("not suitable type\n"));
689 return -1;
690 }
691 bssidx = 0;
692 } else if (bssidx == -1 && get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) {
693 switch (pktflag) {
694 case VNDR_IE_PRBREQ_FLAG :
695 mgmt_ie_buf = wl->sta_info->probe_req_ie;
696 mgmt_ie_len = &wl->sta_info->probe_req_ie_len;
697 mgmt_ie_buf_len = sizeof(wl->sta_info->probe_req_ie);
698 break;
699 case VNDR_IE_ASSOCREQ_FLAG :
700 mgmt_ie_buf = wl->sta_info->assoc_req_ie;
701 mgmt_ie_len = &wl->sta_info->assoc_req_ie_len;
702 mgmt_ie_buf_len = sizeof(wl->sta_info->assoc_req_ie);
703 break;
704 default:
705 mgmt_ie_buf = NULL;
706 mgmt_ie_len = NULL;
707 CFGP2P_ERR(("not suitable type\n"));
708 return -1;
709 }
710 bssidx = 0;
711 } else {
712 CFGP2P_ERR(("not suitable type\n"));
713 return -1;
714 }
715
716 if (vndr_ie_len > mgmt_ie_buf_len) {
717 CFGP2P_ERR(("extra IE size too big\n"));
718 ret = -ENOMEM;
719 } else {
720 if (mgmt_ie_buf != NULL) {
721 if (vndr_ie_len && (vndr_ie_len == *mgmt_ie_len) &&
722 (memcmp(mgmt_ie_buf, vndr_ie, vndr_ie_len) == 0)) {
723 CFGP2P_INFO(("Previous mgmt IE is equals to current IE"));
724 goto exit;
725 }
726 pos = 0;
727 delete = 1;
728 ie_buf = (u8 *) mgmt_ie_buf;
729 while (pos < *mgmt_ie_len) {
730 ie_id = ie_buf[pos++];
731 ie_len = ie_buf[pos++];
732 if ((ie_id == DOT11_MNG_VS_ID) &&
733 (wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) ||
734 wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
735 CFGP2P_INFO(("DELELED ID : %d, Len : %d , OUI :"
736 "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
737 ie_buf[pos+1], ie_buf[pos+2]));
738 ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
739 VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
740 }
741 pos += ie_len;
742 }
743
744 }
745 *mgmt_ie_len = 0;
746 /* Add if there is any extra IE */
747 if (vndr_ie && vndr_ie_len) {
748 /* save the current IE in wl struct */
749 memcpy(mgmt_ie_buf, vndr_ie, vndr_ie_len);
750 *mgmt_ie_len = vndr_ie_len;
751 pos = 0;
752 ie_buf = (u8 *) vndr_ie;
753 delete = 0;
754 while (pos < vndr_ie_len) {
755 ie_id = ie_buf[pos++];
756 ie_len = ie_buf[pos++];
757 if ((ie_id == DOT11_MNG_VS_ID) &&
758 (wl_cfgp2p_is_wps_ie(&ie_buf[pos-2], NULL, 0) ||
759 wl_cfgp2p_is_p2p_ie(&ie_buf[pos-2], NULL, 0))) {
760 CFGP2P_INFO(("ADDED ID : %d, Len : %d , OUI :"
761 "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos],
762 ie_buf[pos+1], ie_buf[pos+2]));
763 ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos,
764 VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete);
765 }
766 pos += ie_len;
767 }
768 }
769 }
770#undef IE_TYPE
771#undef IE_TYPE_LEN
772exit:
773 return ret;
774}
775
776/* Clear the manament IE buffer of BSSCFG
777 * Parameters:
778 * @wl : wl_private data
779 * @bssidx : bssidx for BSS
780 *
781 * Returns 0 if success.
782 */
783s32
784wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx)
785{
786#define INIT_IE(IE_TYPE, BSS_TYPE) \
787 do { \
788 memset(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie, 0, \
789 sizeof(wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie)); \
790 wl_to_p2p_bss_saved_ie(wl, BSS_TYPE).p2p_ ## IE_TYPE ## _ie_len = 0; \
791 } while (0);
792 if (bssidx < 0) {
793 CFGP2P_ERR(("invalid bssidx\n"));
794 return BCME_BADARG;
795 }
796 INIT_IE(probe_req, bssidx);
797 INIT_IE(probe_res, bssidx);
798 INIT_IE(assoc_req, bssidx);
799 INIT_IE(assoc_res, bssidx);
800 INIT_IE(beacon, bssidx);
801 return BCME_OK;
802}
803
804
805/* Is any of the tlvs the expected entry? If
806 * not update the tlvs buffer pointer/length.
807 */
808static bool
809wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type)
810{
811 /* If the contents match the OUI and the type */
812 if (ie[TLV_LEN_OFF] >= oui_len + 1 &&
813 !bcmp(&ie[TLV_BODY_OFF], oui, oui_len) &&
814 type == ie[TLV_BODY_OFF + oui_len]) {
815 return TRUE;
816 }
817
818 if (tlvs == NULL)
819 return FALSE;
820 /* point to the next ie */
821 ie += ie[TLV_LEN_OFF] + TLV_HDR_LEN;
822 /* calculate the length of the rest of the buffer */
823 *tlvs_len -= (int)(ie - *tlvs);
824 /* update the pointer to the start of the buffer */
825 *tlvs = ie;
826
827 return FALSE;
828}
829
830wpa_ie_fixed_t *
831wl_cfgp2p_find_wpaie(u8 *parse, u32 len)
832{
833 bcm_tlv_t *ie;
834
835 while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
836 if (wl_cfgp2p_is_wpa_ie((u8*)ie, &parse, &len)) {
837 return (wpa_ie_fixed_t *)ie;
838 }
839 }
840 return NULL;
841}
842
843wpa_ie_fixed_t *
844wl_cfgp2p_find_wpsie(u8 *parse, u32 len)
845{
846 bcm_tlv_t *ie;
847
848 while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_VS_ID))) {
849 if (wl_cfgp2p_is_wps_ie((u8*)ie, &parse, &len)) {
850 return (wpa_ie_fixed_t *)ie;
851 }
852 }
853 return NULL;
854}
855
856wifi_p2p_ie_t *
857wl_cfgp2p_find_p2pie(u8 *parse, u32 len)
858{
859 bcm_tlv_t *ie;
860
861 while ((ie = bcm_parse_tlvs(parse, (int)len, DOT11_MNG_VS_ID))) {
862 if (wl_cfgp2p_is_p2p_ie((uint8*)ie, &parse, &len)) {
863 return (wifi_p2p_ie_t *)ie;
864 }
865 }
866 return NULL;
867}
868
869static s32
870wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag,
871 s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete)
872{
873 s32 err = BCME_OK;
874 s32 buf_len;
875 s32 iecount;
876
877 vndr_ie_setbuf_t *ie_setbuf;
878
879 /* Validate the pktflag parameter */
880 if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
881 VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
882 VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG))) {
883 CFGP2P_ERR(("p2pwl_vndr_ie: Invalid packet flag 0x%x\n", pktflag));
884 return -1;
885 }
886
887 buf_len = sizeof(vndr_ie_setbuf_t) + data_len - 1;
888 ie_setbuf = (vndr_ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL);
889
890 CFGP2P_INFO((" ie_id : %02x, data length : %d\n", ie_id, data_len));
891 if (!ie_setbuf) {
892
893 CFGP2P_ERR(("Error allocating buffer for IE\n"));
894 return -ENOMEM;
895 }
896 if (delete)
897 strcpy(ie_setbuf->cmd, "del");
898 else
899 strcpy(ie_setbuf->cmd, "add");
900 /* Buffer contains only 1 IE */
901 iecount = htod32(1);
902 memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int));
903 pktflag = htod32(pktflag);
904 memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag,
905 &pktflag, sizeof(uint32));
906 ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = ie_id;
907 ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len
908 = (uchar)(data_len + VNDR_IE_MIN_LEN);
909 memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, oui, 3);
910 memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, data, data_len);
911 err = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", ie_setbuf, buf_len,
912 ioctlbuf, sizeof(ioctlbuf), bssidx);
913
914 CFGP2P_INFO(("vndr_ie iovar returns %d\n", err));
915 kfree(ie_setbuf);
916 return err;
917}
918
919/*
920 * Search the bssidx based on dev argument
921 * Parameters:
922 * @wl : wl_private data
923 * @ndev : net device to search bssidx
924 * Returns bssidx for ndev
925 */
926s32
927wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev)
928{
929 u32 i;
930 s32 index = -1;
931
932 if (ndev == NULL) {
933 CFGP2P_ERR((" ndev is NULL\n"));
934 goto exit;
935 }
936 if (!wl->p2p_supported) {
937 return P2PAPI_BSSCFG_PRIMARY;
938 }
939 for (i = 0; i < P2PAPI_BSSCFG_MAX; i++) {
940 if (ndev == wl_to_p2p_bss_ndev(wl, i)) {
941 index = wl_to_p2p_bss_bssidx(wl, i);
942 break;
943 }
944 }
945 if (index == -1)
946 return P2PAPI_BSSCFG_PRIMARY;
947exit:
948 return index;
949}
950/*
951 * Callback function for WLC_E_P2P_DISC_LISTEN_COMPLETE
952 */
953s32
954wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev,
955 const wl_event_msg_t *e, void *data)
956{
957 s32 ret = BCME_OK;
958
959 CFGP2P_DBG((" Enter\n"));
960 if (wl_get_p2p_status(wl, LISTEN_EXPIRED) == 0) {
961 wl_set_p2p_status(wl, LISTEN_EXPIRED);
962 if (timer_pending(&wl->p2p->listen_timer)) {
963 spin_lock_bh(&wl->p2p->timer_lock);
964 del_timer_sync(&wl->p2p->listen_timer);
965 spin_unlock_bh(&wl->p2p->timer_lock);
966 }
967 cfg80211_remain_on_channel_expired(ndev, wl->cache_cookie, &wl->remain_on_chan,
968 wl->remain_on_chan_type, GFP_KERNEL);
969 } else
970 wl_clr_p2p_status(wl, LISTEN_EXPIRED);
971
972 return ret;
973
974}
975
976/*
977 * Timer expire callback function for LISTEN
978 * We can't report cfg80211_remain_on_channel_expired from Timer ISR context,
979 * so lets do it from thread context.
980 */
981static void
982wl_cfgp2p_listen_expired(unsigned long data)
983{
984 wl_event_msg_t msg;
985 struct wl_priv *wl = (struct wl_priv *) data;
986
987 CFGP2P_DBG((" Enter\n"));
988 msg.event_type = hton32(WLC_E_P2P_DISC_LISTEN_COMPLETE);
989 wl_cfg80211_event(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_DEVICE), &msg, NULL);
990}
991
992/*
993 * Do a P2P Listen on the given channel for the given duration.
994 * A listen consists of sitting idle and responding to P2P probe requests
995 * with a P2P probe response.
996 *
997 * This fn assumes dongle p2p device discovery is already enabled.
998 * Parameters :
999 * @wl : wl_private data
1000 * @channel : channel to listen
1001 * @duration_ms : the time (milli seconds) to wait
1002 */
1003s32
1004wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms)
1005{
1006#define INIT_TIMER(timer, func, duration, extra_delay) \
1007 do { \
1008 init_timer(timer); \
1009 timer->function = func; \
1010 timer->expires = jiffies + msecs_to_jiffies(duration + extra_delay); \
1011 timer->data = (unsigned long) wl; \
1012 add_timer(timer); \
1013 } while (0);
1014
1015 s32 ret = BCME_OK;
1016 struct timer_list *_timer;
1017 CFGP2P_DBG((" Enter Channel : %d, Duration : %d\n", channel, duration_ms));
1018 if (unlikely(wl_get_p2p_status(wl, DISCOVERY_ON) == 0)) {
1019
1020 CFGP2P_ERR((" Discovery is not set, so we have noting to do\n"));
1021
1022 ret = BCME_NOTREADY;
1023 goto exit;
1024 }
1025 if (timer_pending(&wl->p2p->listen_timer)) {
1026 CFGP2P_DBG(("previous LISTEN is not completed yet\n"));
1027 goto exit;
1028
1029 } else
1030 wl_clr_p2p_status(wl, LISTEN_EXPIRED);
1031
1032 wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_LISTEN, channel, (u16) duration_ms,
1033 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
1034 _timer = &wl->p2p->listen_timer;
1035
1036 /* We will wait to receive WLC_E_P2P_DISC_LISTEN_COMPLETE from dongle ,
1037 * otherwise we will wait up to duration_ms + 200ms
1038 */
1039 INIT_TIMER(_timer, wl_cfgp2p_listen_expired, duration_ms, 200);
1040
1041#undef INIT_TIMER
1042exit:
1043 return ret;
1044}
1045
1046
1047s32
1048wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable)
1049{
1050 s32 ret = BCME_OK;
1051 CFGP2P_DBG((" Enter\n"));
1052 if (!wl_get_p2p_status(wl, DISCOVERY_ON)) {
1053
1054 CFGP2P_DBG((" do nothing, discovery is off\n"));
1055 return ret;
1056 }
1057 if (wl_get_p2p_status(wl, SEARCH_ENABLED) == enable) {
1058 CFGP2P_DBG(("already : %d\n", enable));
1059 return ret;
1060 }
1061
1062 wl_chg_p2p_status(wl, SEARCH_ENABLED);
1063 /* When disabling Search, reset the WL driver's p2p discovery state to
1064 * WL_P2P_DISC_ST_SCAN.
1065 */
1066 if (!enable) {
1067 wl_clr_p2p_status(wl, SCANNING);
1068 ret = wl_cfgp2p_set_p2p_mode(wl, WL_P2P_DISC_ST_SCAN, 0, 0,
1069 wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE));
1070 }
1071
1072 return ret;
1073}
1074
1075/*
1076 * Callback function for WLC_E_ACTION_FRAME_COMPLETE, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE
1077 */
1078s32
1079wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev,
1080 const wl_event_msg_t *e, void *data)
1081{
1082 s32 ret = BCME_OK;
1083 u32 event_type = ntoh32(e->event_type);
1084 u32 status = ntoh32(e->status);
1085 CFGP2P_DBG((" Enter\n"));
1086 if (event_type == WLC_E_ACTION_FRAME_COMPLETE) {
1087
1088 CFGP2P_INFO((" WLC_E_ACTION_FRAME_COMPLETE is received : %d\n", status));
1089 if (status == WLC_E_STATUS_SUCCESS) {
1090 wl_set_p2p_status(wl, ACTION_TX_COMPLETED);
1091 }
1092 else {
1093 wl_set_p2p_status(wl, ACTION_TX_NOACK);
1094 CFGP2P_ERR(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n"));
1095 }
1096 wake_up_interruptible(&wl->dongle_event_wait);
1097 } else {
1098 CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received,"
1099 "status : %d\n", status));
1100 }
1101 return ret;
1102}
1103/* Send an action frame immediately without doing channel synchronization.
1104 *
1105 * This function does not wait for a completion event before returning.
1106 * The WLC_E_ACTION_FRAME_COMPLETE event will be received when the action
1107 * frame is transmitted.
1108 * The WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE event will be received when an
1109 * 802.11 ack has been received for the sent action frame.
1110 */
1111s32
1112wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
1113 wl_af_params_t *af_params, s32 bssidx)
1114{
1115 s32 ret = BCME_OK;
1116 s32 timeout = 0;
1117
1118
1119 CFGP2P_INFO(("\n"));
1120 CFGP2P_INFO(("channel : %u , dwell time : %u\n",
1121 af_params->channel, af_params->dwell_time));
1122
1123 wl_clr_p2p_status(wl, ACTION_TX_COMPLETED);
1124 wl_clr_p2p_status(wl, ACTION_TX_NOACK);
1125#define MAX_WAIT_TIME 2000
1126 if (bssidx == P2PAPI_BSSCFG_PRIMARY)
1127 bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE);
1128
1129 ret = wldev_iovar_setbuf_bsscfg(dev, "actframe",
1130 af_params, sizeof(*af_params), ioctlbuf, sizeof(ioctlbuf), bssidx);
1131
1132 if (ret < 0) {
1133
1134 CFGP2P_ERR((" sending action frame is failed\n"));
1135 goto exit;
1136 }
1137 timeout = wait_event_interruptible_timeout(wl->dongle_event_wait,
1138 (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || wl_get_p2p_status(wl, ACTION_TX_NOACK)),
1139 msecs_to_jiffies(MAX_WAIT_TIME));
1140
1141 if (timeout > 0 && wl_get_p2p_status(wl, ACTION_TX_COMPLETED)) {
1142 CFGP2P_INFO(("tx action frame operation is completed\n"));
1143 ret = BCME_OK;
1144 } else {
1145 ret = BCME_ERROR;
1146 CFGP2P_INFO(("tx action frame operation is failed\n"));
1147 }
1148exit:
1149 CFGP2P_INFO((" via act frame iovar : status = %d\n", ret));
1150#undef MAX_WAIT_TIME
1151 return ret;
1152}
1153
1154/* Generate our P2P Device Address and P2P Interface Address from our primary
1155 * MAC address.
1156 */
1157void
1158wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr,
1159 struct ether_addr *out_dev_addr, struct ether_addr *out_int_addr)
1160{
1161 memset(out_dev_addr, 0, sizeof(*out_dev_addr));
1162 memset(out_int_addr, 0, sizeof(*out_int_addr));
1163
1164 /* Generate the P2P Device Address. This consists of the device's
1165 * primary MAC address with the locally administered bit set.
1166 */
1167 memcpy(out_dev_addr, primary_addr, sizeof(*out_dev_addr));
1168 out_dev_addr->octet[0] |= 0x02;
1169
1170 /* Generate the P2P Interface Address. If the discovery and connection
1171 * BSSCFGs need to simultaneously co-exist, then this address must be
1172 * different from the P2P Device Address.
1173 */
1174 memcpy(out_int_addr, out_dev_addr, sizeof(*out_int_addr));
1175 out_int_addr->octet[4] ^= 0x80;
1176
1177}
1178
1179/* P2P IF Address change to Virtual Interface MAC Address */
1180void
1181wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id)
1182{
1183 wifi_p2p_ie_t *ie = (wifi_p2p_ie_t*) buf;
1184 u16 len = ie->len;
1185 u8 *subel;
1186 u8 subelt_id;
1187 u16 subelt_len;
1188 CFGP2P_DBG((" Enter\n"));
1189
1190 /* Point subel to the P2P IE's subelt field.
1191 * Subtract the preceding fields (id, len, OUI, oui_type) from the length.
1192 */
1193 subel = ie->subelts;
1194 len -= 4; /* exclude OUI + OUI_TYPE */
1195
1196 while (len >= 3) {
1197 /* attribute id */
1198 subelt_id = *subel;
1199 subel += 1;
1200 len -= 1;
1201
1202 /* 2-byte little endian */
1203 subelt_len = *subel++;
1204 subelt_len |= *subel++ << 8;
1205
1206 len -= 2;
1207 len -= subelt_len; /* for the remaining subelt fields */
1208
1209 if (subelt_id == element_id) {
1210 if (subelt_id == P2P_SEID_INTINTADDR) {
1211 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1212 CFGP2P_INFO(("Intended P2P Interface Address ATTR FOUND\n"));
1213 } else if (subelt_id == P2P_SEID_DEV_ID) {
1214 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1215 CFGP2P_INFO(("Device ID ATTR FOUND\n"));
1216 } else if (subelt_id == P2P_SEID_DEV_INFO) {
1217 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1218 CFGP2P_INFO(("Device INFO ATTR FOUND\n"));
1219 } else if (subelt_id == P2P_SEID_GROUP_ID) {
1220 memcpy(subel, p2p_int_addr->octet, ETHER_ADDR_LEN);
1221 CFGP2P_INFO(("GROUP ID ATTR FOUND\n"));
1222 } return;
1223 } else {
1224 CFGP2P_DBG(("OTHER id : %d\n", subelt_id));
1225 }
1226 subel += subelt_len;
1227 }
1228}
1229/*
1230 * Check if a BSS is up.
1231 * This is a common implementation called by most OSL implementations of
1232 * p2posl_bss_isup(). DO NOT call this function directly from the
1233 * common code -- call p2posl_bss_isup() instead to allow the OSL to
1234 * override the common implementation if necessary.
1235 */
1236bool
1237wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx)
1238{
1239 s32 result, val;
1240 bool isup = false;
1241 s8 getbuf[64];
1242
1243 /* Check if the BSS is up */
1244 *(int*)getbuf = -1;
1245 result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx,
1246 sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0);
1247 if (result != 0) {
1248 CFGP2P_ERR(("'wl bss -C %d' failed: %d\n", bsscfg_idx, result));
1249 CFGP2P_ERR(("NOTE: this ioctl error is normal "
1250 "when the BSS has not been created yet.\n"));
1251 } else {
1252 val = *(int*)getbuf;
1253 val = dtoh32(val);
1254 CFGP2P_INFO(("---wl bss -C %d ==> %d\n", bsscfg_idx, val));
1255 isup = (val ? TRUE : FALSE);
1256 }
1257 return isup;
1258}
1259
1260
1261/* Bring up or down a BSS */
1262s32
1263wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up)
1264{
1265 s32 ret = BCME_OK;
1266 s32 val = up ? 1 : 0;
1267
1268 struct {
1269 s32 cfg;
1270 s32 val;
1271 } bss_setbuf;
1272
1273 bss_setbuf.cfg = htod32(bsscfg_idx);
1274 bss_setbuf.val = htod32(val);
1275 CFGP2P_INFO(("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down"));
1276 ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf),
1277 ioctlbuf, sizeof(ioctlbuf));
1278
1279 if (ret != 0) {
1280 CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret));
1281 }
1282
1283 return ret;
1284}
1285
1286/* Check if 'p2p' is supported in the driver */
1287s32
1288wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev)
1289{
1290 s32 ret = BCME_OK;
1291 s32 p2p_supported = 0;
1292 ret = wldev_iovar_getint(ndev, "p2p",
1293 &p2p_supported);
1294 if (ret < 0) {
1295 CFGP2P_ERR(("wl p2p error %d\n", ret));
1296 return 0;
1297 }
1298 if (p2p_supported == 1) {
1299 CFGP2P_INFO(("p2p is supported\n"));
1300 } else {
1301 CFGP2P_INFO(("p2p is unsupported\n"));
1302 p2p_supported = 0;
1303 }
1304 return p2p_supported;
1305}
1306
1307/* Cleanup P2P resources */
1308s32
1309wl_cfgp2p_down(struct wl_priv *wl)
1310{
1311 if (timer_pending(&wl->p2p->listen_timer))
1312 del_timer_sync(&wl->p2p->listen_timer);
1313 wl_cfgp2p_deinit_priv(wl);
1314 return 0;
1315}
1316
1317s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
1318{
1319 s32 ret = -1;
1320 int count, start, duration;
1321 wl_p2p_sched_t dongle_noa;
1322
1323 CFGP2P_DBG((" Enter\n"));
1324
1325 memset(&dongle_noa, 0, sizeof(dongle_noa));
1326
1327 if (wl->p2p && wl->p2p->vif_created) {
1328
1329 wl->p2p->noa.desc[0].start = 0;
1330
1331 sscanf(buf, "%d %d %d", &count, &start, &duration);
1332 CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n",
1333 count, start, duration));
1334 if (count != -1)
1335 wl->p2p->noa.desc[0].count = count;
1336
1337 /* supplicant gives interval as start */
1338 if (start != -1)
1339 wl->p2p->noa.desc[0].interval = start;
1340
1341 if (duration != -1)
1342 wl->p2p->noa.desc[0].duration = duration;
1343
1344 if (wl->p2p->noa.desc[0].count != 255) {
1345 wl->p2p->noa.desc[0].start = 200;
1346 dongle_noa.type = WL_P2P_SCHED_TYPE_REQ_ABS;
1347 dongle_noa.action = WL_P2P_SCHED_ACTION_GOOFF;
1348 dongle_noa.option = WL_P2P_SCHED_OPTION_TSFOFS;
1349 }
1350 else {
1351 /* Continuous NoA interval. */
1352 dongle_noa.action = WL_P2P_SCHED_ACTION_NONE;
1353 dongle_noa.type = WL_P2P_SCHED_TYPE_ABS;
1354 if ((wl->p2p->noa.desc[0].interval == 102) ||
1355 (wl->p2p->noa.desc[0].interval == 100)) {
1356 wl->p2p->noa.desc[0].start = 100 -
1357 wl->p2p->noa.desc[0].duration;
1358 dongle_noa.option = WL_P2P_SCHED_OPTION_BCNPCT;
1359 }
1360 else {
1361 dongle_noa.option = WL_P2P_SCHED_OPTION_NORMAL;
1362 }
1363 }
1364 /* Put the noa descriptor in dongle format for dongle */
1365 dongle_noa.desc[0].count = htod32(wl->p2p->noa.desc[0].count);
1366 if (dongle_noa.option == WL_P2P_SCHED_OPTION_BCNPCT) {
1367 dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start);
1368 dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration);
1369 }
1370 else {
1371 dongle_noa.desc[0].start = htod32(wl->p2p->noa.desc[0].start*1000);
1372 dongle_noa.desc[0].duration = htod32(wl->p2p->noa.desc[0].duration*1000);
1373 }
1374 dongle_noa.desc[0].interval = htod32(wl->p2p->noa.desc[0].interval*1000);
1375
1376 ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
1377 "p2p_noa", &dongle_noa, sizeof(dongle_noa), ioctlbuf, sizeof(ioctlbuf));
1378
1379 if (ret < 0) {
1380 CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret));
1381 }
1382 }
1383 else {
1384 CFGP2P_ERR(("ERROR: set_noa in non-p2p mode\n"));
1385 }
1386 return ret;
1387}
1388
1389s32 wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len)
1390{
1391 wifi_p2p_noa_desc_t *noa_desc;
1392 int len = 0, i;
1393 char _buf[200];
1394
1395 CFGP2P_DBG((" Enter\n"));
1396 buf[0] = '\0';
1397 if (wl->p2p && wl->p2p->vif_created) {
1398 if (wl->p2p->noa.desc[0].count || wl->p2p->ops.ops) {
1399 _buf[0] = 1; /* noa index */
1400 _buf[1] = (wl->p2p->ops.ops ? 0x80: 0) |
1401 (wl->p2p->ops.ctw & 0x7f); /* ops + ctw */
1402 len += 2;
1403 if (wl->p2p->noa.desc[0].count) {
1404 noa_desc = (wifi_p2p_noa_desc_t*)&_buf[len];
1405 noa_desc->cnt_type = wl->p2p->noa.desc[0].count;
1406 noa_desc->duration = wl->p2p->noa.desc[0].duration;
1407 noa_desc->interval = wl->p2p->noa.desc[0].interval;
1408 noa_desc->start = wl->p2p->noa.desc[0].start;
1409 len += sizeof(wifi_p2p_noa_desc_t);
1410 }
1411 if (buf_len <= len * 2) {
1412 CFGP2P_ERR(("ERROR: buf_len %d in not enough for"
1413 "returning noa in string format\n", buf_len));
1414 return -1;
1415 }
1416 /* We have to convert the buffer data into ASCII strings */
1417 for (i = 0; i < len; i++) {
1418 sprintf(buf, "%02x", _buf[i]);
1419 buf += 2;
1420 }
1421 buf[i*2] = '\0';
1422 }
1423 }
1424 else {
1425 CFGP2P_ERR(("ERROR: get_noa in non-p2p mode\n"));
1426 return -1;
1427 }
1428 return len * 2;
1429}
1430
1431s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len)
1432{
1433 int ps, ctw;
1434 int ret = -1;
1435 s32 legacy_ps;
1436
1437 CFGP2P_DBG((" Enter\n"));
1438 if (wl->p2p && wl->p2p->vif_created) {
1439 sscanf(buf, "%d %d %d", &legacy_ps, &ps, &ctw);
1440 CFGP2P_DBG((" Enter legacy_ps %d ps %d ctw %d\n", legacy_ps, ps, ctw));
1441 if (ctw != -1) {
1442 wl->p2p->ops.ctw = ctw;
1443 ret = 0;
1444 }
1445 if (ps != -1) {
1446 wl->p2p->ops.ops = ps;
1447 ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
1448 "p2p_ops", &wl->p2p->ops, sizeof(wl->p2p->ops),
1449 ioctlbuf, sizeof(ioctlbuf));
1450 if (ret < 0) {
1451 CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret));
1452 }
1453 }
1454
1455 if (legacy_ps != -1) {
1456 s32 pm = legacy_ps ? PM_MAX : PM_OFF;
1457 ret = wldev_ioctl(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION),
1458 WLC_SET_PM, &pm, sizeof(pm), true);
1459 if (unlikely(ret)) {
1460 CFGP2P_ERR(("error (%d)\n", ret));
1461 }
1462 }
1463 }
1464 else {
1465 CFGP2P_ERR(("ERROR: set_p2p_ps in non-p2p mode\n"));
1466 ret = -1;
1467 }
1468 return ret;
1469}
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
new file mode 100644
index 00000000000..5a69168c6a3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h
@@ -0,0 +1,247 @@
1/*
2 * Linux cfgp2p driver
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wl_cfgp2p.h,v 1.1.4.1.2.8 2011/02/09 01:37:52 Exp $
25 */
26#ifndef _wl_cfgp2p_h_
27#define _wl_cfgp2p_h_
28#include <proto/802.11.h>
29#include <proto/p2p.h>
30
31struct wl_priv;
32extern u32 wl_dbg_level;
33
34/* Enumeration of the usages of the BSSCFGs used by the P2P Library. Do not
35 * confuse this with a bsscfg index. This value is an index into the
36 * saved_ie[] array of structures which in turn contains a bsscfg index field.
37 */
38typedef enum {
39 P2PAPI_BSSCFG_PRIMARY, /* maps to driver's primary bsscfg */
40 P2PAPI_BSSCFG_DEVICE, /* maps to driver's P2P device discovery bsscfg */
41 P2PAPI_BSSCFG_CONNECTION, /* maps to driver's P2P connection bsscfg */
42 P2PAPI_BSSCFG_MAX
43} p2p_bsscfg_type_t;
44
45#define IE_MAX_LEN 300
46/* Structure to hold all saved P2P and WPS IEs for a BSSCFG */
47struct p2p_saved_ie {
48 u8 p2p_probe_req_ie[IE_MAX_LEN];
49 u8 p2p_probe_res_ie[IE_MAX_LEN];
50 u8 p2p_assoc_req_ie[IE_MAX_LEN];
51 u8 p2p_assoc_res_ie[IE_MAX_LEN];
52 u8 p2p_beacon_ie[IE_MAX_LEN];
53 u32 p2p_probe_req_ie_len;
54 u32 p2p_probe_res_ie_len;
55 u32 p2p_assoc_req_ie_len;
56 u32 p2p_assoc_res_ie_len;
57 u32 p2p_beacon_ie_len;
58};
59
60struct p2p_bss {
61 u32 bssidx;
62 struct net_device *dev;
63 struct p2p_saved_ie saved_ie;
64 void *private_data;
65};
66
67struct p2p_info {
68 bool on; /* p2p on/off switch */
69 bool scan;
70 bool vif_created;
71 s8 vir_ifname[IFNAMSIZ];
72 unsigned long status;
73 struct ether_addr dev_addr;
74 struct ether_addr int_addr;
75 struct p2p_bss bss_idx[P2PAPI_BSSCFG_MAX];
76 struct timer_list listen_timer;
77 wl_p2p_sched_t noa;
78 wl_p2p_ops_t ops;
79 wlc_ssid_t ssid;
80 spinlock_t timer_lock;
81};
82
83/* dongle status */
84enum wl_cfgp2p_status {
85 WLP2P_STATUS_DISCOVERY_ON = 0,
86 WLP2P_STATUS_SEARCH_ENABLED,
87 WLP2P_STATUS_IF_ADD,
88 WLP2P_STATUS_IF_DEL,
89 WLP2P_STATUS_IF_DELETING,
90 WLP2P_STATUS_IF_CHANGING,
91 WLP2P_STATUS_IF_CHANGED,
92 WLP2P_STATUS_LISTEN_EXPIRED,
93 WLP2P_STATUS_ACTION_TX_COMPLETED,
94 WLP2P_STATUS_ACTION_TX_NOACK,
95 WLP2P_STATUS_SCANNING
96};
97
98
99#define wl_to_p2p_bss_ndev(w, type) ((wl)->p2p->bss_idx[type].dev)
100#define wl_to_p2p_bss_bssidx(w, type) ((wl)->p2p->bss_idx[type].bssidx)
101#define wl_to_p2p_bss_saved_ie(w, type) ((wl)->p2p->bss_idx[type].saved_ie)
102#define wl_to_p2p_bss_private(w, type) ((wl)->p2p->bss_idx[type].private_data)
103#define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type])
104#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \
105 &(wl)->p2p->status))
106#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : set_bit(WLP2P_STATUS_ ## stat, \
107 &(wl)->p2p->status))
108#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : clear_bit(WLP2P_STATUS_ ## stat, \
109 &(wl)->p2p->status))
110#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : change_bit(WLP2P_STATUS_ ## stat, \
111 &(wl)->p2p->status))
112#define p2p_on(wl) ((wl)->p2p->on)
113#define p2p_scan(wl) ((wl)->p2p->scan)
114#define p2p_is_on(wl) ((wl)->p2p && (wl)->p2p->on)
115
116/* dword align allocation */
117#define WLC_IOCTL_MAXLEN 8192
118#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
119#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
120
121#define CFGP2P_ERR(args) \
122 do { \
123 if (wl_dbg_level & WL_DBG_ERR) { \
124 printk(KERN_ERR "CFGP2P-ERROR) %s : ", __func__); \
125 printk args; \
126 } \
127 } while (0)
128#define CFGP2P_INFO(args) \
129 do { \
130 if (wl_dbg_level & WL_DBG_INFO) { \
131 printk(KERN_ERR "CFGP2P-INFO) %s : ", __func__); \
132 printk args; \
133 } \
134 } while (0)
135#define CFGP2P_DBG(args) \
136 do { \
137 if (wl_dbg_level & WL_DBG_DBG) { \
138 printk(KERN_ERR "CFGP2P-DEBUG) %s :", __func__); \
139 printk args; \
140 } \
141 } while (0)
142
143
144extern s32
145wl_cfgp2p_init_priv(struct wl_priv *wl);
146extern void
147wl_cfgp2p_deinit_priv(struct wl_priv *wl);
148extern s32
149wl_cfgp2p_set_firm_p2p(struct wl_priv *wl);
150extern s32
151wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode,
152 u32 channel, u16 listen_ms, int bssidx);
153extern s32
154wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type,
155 chanspec_t chspec);
156extern s32
157wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac);
158extern s32
159wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, chanspec_t chspec);
160
161extern s32
162wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index);
163
164extern s32
165wl_cfgp2p_init_discovery(struct wl_priv *wl);
166extern s32
167wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len);
168extern s32
169wl_cfgp2p_disable_discovery(struct wl_priv *wl);
170extern s32
171wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, u32 num_chans,
172 u16 *channels,
173 s32 search_state, u16 action, u32 bssidx);
174
175extern wpa_ie_fixed_t *
176wl_cfgp2p_find_wpaie(u8 *parse, u32 len);
177
178extern wpa_ie_fixed_t *
179wl_cfgp2p_find_wpsie(u8 *parse, u32 len);
180
181extern wifi_p2p_ie_t *
182wl_cfgp2p_find_p2pie(u8 *parse, u32 len);
183
184extern s32
185wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx,
186 s32 pktflag, const u8 *vndr_ie, u32 vndr_ie_len);
187extern s32
188wl_cfgp2p_clear_management_ie(struct wl_priv *wl, s32 bssidx);
189
190extern s32
191wl_cfgp2p_find_idx(struct wl_priv *wl, struct net_device *ndev);
192
193
194extern s32
195wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev,
196 const wl_event_msg_t *e, void *data);
197extern s32
198wl_cfgp2p_discover_listen(struct wl_priv *wl, s32 channel, u32 duration_ms);
199
200extern s32
201wl_cfgp2p_discover_enable_search(struct wl_priv *wl, u8 enable);
202
203extern s32
204wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev,
205 const wl_event_msg_t *e, void *data);
206extern s32
207wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev,
208 wl_af_params_t *af_params, s32 bssidx);
209
210extern void
211wl_cfgp2p_generate_bss_mac(struct ether_addr *primary_addr, struct ether_addr *out_dev_addr,
212 struct ether_addr *out_int_addr);
213
214extern void
215wl_cfg80211_change_ifaddr(u8* buf, struct ether_addr *p2p_int_addr, u8 element_id);
216extern bool
217wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx);
218
219extern s32
220wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up);
221
222
223extern s32
224wl_cfgp2p_supported(struct wl_priv *wl, struct net_device *ndev);
225
226extern s32
227wl_cfgp2p_down(struct wl_priv *wl);
228
229extern s32
230wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len);
231
232extern s32
233wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len);
234
235extern s32
236wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len);
237
238/* WiFi Direct */
239#define SOCIAL_CHAN_1 1
240#define SOCIAL_CHAN_2 6
241#define SOCIAL_CHAN_3 11
242#define WL_P2P_WILDCARD_SSID "DIRECT-"
243#define WL_P2P_WILDCARD_SSID_LEN 7
244#define WL_P2P_INTERFACE_PREFIX "p2p"
245#define WL_P2P_TEMP_CHAN "11"
246#define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0)
247#endif /* _wl_cfgp2p_h_ */
diff --git a/drivers/net/wireless/bcmdhd/wl_dbg.h b/drivers/net/wireless/bcmdhd/wl_dbg.h
new file mode 100644
index 00000000000..0b99557cbe8
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_dbg.h
@@ -0,0 +1,49 @@
1/*
2 * Minimal debug/trace/assert driver definitions for
3 * Broadcom 802.11 Networking Adapter.
4 *
5 * Copyright (C) 1999-2011, Broadcom Corporation
6 *
7 * Unless you and Broadcom execute a separate written software license
8 * agreement governing use of this software, this software is licensed to you
9 * under the terms of the GNU General Public License version 2 (the "GPL"),
10 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11 * following added to such license:
12 *
13 * As a special exception, the copyright holders of this software give you
14 * permission to link this software with independent modules, and to copy and
15 * distribute the resulting executable under terms of your choice, provided that
16 * you also meet, for each linked independent module, the terms and conditions of
17 * the license of that module. An independent module is a module which is not
18 * derived from this software. The special exception does not apply to any
19 * modifications of the software.
20 *
21 * Notwithstanding the above, under no circumstances may you combine this
22 * software in any way with any other Broadcom software provided under a license
23 * other than the GPL, without Broadcom's express prior written consent.
24 *
25 * $Id: wl_dbg.h,v 1.115.6.3 2010-12-15 21:42:23 Exp $
26 */
27
28
29
30#ifndef _wl_dbg_h_
31#define _wl_dbg_h_
32
33
34extern uint32 wl_msg_level;
35extern uint32 wl_msg_level2;
36
37#define WL_PRINT(args) printf args
38
39
40
41#define WL_NONE(args)
42
43#define WL_ERROR(args)
44#define WL_TRACE(args)
45
46
47extern uint32 wl_msg_level;
48extern uint32 wl_msg_level2;
49#endif
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c
new file mode 100644
index 00000000000..457372b62b3
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_iw.c
@@ -0,0 +1,8766 @@
1/*
2 * Linux Wireless Extensions support
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wl_iw.c,v 1.132.2.18 2011-02-05 01:44:47 Exp $
25 */
26
27#include <wlioctl.h>
28
29#include <typedefs.h>
30#include <linuxver.h>
31#include <osl.h>
32
33#include <bcmutils.h>
34#include <bcmendian.h>
35#include <proto/ethernet.h>
36
37#include <linux/if_arp.h>
38#include <asm/uaccess.h>
39
40#include <dngl_stats.h>
41#include <dhd.h>
42#include <dhdioctl.h>
43
44typedef void wlc_info_t;
45typedef void wl_info_t;
46typedef const struct si_pub si_t;
47#include <wlioctl.h>
48
49#include <proto/ethernet.h>
50#include <dngl_stats.h>
51#include <dhd.h>
52#define WL_ERROR(x) printf x
53#define WL_TRACE(x)
54#define WL_ASSOC(x)
55#define WL_INFORM(x)
56#define WL_WSEC(x)
57#define WL_SCAN(x)
58
59
60#ifdef PNO_SET_DEBUG
61#define WL_PNO(x) printf x
62#else
63#define WL_PNO(x)
64#endif
65
66
67#define JF2MS ((((jiffies / HZ) * 1000) + ((jiffies % HZ) * 1000) / HZ))
68
69#ifdef COEX_DBG
70#define WL_TRACE_COEX(x) printf("TS:%lu ", JF2MS); \
71 printf x
72#else
73#define WL_TRACE_COEX(x)
74#endif
75
76#ifdef SCAN_DBG
77#define WL_TRACE_SCAN(x) printf("TS:%lu ", JF2MS); \
78 printf x
79#else
80#define WL_TRACE_SCAN(x)
81#endif
82
83
84#include <wl_iw.h>
85
86
87
88
89#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
90
91#include <linux/rtnetlink.h>
92
93#define WL_IW_USE_ISCAN 1
94#define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 1
95
96#ifdef OEM_CHROMIUMOS
97bool g_set_essid_before_scan = TRUE;
98#endif
99
100#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
101 struct mutex g_wl_ss_scan_lock;
102#endif
103
104#if defined(SOFTAP)
105#define WL_SOFTAP(x)
106static struct net_device *priv_dev;
107extern bool ap_cfg_running;
108extern bool ap_fw_loaded;
109struct net_device *ap_net_dev = NULL;
110tsk_ctl_t ap_eth_ctl;
111static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap);
112static int wl_iw_softap_deassoc_stations(struct net_device *dev, u8 *mac);
113#endif
114
115
116#define WL_IW_IOCTL_CALL(func_call) \
117 do { \
118 func_call; \
119 } while (0)
120
121#define RETURN_IF_EXTRA_NULL(extra) \
122 if (!extra) { \
123 WL_ERROR(("%s: error : extra is null pointer\n", __FUNCTION__)); \
124 return -EINVAL; \
125 }
126
127static int g_onoff = G_WLAN_SET_ON;
128wl_iw_extra_params_t g_wl_iw_params;
129
130
131#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1
132
133static struct mutex wl_cache_lock;
134static struct mutex wl_softap_lock;
135
136#define DHD_OS_MUTEX_INIT(a) mutex_init(a)
137#define DHD_OS_MUTEX_LOCK(a) mutex_lock(a)
138#define DHD_OS_MUTEX_UNLOCK(a) mutex_unlock(a)
139
140#else
141
142#define DHD_OS_MUTEX_INIT(a)
143#define DHD_OS_MUTEX_LOCK(a)
144#define DHD_OS_MUTEX_UNLOCK(a)
145
146#endif
147
148#include <bcmsdbus.h>
149extern void dhd_customer_gpio_wlan_ctrl(int onoff);
150extern uint dhd_dev_reset(struct net_device *dev, uint8 flag);
151extern void dhd_dev_init_ioctl(struct net_device *dev);
152
153uint wl_msg_level = WL_ERROR_VAL;
154
155#define MAX_WLIW_IOCTL_LEN 1024
156
157
158#define htod32(i) i
159#define htod16(i) i
160#define dtoh32(i) i
161#define dtoh16(i) i
162#define htodchanspec(i) i
163#define dtohchanspec(i) i
164
165#ifdef CONFIG_WIRELESS_EXT
166
167extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
168extern int dhd_wait_pend8021x(struct net_device *dev);
169#endif
170
171#if WIRELESS_EXT < 19
172#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST)
173#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST)
174#endif
175
176static void *g_scan = NULL;
177static volatile uint g_scan_specified_ssid;
178static wlc_ssid_t g_specific_ssid;
179
180static wlc_ssid_t g_ssid;
181
182#ifdef CONFIG_WPS2
183static char *g_wps_probe_req_ie;
184static int g_wps_probe_req_ie_len;
185#endif
186
187bool btcoex_is_sco_active(struct net_device *dev);
188static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl;
189#if defined(CONFIG_FIRST_SCAN)
190static volatile uint g_first_broadcast_scan;
191static volatile uint g_first_counter_scans;
192#define MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN 3
193#endif
194
195#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
196#define DAEMONIZE(a) daemonize(a); \
197 allow_signal(SIGKILL); \
198 allow_signal(SIGTERM);
199#else
200#define RAISE_RX_SOFTIRQ() \
201 cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
202#define DAEMONIZE(a) daemonize(); \
203 do { if (a) \
204 strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
205 } while (0);
206#endif
207
208#if defined(WL_IW_USE_ISCAN)
209#if !defined(CSCAN)
210static void wl_iw_free_ss_cache(void);
211static int wl_iw_run_ss_cache_timer(int kick_off);
212#endif
213#if defined(CONFIG_FIRST_SCAN)
214int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag);
215#endif
216static int dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len);
217#define ISCAN_STATE_IDLE 0
218#define ISCAN_STATE_SCANING 1
219
220
221#define WLC_IW_ISCAN_MAXLEN 2048
222typedef struct iscan_buf {
223 struct iscan_buf * next;
224 char iscan_buf[WLC_IW_ISCAN_MAXLEN];
225} iscan_buf_t;
226
227typedef struct iscan_info {
228 struct net_device *dev;
229 struct timer_list timer;
230 uint32 timer_ms;
231 uint32 timer_on;
232 int iscan_state;
233 iscan_buf_t * list_hdr;
234 iscan_buf_t * list_cur;
235
236
237 tsk_ctl_t tsk_ctl;
238
239 uint32 scan_flag;
240#if defined CSCAN
241 char ioctlbuf[WLC_IOCTL_MEDLEN];
242#else
243 char ioctlbuf[WLC_IOCTL_SMLEN];
244#endif
245
246 wl_iscan_params_t *iscan_ex_params_p;
247 int iscan_ex_param_size;
248} iscan_info_t;
249
250
251
252#define COEX_DHCP 1
253#ifdef COEX_DHCP
254
255#define BT_DHCP_eSCO_FIX
256#define BT_DHCP_USE_FLAGS
257#define BT_DHCP_OPPORTUNITY_WINDOW_TIME 2500
258#define BT_DHCP_FLAG_FORCE_TIME 5500
259
260
261
262static int wl_iw_set_btcoex_dhcp(
263 struct net_device *dev,
264 struct iw_request_info *info,
265 union iwreq_data *wrqu,
266 char *extra
267);
268
269static void wl_iw_bt_flag_set(struct net_device *dev, bool set);
270static void wl_iw_bt_release(void);
271
272typedef enum bt_coex_status {
273 BT_DHCP_IDLE = 0,
274 BT_DHCP_START,
275 BT_DHCP_OPPORTUNITY_WINDOW,
276 BT_DHCP_FLAG_FORCE_TIMEOUT
277} coex_status_t;
278
279
280typedef struct bt_info {
281 struct net_device *dev;
282 struct timer_list timer;
283 uint32 timer_ms;
284 uint32 timer_on;
285 uint32 ts_dhcp_start;
286 uint32 ts_dhcp_ok;
287 bool dhcp_done;
288 int bt_state;
289
290
291 tsk_ctl_t tsk_ctl;
292
293} bt_info_t;
294
295bt_info_t *g_bt = NULL;
296static void wl_iw_bt_timerfunc(ulong data);
297#endif
298iscan_info_t *g_iscan = NULL;
299void dhd_print_buf(void *pbuf, int len, int bytes_per_line);
300static void wl_iw_timerfunc(ulong data);
301static void wl_iw_set_event_mask(struct net_device *dev);
302static int
303wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action);
304#endif
305
306static int
307wl_iw_set_scan(
308 struct net_device *dev,
309 struct iw_request_info *info,
310 union iwreq_data *wrqu,
311 char *extra
312);
313
314#ifndef CSCAN
315static int
316wl_iw_get_scan(
317 struct net_device *dev,
318 struct iw_request_info *info,
319 struct iw_point *dwrq,
320 char *extra
321);
322
323static uint
324wl_iw_get_scan_prep(
325 wl_scan_results_t *list,
326 struct iw_request_info *info,
327 char *extra,
328 short max_size
329);
330#endif
331
332static void
333swap_key_from_BE(
334 wl_wsec_key_t *key
335)
336{
337 key->index = htod32(key->index);
338 key->len = htod32(key->len);
339 key->algo = htod32(key->algo);
340 key->flags = htod32(key->flags);
341 key->rxiv.hi = htod32(key->rxiv.hi);
342 key->rxiv.lo = htod16(key->rxiv.lo);
343 key->iv_initialized = htod32(key->iv_initialized);
344}
345
346static void
347swap_key_to_BE(
348 wl_wsec_key_t *key
349)
350{
351 key->index = dtoh32(key->index);
352 key->len = dtoh32(key->len);
353 key->algo = dtoh32(key->algo);
354 key->flags = dtoh32(key->flags);
355 key->rxiv.hi = dtoh32(key->rxiv.hi);
356 key->rxiv.lo = dtoh16(key->rxiv.lo);
357 key->iv_initialized = dtoh32(key->iv_initialized);
358}
359
360static int
361dev_wlc_ioctl(
362 struct net_device *dev,
363 int cmd,
364 void *arg,
365 int len
366)
367{
368 struct ifreq ifr;
369 wl_ioctl_t ioc;
370 mm_segment_t fs;
371 int ret = -EINVAL;
372
373 if (!dev) {
374 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
375 return ret;
376 }
377
378 net_os_wake_lock(dev);
379
380 WL_INFORM(("%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n",
381 __FUNCTION__, current->pid, cmd, arg, len));
382
383 if (g_onoff == G_WLAN_SET_ON) {
384 memset(&ioc, 0, sizeof(ioc));
385 ioc.cmd = cmd;
386 ioc.buf = arg;
387 ioc.len = len;
388
389 strcpy(ifr.ifr_name, dev->name);
390 ifr.ifr_data = (caddr_t) &ioc;
391
392
393 ret = dev_open(dev);
394 if (ret) {
395 WL_ERROR(("%s: Error dev_open: %d\n", __func__, ret));
396 net_os_wake_unlock(dev);
397 return ret;
398 }
399
400 fs = get_fs();
401 set_fs(get_ds());
402#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)
403 ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
404#else
405 ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
406#endif
407 set_fs(fs);
408 }
409 else {
410 WL_TRACE(("%s: call after driver stop : ignored\n", __FUNCTION__));
411 }
412
413 net_os_wake_unlock(dev);
414
415 return ret;
416}
417
418
419static int
420dev_wlc_intvar_get_reg(
421 struct net_device *dev,
422 char *name,
423 uint reg,
424 int *retval)
425{
426 union {
427 char buf[WLC_IOCTL_SMLEN];
428 int val;
429 } var;
430 int error;
431
432 uint len;
433 len = bcm_mkiovar(name, (char *)(&reg), sizeof(reg), (char *)(&var), sizeof(var.buf));
434 ASSERT(len);
435 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
436
437 *retval = dtoh32(var.val);
438 return (error);
439}
440
441
442static int
443dev_wlc_intvar_set_reg(
444 struct net_device *dev,
445 char *name,
446 char *addr,
447 char * val)
448{
449 char reg_addr[8];
450
451 memset(reg_addr, 0, sizeof(reg_addr));
452 memcpy((char *)&reg_addr[0], (char *)addr, 4);
453 memcpy((char *)&reg_addr[4], (char *)val, 4);
454
455 return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
456}
457
458
459
460
461static int
462dev_wlc_intvar_set(
463 struct net_device *dev,
464 char *name,
465 int val)
466{
467 char buf[WLC_IOCTL_SMLEN];
468 uint len;
469
470 val = htod32(val);
471 len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
472 ASSERT(len);
473
474 return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len));
475}
476
477#if defined(WL_IW_USE_ISCAN)
478static int
479dev_iw_iovar_setbuf(
480 struct net_device *dev,
481 char *iovar,
482 void *param,
483 int paramlen,
484 void *bufptr,
485 int buflen)
486{
487 int iolen;
488
489 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
490 ASSERT(iolen);
491
492 if (iolen == 0)
493 return 0;
494
495 return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen));
496}
497
498static int
499dev_iw_iovar_getbuf(
500 struct net_device *dev,
501 char *iovar,
502 void *param,
503 int paramlen,
504 void *bufptr,
505 int buflen)
506{
507 int iolen;
508
509 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
510 ASSERT(iolen);
511
512 return (dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen));
513}
514#endif
515
516
517#if WIRELESS_EXT > 17
518static int
519dev_wlc_bufvar_set(
520 struct net_device *dev,
521 char *name,
522 char *buf, int len)
523{
524#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
525 char ioctlbuf[MAX_WLIW_IOCTL_LEN];
526#else
527 static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
528#endif
529 uint buflen;
530
531 buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
532 ASSERT(buflen);
533
534 return (dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen));
535}
536#endif
537
538
539static int
540dev_wlc_bufvar_get(
541 struct net_device *dev,
542 char *name,
543 char *buf, int buflen)
544{
545#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
546 char ioctlbuf[MAX_WLIW_IOCTL_LEN];
547#else
548 static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
549#endif
550 int error;
551 uint len;
552
553 len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf));
554 ASSERT(len);
555 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_WLIW_IOCTL_LEN);
556 if (!error)
557 bcopy(ioctlbuf, buf, buflen);
558
559 return (error);
560}
561
562
563
564static int
565dev_wlc_intvar_get(
566 struct net_device *dev,
567 char *name,
568 int *retval)
569{
570 union {
571 char buf[WLC_IOCTL_SMLEN];
572 int val;
573 } var;
574 int error;
575
576 uint len;
577 uint data_null;
578
579 len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf));
580 ASSERT(len);
581 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
582
583 *retval = dtoh32(var.val);
584
585 return (error);
586}
587
588
589#if WIRELESS_EXT > 12
590static int
591wl_iw_set_active_scan(
592 struct net_device *dev,
593 struct iw_request_info *info,
594 union iwreq_data *wrqu,
595 char *extra
596)
597{
598 int as = 0;
599 int error = 0;
600 char *p = extra;
601
602#if defined(WL_IW_USE_ISCAN)
603 if (g_iscan->iscan_state == ISCAN_STATE_IDLE)
604#endif
605 error = dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as));
606#if defined(WL_IW_USE_ISCAN)
607 else
608 g_iscan->scan_flag = as;
609#endif
610 p += snprintf(p, MAX_WX_STRING, "OK");
611
612 wrqu->data.length = p - extra + 1;
613 return error;
614}
615
616static int
617wl_iw_set_passive_scan(
618 struct net_device *dev,
619 struct iw_request_info *info,
620 union iwreq_data *wrqu,
621 char *extra
622)
623{
624 int ps = 1;
625 int error = 0;
626 char *p = extra;
627
628#if defined(WL_IW_USE_ISCAN)
629 if (g_iscan->iscan_state == ISCAN_STATE_IDLE) {
630#endif
631
632
633 if (g_scan_specified_ssid == 0) {
634 error = dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &ps, sizeof(ps));
635 }
636#if defined(WL_IW_USE_ISCAN)
637 }
638 else
639 g_iscan->scan_flag = ps;
640#endif
641
642 p += snprintf(p, MAX_WX_STRING, "OK");
643
644 wrqu->data.length = p - extra + 1;
645 return error;
646}
647
648
649static int
650wl_iw_set_txpower(
651 struct net_device *dev,
652 struct iw_request_info *info,
653 union iwreq_data *wrqu,
654 char *extra
655)
656{
657 int error = 0;
658 char *p = extra;
659 int txpower = -1;
660
661 txpower = bcm_atoi(extra + strlen(TXPOWER_SET_CMD) + 1);
662 if ((txpower >= 0) && (txpower <= 127))
663 {
664 txpower |= WL_TXPWR_OVERRIDE;
665 txpower = htod32(txpower);
666
667 error = dev_wlc_intvar_set(dev, "qtxpower", txpower);
668 p += snprintf(p, MAX_WX_STRING, "OK");
669 WL_TRACE(("%s: set TXpower 0x%X is OK\n", __FUNCTION__, txpower));
670 } else {
671 WL_ERROR(("%s: set tx power failed\n", __FUNCTION__));
672 p += snprintf(p, MAX_WX_STRING, "FAIL");
673 }
674
675 wrqu->data.length = p - extra + 1;
676 return error;
677}
678
679static int
680wl_iw_get_macaddr(
681 struct net_device *dev,
682 struct iw_request_info *info,
683 union iwreq_data *wrqu,
684 char *extra
685)
686{
687 int error;
688 char buf[128];
689 struct ether_addr *id;
690 char *p = extra;
691
692
693 strcpy(buf, "cur_etheraddr");
694 error = dev_wlc_ioctl(dev, WLC_GET_VAR, buf, sizeof(buf));
695 id = (struct ether_addr *) buf;
696 p += snprintf(p, MAX_WX_STRING, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
697 id->octet[0], id->octet[1], id->octet[2],
698 id->octet[3], id->octet[4], id->octet[5]);
699 wrqu->data.length = p - extra + 1;
700
701 return error;
702}
703
704
705
706static int
707wl_iw_set_country(
708 struct net_device *dev,
709 struct iw_request_info *info,
710 union iwreq_data *wrqu,
711 char *extra
712)
713{
714 char country_code[WLC_CNTRY_BUF_SZ];
715 int error = 0;
716 char *p = extra;
717 int country_offset;
718 int country_code_size;
719 wl_country_t cspec = {{0}, 0, {0}};
720 char smbuf[WLC_IOCTL_SMLEN];
721 scb_val_t scbval;
722
723 cspec.rev = -1;
724 memset(country_code, 0, sizeof(country_code));
725 memset(smbuf, 0, sizeof(smbuf));
726
727
728 country_offset = strcspn(extra, " ");
729 country_code_size = strlen(extra) - country_offset;
730
731
732 if (country_offset != 0) {
733 strncpy(country_code, extra + country_offset +1,
734 MIN(country_code_size, sizeof(country_code)));
735
736
737 bzero(&scbval, sizeof(scb_val_t));
738 if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) {
739 WL_ERROR(("%s: set country failed due to Disassoc error\n", __FUNCTION__));
740 goto exit_failed;
741 }
742
743 memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
744 memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
745
746 get_customized_country_code((char *)&cspec.country_abbrev, &cspec);
747
748
749 if ((error = dev_iw_iovar_setbuf(dev, "country", &cspec,
750 sizeof(cspec), smbuf, sizeof(smbuf))) >= 0) {
751 p += snprintf(p, MAX_WX_STRING, "OK");
752 WL_ERROR(("%s: set country for %s as %s rev %d is OK\n",
753 __FUNCTION__, country_code, cspec.ccode, cspec.rev));
754 dhd_bus_country_set(dev, &cspec);
755 goto exit;
756 }
757 }
758
759 WL_ERROR(("%s: set country for %s as %s rev %d failed\n",
760 __FUNCTION__, country_code, cspec.ccode, cspec.rev));
761
762exit_failed:
763 p += snprintf(p, MAX_WX_STRING, "FAIL");
764
765exit:
766 wrqu->data.length = p - extra + 1;
767 return error;
768}
769
770static int
771wl_iw_set_power_mode(
772 struct net_device *dev,
773 struct iw_request_info *info,
774 union iwreq_data *wrqu,
775 char *extra
776)
777{
778 int error = 0;
779 char *p = extra;
780 static int pm = PM_FAST;
781 int pm_local = PM_OFF;
782 char powermode_val = 0;
783
784 WL_TRACE_COEX(("%s: DHCP session cmd:%s\n", __FUNCTION__, extra));
785
786 strncpy((char *)&powermode_val, extra + strlen("POWERMODE") +1, 1);
787
788 if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
789
790 WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
791
792 dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm));
793 dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local));
794
795
796 net_os_set_packet_filter(dev, 0);
797
798#ifdef COEX_DHCP
799 g_bt->ts_dhcp_start = JF2MS;
800 g_bt->dhcp_done = FALSE;
801 WL_TRACE_COEX(("%s: DHCP start, pm:%d changed to pm:%d\n",
802 __FUNCTION__, pm, pm_local));
803
804#endif
805 } else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) {
806
807
808 dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
809
810
811 net_os_set_packet_filter(dev, 1);
812
813#ifdef COEX_DHCP
814 g_bt->dhcp_done = TRUE;
815 g_bt->ts_dhcp_ok = JF2MS;
816 WL_TRACE_COEX(("%s: DHCP done for:%d ms, restored pm:%d\n",
817 __FUNCTION__, (g_bt->ts_dhcp_ok - g_bt->ts_dhcp_start), pm));
818#endif
819
820 } else {
821 WL_ERROR(("%s Unkwown yet power setting, ignored\n",
822 __FUNCTION__));
823 }
824
825 p += snprintf(p, MAX_WX_STRING, "OK");
826
827 wrqu->data.length = p - extra + 1;
828
829 return error;
830}
831
832
833bool btcoex_is_sco_active(struct net_device *dev)
834{
835 int ioc_res = 0;
836 bool res = FALSE;
837 int sco_id_cnt = 0;
838 int param27;
839 int i;
840
841 for (i = 0; i < 12; i++) {
842
843 ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
844
845 WL_TRACE_COEX(("%s, sample[%d], btc params: 27:%x\n",
846 __FUNCTION__, i, param27));
847
848 if (ioc_res < 0) {
849 WL_ERROR(("%s ioc read btc params error\n", __FUNCTION__));
850 break;
851 }
852
853 if ((param27 & 0x6) == 2) {
854 sco_id_cnt++;
855 }
856
857 if (sco_id_cnt > 2) {
858 WL_TRACE_COEX(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n",
859 __FUNCTION__, sco_id_cnt, i));
860 res = TRUE;
861 break;
862 }
863
864 msleep(5);
865 }
866
867 return res;
868}
869
870#if defined(BT_DHCP_eSCO_FIX)
871
872static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
873{
874 static bool saved_status = FALSE;
875
876 char buf_reg50va_dhcp_on[8] = { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
877 char buf_reg51va_dhcp_on[8] = { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
878 char buf_reg64va_dhcp_on[8] = { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
879 char buf_reg65va_dhcp_on[8] = { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
880 char buf_reg71va_dhcp_on[8] = { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
881
882 uint32 regaddr;
883 static uint32 saved_reg50;
884 static uint32 saved_reg51;
885 static uint32 saved_reg64;
886 static uint32 saved_reg65;
887 static uint32 saved_reg71;
888
889 if (trump_sco) {
890
891
892 WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n"));
893
894
895 if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
896 (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
897 (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
898 (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
899 (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
900
901 saved_status = TRUE;
902 WL_TRACE_COEX(("%s saved bt_params[50,51,64,65,71]:"
903 " 0x%x 0x%x 0x%x 0x%x 0x%x\n",
904 __FUNCTION__, saved_reg50, saved_reg51,
905 saved_reg64, saved_reg65, saved_reg71));
906
907 } else {
908 WL_ERROR((":%s: save btc_params failed\n",
909 __FUNCTION__));
910 saved_status = FALSE;
911 return -1;
912 }
913
914 WL_TRACE_COEX(("override with [50,51,64,65,71]:"
915 " 0x%x 0x%x 0x%x 0x%x 0x%x\n",
916 *(u32 *)(buf_reg50va_dhcp_on+4),
917 *(u32 *)(buf_reg51va_dhcp_on+4),
918 *(u32 *)(buf_reg64va_dhcp_on+4),
919 *(u32 *)(buf_reg65va_dhcp_on+4),
920 *(u32 *)(buf_reg71va_dhcp_on+4)));
921
922 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg50va_dhcp_on[0], 8);
923 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg51va_dhcp_on[0], 8);
924 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg64va_dhcp_on[0], 8);
925 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg65va_dhcp_on[0], 8);
926 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg71va_dhcp_on[0], 8);
927
928 saved_status = TRUE;
929
930 } else if (saved_status) {
931
932 WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n"));
933
934 regaddr = 50;
935 dev_wlc_intvar_set_reg(dev, "btc_params",
936 (char *)&regaddr, (char *)&saved_reg50);
937 regaddr = 51;
938 dev_wlc_intvar_set_reg(dev, "btc_params",
939 (char *)&regaddr, (char *)&saved_reg51);
940 regaddr = 64;
941 dev_wlc_intvar_set_reg(dev, "btc_params",
942 (char *)&regaddr, (char *)&saved_reg64);
943 regaddr = 65;
944 dev_wlc_intvar_set_reg(dev, "btc_params",
945 (char *)&regaddr, (char *)&saved_reg65);
946 regaddr = 71;
947 dev_wlc_intvar_set_reg(dev, "btc_params",
948 (char *)&regaddr, (char *)&saved_reg71);
949
950 WL_TRACE_COEX(("restore bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
951 saved_reg50, saved_reg51, saved_reg64,
952 saved_reg65, saved_reg71));
953
954 saved_status = FALSE;
955 } else {
956 WL_ERROR((":%s att to restore not saved BTCOEX params\n",
957 __FUNCTION__));
958 return -1;
959 }
960 return 0;
961}
962#endif
963
964
965static int
966wl_iw_get_power_mode(
967 struct net_device *dev,
968 struct iw_request_info *info,
969 union iwreq_data *wrqu,
970 char *extra
971)
972{
973 int error = 0;
974 int pm_local;
975 char *p = extra;
976
977 error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm_local, sizeof(pm_local));
978 if (!error) {
979 WL_TRACE(("%s: Powermode = %d\n", __func__, pm_local));
980 if (pm_local == PM_OFF)
981 pm_local = 1;
982 else
983 pm_local = 0;
984 p += snprintf(p, MAX_WX_STRING, "powermode = %d", pm_local);
985 }
986 else {
987 WL_TRACE(("%s: Error = %d\n", __func__, error));
988 p += snprintf(p, MAX_WX_STRING, "FAIL");
989 }
990 wrqu->data.length = p - extra + 1;
991 return error;
992}
993
994static int
995wl_iw_set_btcoex_dhcp(
996 struct net_device *dev,
997 struct iw_request_info *info,
998 union iwreq_data *wrqu,
999 char *extra
1000)
1001{
1002 int error = 0;
1003 char *p = extra;
1004 char powermode_val = 0;
1005 char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
1006 char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
1007 char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
1008
1009 uint32 regaddr;
1010 static uint32 saved_reg66;
1011 static uint32 saved_reg41;
1012 static uint32 saved_reg68;
1013 static bool saved_status = FALSE;
1014
1015#ifdef COEX_DHCP
1016 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
1017#endif
1018
1019
1020 strncpy((char *)&powermode_val, extra + strlen("BTCOEXMODE") +1, 1);
1021
1022 if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
1023
1024 WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
1025
1026
1027 if ((saved_status == FALSE) &&
1028 (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
1029 (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
1030 (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
1031 saved_status = TRUE;
1032 WL_TRACE(("Saved 0x%x 0x%x 0x%x\n",
1033 saved_reg66, saved_reg41, saved_reg68));
1034
1035
1036
1037
1038#ifdef COEX_DHCP
1039
1040 if (btcoex_is_sco_active(dev)) {
1041
1042 dev_wlc_bufvar_set(dev, "btc_params",
1043 (char *)&buf_reg66va_dhcp_on[0],
1044 sizeof(buf_reg66va_dhcp_on));
1045
1046 dev_wlc_bufvar_set(dev, "btc_params",
1047 (char *)&buf_reg41va_dhcp_on[0],
1048 sizeof(buf_reg41va_dhcp_on));
1049
1050 dev_wlc_bufvar_set(dev, "btc_params",
1051 (char *)&buf_reg68va_dhcp_on[0],
1052 sizeof(buf_reg68va_dhcp_on));
1053 saved_status = TRUE;
1054
1055 g_bt->bt_state = BT_DHCP_START;
1056 g_bt->timer_on = 1;
1057 mod_timer(&g_bt->timer, g_bt->timer.expires);
1058 WL_TRACE_COEX(("%s enable BT DHCP Timer\n",
1059 __FUNCTION__));
1060 }
1061#endif
1062 }
1063 else if (saved_status == TRUE) {
1064 WL_ERROR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
1065 }
1066 }
1067 else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
1068
1069
1070
1071
1072#ifdef COEX_DHCP
1073
1074 WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
1075 if (g_bt->timer_on) {
1076 g_bt->timer_on = 0;
1077 del_timer_sync(&g_bt->timer);
1078
1079 if (g_bt->bt_state != BT_DHCP_IDLE) {
1080
1081 WL_TRACE_COEX(("%s bt->bt_state:%d\n",
1082 __FUNCTION__, g_bt->bt_state));
1083
1084 up(&g_bt->tsk_ctl.sema);
1085 }
1086 }
1087
1088
1089 if (saved_status == TRUE)
1090 dev_wlc_bufvar_set(dev, "btc_flags",
1091 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
1092#endif
1093
1094
1095 if (saved_status == TRUE) {
1096 regaddr = 66;
1097 dev_wlc_intvar_set_reg(dev, "btc_params",
1098 (char *)&regaddr, (char *)&saved_reg66);
1099 regaddr = 41;
1100 dev_wlc_intvar_set_reg(dev, "btc_params",
1101 (char *)&regaddr, (char *)&saved_reg41);
1102 regaddr = 68;
1103 dev_wlc_intvar_set_reg(dev, "btc_params",
1104 (char *)&regaddr, (char *)&saved_reg68);
1105
1106 WL_TRACE_COEX(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n",
1107 saved_reg66, saved_reg41, saved_reg68));
1108 }
1109 saved_status = FALSE;
1110
1111 }
1112 else {
1113 WL_ERROR(("%s Unkwown yet power setting, ignored\n",
1114 __FUNCTION__));
1115 }
1116
1117 p += snprintf(p, MAX_WX_STRING, "OK");
1118
1119 wrqu->data.length = p - extra + 1;
1120
1121 return error;
1122}
1123
1124static int
1125wl_iw_set_suspend(
1126struct net_device *dev,
1127struct iw_request_info *info,
1128union iwreq_data *wrqu,
1129char *extra
1130)
1131{
1132 int suspend_flag;
1133 int ret_now;
1134 int ret = 0;
1135
1136 suspend_flag = *(extra + strlen(SETSUSPEND_CMD) + 1) - '0';
1137
1138 if (suspend_flag != 0)
1139 suspend_flag = 1;
1140
1141 ret_now = net_os_set_suspend_disable(dev, suspend_flag);
1142
1143
1144 if (ret_now != suspend_flag) {
1145 if (!(ret = net_os_set_suspend(dev, ret_now)))
1146 WL_ERROR(("%s: Suspend Flag %d -> %d\n",
1147 __FUNCTION__, ret_now, suspend_flag));
1148 else
1149 WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1150 }
1151
1152 return ret;
1153}
1154
1155static int
1156wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len)
1157{
1158 int i, c;
1159 char *p = ssid_buf;
1160
1161 if (ssid_len > 32) ssid_len = 32;
1162
1163 for (i = 0; i < ssid_len; i++) {
1164 c = (int)ssid[i];
1165 if (c == '\\') {
1166 *p++ = '\\';
1167 *p++ = '\\';
1168 } else if (isprint((uchar)c)) {
1169 *p++ = (char)c;
1170 } else {
1171 p += sprintf(p, "\\x%02X", c);
1172 }
1173 }
1174 *p = '\0';
1175
1176 return p - ssid_buf;
1177}
1178
1179static int
1180wl_iw_get_link_speed(
1181 struct net_device *dev,
1182 struct iw_request_info *info,
1183 union iwreq_data *wrqu,
1184 char *extra
1185)
1186{
1187 int error = 0;
1188 char *p = extra;
1189 static int link_speed;
1190
1191
1192 net_os_wake_lock(dev);
1193 if (g_onoff == G_WLAN_SET_ON) {
1194 error = dev_wlc_ioctl(dev, WLC_GET_RATE, &link_speed, sizeof(link_speed));
1195 link_speed *= 500000;
1196 }
1197
1198 p += snprintf(p, MAX_WX_STRING, "LinkSpeed %d", link_speed/1000000);
1199
1200 wrqu->data.length = p - extra + 1;
1201
1202 net_os_wake_unlock(dev);
1203 return error;
1204}
1205
1206
1207static int
1208wl_iw_get_dtim_skip(
1209 struct net_device *dev,
1210 struct iw_request_info *info,
1211 union iwreq_data *wrqu,
1212 char *extra
1213)
1214{
1215 int error = -1;
1216 char *p = extra;
1217 char iovbuf[32];
1218
1219 net_os_wake_lock(dev);
1220 if (g_onoff == G_WLAN_SET_ON) {
1221
1222 memset(iovbuf, 0, sizeof(iovbuf));
1223 strcpy(iovbuf, "bcn_li_dtim");
1224
1225 if ((error = dev_wlc_ioctl(dev, WLC_GET_VAR,
1226 &iovbuf, sizeof(iovbuf))) >= 0) {
1227
1228 p += snprintf(p, MAX_WX_STRING, "Dtim_skip %d", iovbuf[0]);
1229 WL_TRACE(("%s: get dtim_skip = %d\n", __FUNCTION__, iovbuf[0]));
1230 wrqu->data.length = p - extra + 1;
1231 }
1232 else
1233 WL_ERROR(("%s: get dtim_skip failed code %d\n",
1234 __FUNCTION__, error));
1235 }
1236 net_os_wake_unlock(dev);
1237 return error;
1238}
1239
1240
1241static int
1242wl_iw_set_dtim_skip(
1243 struct net_device *dev,
1244 struct iw_request_info *info,
1245 union iwreq_data *wrqu,
1246 char *extra
1247)
1248{
1249 int error = -1;
1250 char *p = extra;
1251 int bcn_li_dtim;
1252 char iovbuf[32];
1253
1254 net_os_wake_lock(dev);
1255 if (g_onoff == G_WLAN_SET_ON) {
1256
1257 bcn_li_dtim = htod32((uint)*(extra + strlen(DTIM_SKIP_SET_CMD) + 1) - '0');
1258
1259 if ((bcn_li_dtim >= 0) || ((bcn_li_dtim <= 5))) {
1260
1261 memset(iovbuf, 0, sizeof(iovbuf));
1262 bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
1263 4, iovbuf, sizeof(iovbuf));
1264
1265 if ((error = dev_wlc_ioctl(dev, WLC_SET_VAR,
1266 &iovbuf, sizeof(iovbuf))) >= 0) {
1267 p += snprintf(p, MAX_WX_STRING, "OK");
1268
1269
1270 net_os_set_dtim_skip(dev, bcn_li_dtim);
1271
1272 WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__,
1273 bcn_li_dtim));
1274 goto exit;
1275 }
1276 else WL_ERROR(("%s: set dtim_skip %d failed code %d\n",
1277 __FUNCTION__, bcn_li_dtim, error));
1278 }
1279 else WL_ERROR(("%s Incorrect dtim_skip setting %d, ignored\n",
1280 __FUNCTION__, bcn_li_dtim));
1281 }
1282
1283 p += snprintf(p, MAX_WX_STRING, "FAIL");
1284
1285exit:
1286 wrqu->data.length = p - extra + 1;
1287 net_os_wake_unlock(dev);
1288 return error;
1289}
1290
1291
1292static int
1293wl_iw_get_band(
1294 struct net_device *dev,
1295 struct iw_request_info *info,
1296 union iwreq_data *wrqu,
1297 char *extra
1298)
1299{
1300 int error = -1;
1301 char *p = extra;
1302 static int band;
1303
1304 net_os_wake_lock(dev);
1305
1306 if (g_onoff == G_WLAN_SET_ON) {
1307 error = dev_wlc_ioctl(dev, WLC_GET_BAND, &band, sizeof(band));
1308
1309 p += snprintf(p, MAX_WX_STRING, "Band %d", band);
1310
1311 wrqu->data.length = p - extra + 1;
1312 }
1313
1314 net_os_wake_unlock(dev);
1315 return error;
1316}
1317
1318
1319static int
1320wl_iw_set_band(
1321 struct net_device *dev,
1322 struct iw_request_info *info,
1323 union iwreq_data *wrqu,
1324 char *extra
1325)
1326{
1327 int error = -1;
1328 char *p = extra;
1329 uint band;
1330
1331 net_os_wake_lock(dev);
1332
1333 if (g_onoff == G_WLAN_SET_ON) {
1334
1335 band = htod32((uint)*(extra + strlen(BAND_SET_CMD) + 1) - '0');
1336
1337 if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) {
1338
1339 if ((error = dev_wlc_ioctl(dev, WLC_SET_BAND,
1340 &band, sizeof(band))) >= 0) {
1341 p += snprintf(p, MAX_WX_STRING, "OK");
1342 WL_TRACE(("%s: set band %d OK\n", __FUNCTION__, band));
1343 goto exit;
1344 } else {
1345 WL_ERROR(("%s: set band %d failed code %d\n", __FUNCTION__,
1346 band, error));
1347 }
1348 } else {
1349 WL_ERROR(("%s Incorrect band setting %d, ignored\n", __FUNCTION__, band));
1350 }
1351 }
1352
1353 p += snprintf(p, MAX_WX_STRING, "FAIL");
1354
1355exit:
1356 wrqu->data.length = p - extra + 1;
1357 net_os_wake_unlock(dev);
1358 return error;
1359}
1360
1361#ifdef PNO_SUPPORT
1362
1363static int
1364wl_iw_set_pno_reset(
1365 struct net_device *dev,
1366 struct iw_request_info *info,
1367 union iwreq_data *wrqu,
1368 char *extra
1369)
1370{
1371 int error = -1;
1372 char *p = extra;
1373
1374 net_os_wake_lock(dev);
1375 if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) {
1376
1377 if ((error = dhd_dev_pno_reset(dev)) >= 0) {
1378 p += snprintf(p, MAX_WX_STRING, "OK");
1379 WL_TRACE(("%s: set OK\n", __FUNCTION__));
1380 goto exit;
1381 }
1382 else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error));
1383 }
1384
1385 p += snprintf(p, MAX_WX_STRING, "FAIL");
1386
1387exit:
1388 wrqu->data.length = p - extra + 1;
1389 net_os_wake_unlock(dev);
1390 return error;
1391}
1392
1393
1394
1395static int
1396wl_iw_set_pno_enable(
1397 struct net_device *dev,
1398 struct iw_request_info *info,
1399 union iwreq_data *wrqu,
1400 char *extra
1401)
1402{
1403 int error = -1;
1404 char *p = extra;
1405 int pfn_enabled;
1406
1407 net_os_wake_lock(dev);
1408 pfn_enabled = htod32((uint)*(extra + strlen(PNOENABLE_SET_CMD) + 1) - '0');
1409
1410 if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) {
1411
1412 if ((error = dhd_dev_pno_enable(dev, pfn_enabled)) >= 0) {
1413 p += snprintf(p, MAX_WX_STRING, "OK");
1414 WL_TRACE(("%s: set OK\n", __FUNCTION__));
1415 goto exit;
1416 }
1417 else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error));
1418 }
1419
1420 p += snprintf(p, MAX_WX_STRING, "FAIL");
1421
1422exit:
1423 wrqu->data.length = p - extra + 1;
1424 net_os_wake_unlock(dev);
1425 return error;
1426}
1427
1428
1429
1430static int
1431wl_iw_set_pno_set(
1432 struct net_device *dev,
1433 struct iw_request_info *info,
1434 union iwreq_data *wrqu,
1435 char *extra
1436)
1437{
1438 int res = -1;
1439 wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
1440 int nssid = 0;
1441 cmd_tlv_t *cmd_tlv_temp;
1442 char *str_ptr;
1443 int tlv_size_left;
1444 int pno_time;
1445 int pno_repeat;
1446 int pno_freq_expo_max;
1447#ifdef PNO_SET_DEBUG
1448 int i;
1449 char pno_in_example[] = {
1450 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
1451 'S', '1', '2', '0',
1452 'S',
1453 0x04,
1454 'B', 'R', 'C', 'M',
1455 'S',
1456 0x04,
1457 'G', 'O', 'O', 'G',
1458 'T',
1459 '1', 'E',
1460 'R',
1461 '2',
1462 'M',
1463 '2',
1464 0x00
1465 };
1466#endif
1467
1468 net_os_wake_lock(dev);
1469 WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
1470 __FUNCTION__, info->cmd, info->flags,
1471 wrqu->data.pointer, wrqu->data.length));
1472
1473 if (g_onoff == G_WLAN_SET_OFF) {
1474 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
1475 goto exit_proc;
1476 }
1477
1478 if (wrqu->data.length < (strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))) {
1479 WL_ERROR(("%s argument=%d less %d\n", __FUNCTION__,
1480 wrqu->data.length, (int)(strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))));
1481 goto exit_proc;
1482 }
1483
1484#ifdef PNO_SET_DEBUG
1485 if (!(extra = kmalloc(sizeof(pno_in_example) +100, GFP_KERNEL))) {
1486 res = -ENOMEM;
1487 goto exit_proc;
1488 }
1489 memcpy(extra, pno_in_example, sizeof(pno_in_example));
1490 wrqu->data.length = sizeof(pno_in_example);
1491 for (i = 0; i < wrqu->data.length; i++)
1492 printf("%02X ", extra[i]);
1493 printf("\n");
1494#endif
1495
1496 str_ptr = extra;
1497#ifdef PNO_SET_DEBUG
1498 str_ptr += strlen("PNOSETUP ");
1499 tlv_size_left = wrqu->data.length - strlen("PNOSETUP ");
1500#else
1501 str_ptr += strlen(PNOSETUP_SET_CMD);
1502 tlv_size_left = wrqu->data.length - strlen(PNOSETUP_SET_CMD);
1503#endif
1504
1505 cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
1506 memset(ssids_local, 0, sizeof(ssids_local));
1507 pno_repeat = pno_freq_expo_max = 0;
1508
1509 if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
1510 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
1511 (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION))
1512 {
1513 str_ptr += sizeof(cmd_tlv_t);
1514 tlv_size_left -= sizeof(cmd_tlv_t);
1515
1516
1517 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
1518 MAX_PFN_LIST_COUNT,
1519 &tlv_size_left)) <= 0) {
1520 WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
1521 goto exit_proc;
1522 }
1523 else {
1524 if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
1525 WL_ERROR(("%s scan duration corrupted field size %d\n",
1526 __FUNCTION__, tlv_size_left));
1527 goto exit_proc;
1528 }
1529 str_ptr++;
1530 pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
1531 WL_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
1532
1533
1534 if (str_ptr[0] != 0) {
1535 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
1536 WL_ERROR(("%s pno repeat : corrupted field\n",
1537 __FUNCTION__));
1538 goto exit_proc;
1539 }
1540 str_ptr++;
1541 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
1542 WL_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
1543 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
1544 WL_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n",
1545 __FUNCTION__));
1546 goto exit_proc;
1547 }
1548 str_ptr++;
1549 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
1550 WL_PNO(("%s: pno_freq_expo_max=%d\n",
1551 __FUNCTION__, pno_freq_expo_max));
1552 }
1553 }
1554 }
1555 else {
1556 WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
1557 goto exit_proc;
1558 }
1559
1560
1561 res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
1562
1563exit_proc:
1564 net_os_wake_unlock(dev);
1565 return res;
1566}
1567#endif
1568
1569static int
1570wl_iw_get_rssi(
1571 struct net_device *dev,
1572 struct iw_request_info *info,
1573 union iwreq_data *wrqu,
1574 char *extra
1575)
1576{
1577 static int rssi = 0;
1578 static wlc_ssid_t ssid = {0};
1579 int error = 0;
1580 char *p = extra;
1581 static char ssidbuf[SSID_FMT_BUF_LEN];
1582 scb_val_t scb_val;
1583
1584 net_os_wake_lock(dev);
1585
1586 bzero(&scb_val, sizeof(scb_val_t));
1587
1588 if (g_onoff == G_WLAN_SET_ON) {
1589 error = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
1590 if (error) {
1591 WL_ERROR(("%s: Fails %d\n", __FUNCTION__, error));
1592 net_os_wake_unlock(dev);
1593 return error;
1594 }
1595 rssi = dtoh32(scb_val.val);
1596
1597 error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
1598 if (!error) {
1599 ssid.SSID_len = dtoh32(ssid.SSID_len);
1600 wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len));
1601 }
1602 }
1603
1604 p += snprintf(p, MAX_WX_STRING, "%s rssi %d ", ssidbuf, rssi);
1605 wrqu->data.length = p - extra + 1;
1606
1607 net_os_wake_unlock(dev);
1608 return error;
1609}
1610
1611int
1612wl_iw_send_priv_event(
1613 struct net_device *dev,
1614 char *flag
1615)
1616{
1617 union iwreq_data wrqu;
1618 char extra[IW_CUSTOM_MAX + 1];
1619 int cmd;
1620
1621 cmd = IWEVCUSTOM;
1622 memset(&wrqu, 0, sizeof(wrqu));
1623 if (strlen(flag) > sizeof(extra))
1624 return -1;
1625
1626 strcpy(extra, flag);
1627 wrqu.data.length = strlen(extra);
1628 wireless_send_event(dev, cmd, &wrqu, extra);
1629 net_os_wake_lock_timeout_enable(dev, DHD_EVENT_TIMEOUT);
1630 WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra));
1631
1632 return 0;
1633}
1634
1635
1636int
1637wl_control_wl_start(struct net_device *dev)
1638{
1639 wl_iw_t *iw;
1640 int ret = 0;
1641
1642 WL_TRACE(("Enter %s \n", __FUNCTION__));
1643
1644 if (!dev) {
1645 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
1646 return -1;
1647 }
1648
1649 iw = *(wl_iw_t **)netdev_priv(dev);
1650
1651 if (!iw) {
1652 WL_ERROR(("%s: wl is null\n", __FUNCTION__));
1653 return -1;
1654 }
1655
1656 dhd_net_if_lock(dev);
1657
1658 if (g_onoff == G_WLAN_SET_OFF) {
1659 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
1660
1661#if defined(BCMLXSDMMC)
1662 sdioh_start(NULL, 0);
1663#endif
1664
1665 ret = dhd_dev_reset(dev, 0);
1666
1667#if defined(BCMLXSDMMC)
1668 sdioh_start(NULL, 1);
1669#endif
1670 if (!ret)
1671 dhd_dev_init_ioctl(dev);
1672
1673 g_onoff = G_WLAN_SET_ON;
1674 }
1675 WL_TRACE(("Exited %s\n", __FUNCTION__));
1676
1677 dhd_net_if_unlock(dev);
1678 return ret;
1679}
1680
1681
1682static int
1683wl_iw_control_wl_off(
1684 struct net_device *dev,
1685 struct iw_request_info *info
1686)
1687{
1688 wl_iw_t *iw;
1689 int ret = 0;
1690
1691 WL_TRACE(("Enter %s\n", __FUNCTION__));
1692
1693 if (!dev) {
1694 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
1695 return -1;
1696 }
1697
1698 iw = *(wl_iw_t **)netdev_priv(dev);
1699
1700 if (!iw) {
1701 WL_ERROR(("%s: wl is null\n", __FUNCTION__));
1702 return -1;
1703 }
1704
1705 dhd_net_if_lock(dev);
1706
1707#ifdef SOFTAP
1708 ap_cfg_running = FALSE;
1709#endif
1710
1711 if (g_onoff == G_WLAN_SET_ON) {
1712 g_onoff = G_WLAN_SET_OFF;
1713
1714#if defined(WL_IW_USE_ISCAN)
1715 g_iscan->iscan_state = ISCAN_STATE_IDLE;
1716#endif
1717
1718 ret = dhd_dev_reset(dev, 1);
1719
1720#if defined(WL_IW_USE_ISCAN)
1721#if !defined(CSCAN)
1722
1723 wl_iw_free_ss_cache();
1724 wl_iw_run_ss_cache_timer(0);
1725
1726 g_ss_cache_ctrl.m_link_down = 1;
1727#endif
1728 memset(g_scan, 0, G_SCAN_RESULTS);
1729 g_scan_specified_ssid = 0;
1730#if defined(CONFIG_FIRST_SCAN)
1731
1732 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
1733 g_first_counter_scans = 0;
1734#endif
1735#endif
1736
1737#if defined(BCMLXSDMMC)
1738 sdioh_stop(NULL);
1739#endif
1740
1741 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
1742
1743 wl_iw_send_priv_event(dev, "STOP");
1744 }
1745
1746 dhd_net_if_unlock(dev);
1747
1748 WL_TRACE(("Exited %s\n", __FUNCTION__));
1749
1750 return ret;
1751}
1752
1753static int
1754wl_iw_control_wl_on(
1755 struct net_device *dev,
1756 struct iw_request_info *info
1757)
1758{
1759 int ret = 0;
1760
1761 WL_TRACE(("Enter %s \n", __FUNCTION__));
1762
1763 ret = wl_control_wl_start(dev);
1764
1765 wl_iw_send_priv_event(dev, "START");
1766
1767#ifdef SOFTAP
1768 if (!ap_fw_loaded) {
1769 wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
1770 }
1771#else
1772 wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
1773#endif
1774
1775 WL_TRACE(("Exited %s\n", __FUNCTION__));
1776
1777 return ret;
1778}
1779
1780#ifdef SOFTAP
1781static struct ap_profile my_ap;
1782static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap);
1783static int get_assoc_sta_list(struct net_device *dev, char *buf, int len);
1784static int set_ap_mac_list(struct net_device *dev, void *buf);
1785
1786#define PTYPE_STRING 0
1787#define PTYPE_INTDEC 1
1788#define PTYPE_INTHEX 2
1789#define PTYPE_STR_HEX 3
1790
1791static int get_parameter_from_string(
1792 char **str_ptr, const char *token, int param_type, void *dst, int param_max_len);
1793
1794static int
1795hex2num(char c)
1796{
1797 if (c >= '0' && c <= '9')
1798 return c - '0';
1799 if (c >= 'a' && c <= 'f')
1800 return c - 'a' + 10;
1801 if (c >= 'A' && c <= 'F')
1802 return c - 'A' + 10;
1803 return -1;
1804}
1805
1806
1807
1808static int
1809hstr_2_buf(const char *txt, u8 *buf, int len)
1810{
1811 int i;
1812
1813 for (i = 0; i < len; i++) {
1814 int a, b;
1815
1816 a = hex2num(*txt++);
1817 if (a < 0)
1818 return -1;
1819 b = hex2num(*txt++);
1820 if (b < 0)
1821 return -1;
1822 *buf++ = (a << 4) | b;
1823 }
1824
1825 return 0;
1826}
1827
1828
1829
1830static int
1831init_ap_profile_from_string(char *param_str, struct ap_profile *ap_cfg)
1832{
1833 char *str_ptr = param_str;
1834 char sub_cmd[16];
1835 int ret = 0;
1836
1837 memset(sub_cmd, 0, sizeof(sub_cmd));
1838 memset(ap_cfg, 0, sizeof(struct ap_profile));
1839
1840
1841 if (get_parameter_from_string(&str_ptr, "ASCII_CMD=",
1842 PTYPE_STRING, sub_cmd, SSID_LEN) != 0) {
1843 return -1;
1844 }
1845 if (strncmp(sub_cmd, "AP_CFG", 6)) {
1846 WL_ERROR(("ERROR: sub_cmd:%s != 'AP_CFG'!\n", sub_cmd));
1847 return -1;
1848 }
1849
1850
1851
1852 ret = get_parameter_from_string(&str_ptr, "SSID=", PTYPE_STRING, ap_cfg->ssid, SSID_LEN);
1853
1854 ret |= get_parameter_from_string(&str_ptr, "SEC=", PTYPE_STRING, ap_cfg->sec, SEC_LEN);
1855
1856 ret |= get_parameter_from_string(&str_ptr, "KEY=", PTYPE_STRING, ap_cfg->key, KEY_LEN);
1857
1858 ret |= get_parameter_from_string(&str_ptr, "CHANNEL=", PTYPE_INTDEC, &ap_cfg->channel, 5);
1859
1860
1861 get_parameter_from_string(&str_ptr, "PREAMBLE=", PTYPE_INTDEC, &ap_cfg->preamble, 5);
1862
1863
1864 get_parameter_from_string(&str_ptr, "MAX_SCB=", PTYPE_INTDEC, &ap_cfg->max_scb, 5);
1865
1866
1867 get_parameter_from_string(&str_ptr, "HIDDEN=",
1868 PTYPE_INTDEC, &ap_cfg->closednet, 5);
1869
1870
1871 get_parameter_from_string(&str_ptr, "COUNTRY=",
1872 PTYPE_STRING, &ap_cfg->country_code, 3);
1873
1874 return ret;
1875}
1876#endif
1877
1878
1879
1880#ifdef SOFTAP
1881static int
1882iwpriv_set_ap_config(struct net_device *dev,
1883 struct iw_request_info *info,
1884 union iwreq_data *wrqu,
1885 char *ext)
1886{
1887 int res = 0;
1888 char *extra = NULL;
1889 struct ap_profile *ap_cfg = &my_ap;
1890
1891 WL_TRACE(("> Got IWPRIV SET_AP IOCTL: info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n",
1892 info->cmd, info->flags,
1893 wrqu->data.pointer, wrqu->data.length));
1894
1895 if (!ap_fw_loaded) {
1896 WL_ERROR(("Can't execute %s(), SOFTAP fw is not Loaded\n",
1897 __FUNCTION__));
1898 return -1;
1899 }
1900
1901 if (wrqu->data.length != 0) {
1902
1903 char *str_ptr;
1904
1905 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
1906 return -ENOMEM;
1907
1908 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
1909 kfree(extra);
1910 return -EFAULT;
1911 }
1912
1913 extra[wrqu->data.length] = 0;
1914 WL_SOFTAP((" Got str param in iw_point:\n %s\n", extra));
1915
1916 memset(ap_cfg, 0, sizeof(struct ap_profile));
1917
1918
1919
1920 str_ptr = extra;
1921
1922 if ((res = init_ap_profile_from_string(extra, ap_cfg)) < 0) {
1923 WL_ERROR(("%s failed to parse %d\n", __FUNCTION__, res));
1924 kfree(extra);
1925 return -1;
1926 }
1927
1928 } else {
1929
1930 WL_ERROR(("IWPRIV argument len = 0 \n"));
1931 return -1;
1932 }
1933
1934 if ((res = set_ap_cfg(dev, ap_cfg)) < 0)
1935 WL_ERROR(("%s failed to set_ap_cfg %d\n", __FUNCTION__, res));
1936
1937 kfree(extra);
1938
1939 return res;
1940}
1941#endif
1942
1943
1944
1945#ifdef SOFTAP
1946static int iwpriv_get_assoc_list(struct net_device *dev,
1947 struct iw_request_info *info,
1948 union iwreq_data *p_iwrq,
1949 char *extra)
1950{
1951 int i, ret = 0;
1952 char mac_buf[256];
1953 struct maclist *sta_maclist = (struct maclist *)mac_buf;
1954
1955 char mac_lst[384];
1956 char *p_mac_str;
1957 char *p_mac_str_end;
1958 wl_iw_t *iw;
1959
1960 if ((!dev) || (!extra)) {
1961
1962 return -EINVAL;
1963 }
1964
1965
1966 iw = *(wl_iw_t **)netdev_priv(dev);
1967
1968 net_os_wake_lock(dev);
1969 DHD_OS_MUTEX_LOCK(&wl_softap_lock);
1970
1971 WL_TRACE(("\n %s: IWPRIV IOCTL: cmd:%hx, flags:%hx, extra:%p, iwp.len:%d,"
1972 "iwp.len:%p, iwp.flags:%x \n", __FUNCTION__, info->cmd, info->flags,
1973 extra, p_iwrq->data.length, p_iwrq->data.pointer, p_iwrq->data.flags));
1974
1975
1976 memset(sta_maclist, 0, sizeof(mac_buf));
1977
1978 sta_maclist->count = 8;
1979
1980 WL_SOFTAP(("%s: net device:%s, buf_sz:%d\n",
1981 __FUNCTION__, dev->name, sizeof(mac_buf)));
1982
1983 if ((ret = get_assoc_sta_list(dev, mac_buf, sizeof(mac_buf))) < 0) {
1984 WL_ERROR(("%s: sta list ioctl error:%d\n",
1985 __FUNCTION__, ret));
1986 goto func_exit;
1987 }
1988
1989 WL_SOFTAP(("%s: got %d stations\n", __FUNCTION__,
1990 sta_maclist->count));
1991
1992
1993
1994 memset(mac_lst, 0, sizeof(mac_lst));
1995 p_mac_str = mac_lst;
1996 p_mac_str_end = &mac_lst[sizeof(mac_lst)-1];
1997
1998 for (i = 0; i < 8; i++) {
1999 struct ether_addr * id = &sta_maclist->ea[i];
2000 if (!ETHER_ISNULLADDR(id->octet)) {
2001 scb_val_t scb_val;
2002 int rssi = 0;
2003 bzero(&scb_val, sizeof(scb_val_t));
2004
2005
2006 if ((p_mac_str_end - p_mac_str) <= 36) {
2007 WL_ERROR(("%s: mac list buf is < 36 for item[%i] item\n",
2008 __FUNCTION__, i));
2009 break;
2010 }
2011
2012 p_mac_str += snprintf(p_mac_str, MAX_WX_STRING,
2013 "\nMac[%d]=%02X:%02X:%02X:%02X:%02X:%02X,", i,
2014 id->octet[0], id->octet[1], id->octet[2],
2015 id->octet[3], id->octet[4], id->octet[5]);
2016
2017
2018 bcopy(id->octet, &scb_val.ea, 6);
2019 ret = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
2020 if (ret < 0) {
2021 snprintf(p_mac_str, MAX_WX_STRING, "RSSI:ERR");
2022 WL_ERROR(("%s: RSSI ioctl error:%d\n",
2023 __FUNCTION__, ret));
2024 break;
2025 }
2026
2027 rssi = dtoh32(scb_val.val);
2028 p_mac_str += snprintf(p_mac_str, MAX_WX_STRING,
2029 "RSSI:%d", rssi);
2030 }
2031 }
2032
2033 p_iwrq->data.length = strlen(mac_lst)+1;
2034
2035 WL_SOFTAP(("%s: data to user:\n%s\n usr_ptr:%p\n", __FUNCTION__,
2036 mac_lst, p_iwrq->data.pointer));
2037
2038 if (p_iwrq->data.length) {
2039 bcopy(mac_lst, extra, p_iwrq->data.length);
2040 }
2041
2042func_exit:
2043
2044 DHD_OS_MUTEX_UNLOCK(&wl_softap_lock);
2045 net_os_wake_unlock(dev);
2046
2047 WL_SOFTAP(("%s: Exited\n", __FUNCTION__));
2048 return ret;
2049}
2050#endif
2051
2052
2053#ifdef SOFTAP
2054
2055#define MAC_FILT_MAX 8
2056static int iwpriv_set_mac_filters(struct net_device *dev,
2057 struct iw_request_info *info,
2058 union iwreq_data *wrqu,
2059 char *ext)
2060{
2061 int i, ret = -1;
2062 char * extra = NULL;
2063 int mac_cnt = 0;
2064 int mac_mode = 0;
2065 struct ether_addr *p_ea;
2066 struct mac_list_set mflist_set;
2067
2068 WL_SOFTAP((">>> Got IWPRIV SET_MAC_FILTER IOCTL: info->cmd:%x,"
2069 "info->flags:%x, u.data:%p, u.len:%d\n",
2070 info->cmd, info->flags,
2071 wrqu->data.pointer, wrqu->data.length));
2072
2073 if (wrqu->data.length != 0) {
2074
2075 char *str_ptr;
2076
2077 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
2078 return -ENOMEM;
2079
2080 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
2081 kfree(extra);
2082 return -EFAULT;
2083 }
2084
2085 extra[wrqu->data.length] = 0;
2086 WL_SOFTAP((" Got parameter string in iw_point:\n %s \n", extra));
2087
2088 memset(&mflist_set, 0, sizeof(mflist_set));
2089
2090
2091 str_ptr = extra;
2092
2093
2094
2095 if (get_parameter_from_string(&str_ptr, "MAC_MODE=",
2096 PTYPE_INTDEC, &mac_mode, 4) != 0) {
2097 WL_ERROR(("ERROR: 'MAC_MODE=' token is missing\n"));
2098 goto exit_proc;
2099 }
2100
2101 p_ea = &mflist_set.mac_list.ea[0];
2102
2103 if (get_parameter_from_string(&str_ptr, "MAC_CNT=",
2104 PTYPE_INTDEC, &mac_cnt, 4) != 0) {
2105 WL_ERROR(("ERROR: 'MAC_CNT=' token param is missing \n"));
2106 goto exit_proc;
2107 }
2108
2109 if (mac_cnt > MAC_FILT_MAX) {
2110 WL_ERROR(("ERROR: number of MAC filters > MAX\n"));
2111 goto exit_proc;
2112 }
2113
2114 for (i=0; i< mac_cnt; i++)
2115 if (get_parameter_from_string(&str_ptr, "MAC=",
2116 PTYPE_STR_HEX, &p_ea[i], 12) != 0) {
2117 WL_ERROR(("ERROR: MAC_filter[%d] is missing !\n", i));
2118 goto exit_proc;
2119 }
2120
2121 WL_SOFTAP(("MAC_MODE=:%d, MAC_CNT=%d, MACs:..\n", mac_mode, mac_cnt));
2122 for (i = 0; i < mac_cnt; i++) {
2123 WL_SOFTAP(("mac_filt[%d]:", i));
2124 dhd_print_buf(&p_ea[i], 6, 0);
2125 }
2126
2127
2128 mflist_set.mode = mac_mode;
2129 mflist_set.mac_list.count = mac_cnt;
2130 set_ap_mac_list(dev, &mflist_set);
2131
2132
2133 wrqu->data.pointer = NULL;
2134 wrqu->data.length = 0;
2135 ret = 0;
2136
2137 } else {
2138
2139 WL_ERROR(("IWPRIV argument len is 0\n"));
2140 return -1;
2141 }
2142
2143 exit_proc:
2144 kfree(extra);
2145 return ret;
2146}
2147#endif
2148
2149
2150#ifdef SOFTAP
2151
2152static int iwpriv_set_ap_sta_disassoc(struct net_device *dev,
2153 struct iw_request_info *info,
2154 union iwreq_data *wrqu,
2155 char *ext)
2156{
2157 int res = 0;
2158 char sta_mac[6] = {0, 0, 0, 0, 0, 0};
2159 char cmd_buf[256];
2160 char *str_ptr = cmd_buf;
2161
2162 WL_SOFTAP((">>%s called\n args: info->cmd:%x,"
2163 " info->flags:%x, u.data.p:%p, u.data.len:%d\n",
2164 __FUNCTION__, info->cmd, info->flags,
2165 wrqu->data.pointer, wrqu->data.length));
2166
2167 if (wrqu->data.length != 0) {
2168
2169 if (copy_from_user(cmd_buf, wrqu->data.pointer, wrqu->data.length)) {
2170 return -EFAULT;
2171 }
2172
2173 if (get_parameter_from_string(&str_ptr,
2174 "MAC=", PTYPE_STR_HEX, sta_mac, 12) == 0) {
2175 res = wl_iw_softap_deassoc_stations(dev, sta_mac);
2176 } else {
2177 WL_ERROR(("ERROR: STA_MAC= token not found\n"));
2178 }
2179 }
2180
2181 return res;
2182}
2183#endif
2184
2185#endif
2186
2187#if WIRELESS_EXT < 13
2188struct iw_request_info
2189{
2190 __u16 cmd;
2191 __u16 flags;
2192};
2193
2194typedef int (*iw_handler)(struct net_device *dev,
2195 struct iw_request_info *info,
2196 void *wrqu,
2197 char *extra);
2198#endif
2199
2200static int
2201wl_iw_config_commit(
2202 struct net_device *dev,
2203 struct iw_request_info *info,
2204 void *zwrq,
2205 char *extra
2206)
2207{
2208 wlc_ssid_t ssid;
2209 int error;
2210 struct sockaddr bssid;
2211
2212 WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name));
2213
2214 if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid))))
2215 return error;
2216
2217 ssid.SSID_len = dtoh32(ssid.SSID_len);
2218
2219 if (!ssid.SSID_len)
2220 return 0;
2221
2222 bzero(&bssid, sizeof(struct sockaddr));
2223 if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) {
2224 WL_ERROR(("%s: WLC_REASSOC to %s failed \n", __FUNCTION__, ssid.SSID));
2225 return error;
2226 }
2227
2228 return 0;
2229}
2230
2231static int
2232wl_iw_get_name(
2233 struct net_device *dev,
2234 struct iw_request_info *info,
2235 char *cwrq,
2236 char *extra
2237)
2238{
2239 WL_TRACE(("%s: SIOCGIWNAME\n", dev->name));
2240
2241 strcpy(cwrq, "IEEE 802.11-DS");
2242
2243 return 0;
2244}
2245
2246static int
2247wl_iw_set_freq(
2248 struct net_device *dev,
2249 struct iw_request_info *info,
2250 struct iw_freq *fwrq,
2251 char *extra
2252)
2253{
2254 int error, chan;
2255 uint sf = 0;
2256
2257 WL_TRACE(("%s %s: SIOCSIWFREQ\n", __FUNCTION__, dev->name));
2258
2259#if defined(SOFTAP)
2260 if (ap_cfg_running) {
2261 WL_TRACE(("%s:>> not executed, 'SOFT_AP is active' \n", __FUNCTION__));
2262 return 0;
2263 }
2264#endif
2265
2266
2267 if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
2268 chan = fwrq->m;
2269 }
2270
2271 else {
2272
2273 if (fwrq->e >= 6) {
2274 fwrq->e -= 6;
2275 while (fwrq->e--)
2276 fwrq->m *= 10;
2277 } else if (fwrq->e < 6) {
2278 while (fwrq->e++ < 6)
2279 fwrq->m /= 10;
2280 }
2281
2282 if (fwrq->m > 4000 && fwrq->m < 5000)
2283 sf = WF_CHAN_FACTOR_4_G;
2284
2285 chan = wf_mhz2channel(fwrq->m, sf);
2286 }
2287
2288 chan = htod32(chan);
2289
2290 if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan))))
2291 return error;
2292
2293 g_wl_iw_params.target_channel = chan;
2294
2295
2296 return -EINPROGRESS;
2297}
2298
2299static int
2300wl_iw_get_freq(
2301 struct net_device *dev,
2302 struct iw_request_info *info,
2303 struct iw_freq *fwrq,
2304 char *extra
2305)
2306{
2307 channel_info_t ci;
2308 int error;
2309
2310 WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name));
2311
2312 if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
2313 return error;
2314
2315
2316 fwrq->m = dtoh32(ci.hw_channel);
2317 fwrq->e = dtoh32(0);
2318 return 0;
2319}
2320
2321static int
2322wl_iw_set_mode(
2323 struct net_device *dev,
2324 struct iw_request_info *info,
2325 __u32 *uwrq,
2326 char *extra
2327)
2328{
2329 int infra = 0, ap = 0, error = 0;
2330
2331 WL_TRACE(("%s: SIOCSIWMODE\n", dev->name));
2332
2333 switch (*uwrq) {
2334 case IW_MODE_MASTER:
2335 infra = ap = 1;
2336 break;
2337 case IW_MODE_ADHOC:
2338 case IW_MODE_AUTO:
2339 break;
2340 case IW_MODE_INFRA:
2341 infra = 1;
2342 break;
2343 default:
2344 return -EINVAL;
2345 }
2346 infra = htod32(infra);
2347 ap = htod32(ap);
2348
2349 if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) ||
2350 (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap))))
2351 return error;
2352
2353
2354 return -EINPROGRESS;
2355}
2356
2357static int
2358wl_iw_get_mode(
2359 struct net_device *dev,
2360 struct iw_request_info *info,
2361 __u32 *uwrq,
2362 char *extra
2363)
2364{
2365 int error, infra = 0, ap = 0;
2366
2367 WL_TRACE(("%s: SIOCGIWMODE\n", dev->name));
2368
2369 if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) ||
2370 (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap))))
2371 return error;
2372
2373 infra = dtoh32(infra);
2374 ap = dtoh32(ap);
2375 *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
2376
2377 return 0;
2378}
2379
2380static int
2381wl_iw_get_range(
2382 struct net_device *dev,
2383 struct iw_request_info *info,
2384 struct iw_point *dwrq,
2385 char *extra
2386)
2387{
2388 struct iw_range *range = (struct iw_range *) extra;
2389 wl_uint32_list_t *list;
2390 wl_rateset_t rateset;
2391 int8 *channels;
2392 int error, i, k;
2393 uint sf, ch;
2394
2395 int phytype;
2396 int bw_cap = 0, sgi_tx = 0, nmode = 0;
2397 channel_info_t ci;
2398 uint8 nrate_list2copy = 0;
2399 uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130},
2400 {14, 29, 43, 58, 87, 116, 130, 144},
2401 {27, 54, 81, 108, 162, 216, 243, 270},
2402 {30, 60, 90, 120, 180, 240, 270, 300}};
2403
2404 WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name));
2405
2406 if (!extra)
2407 return -EINVAL;
2408
2409 channels = kmalloc((MAXCHANNEL+1)*4, GFP_KERNEL);
2410 if (!channels) {
2411 WL_ERROR(("Could not alloc channels\n"));
2412 return -ENOMEM;
2413 }
2414 list = (wl_uint32_list_t *)channels;
2415
2416 dwrq->length = sizeof(struct iw_range);
2417 memset(range, 0, sizeof(*range));
2418
2419
2420 range->min_nwid = range->max_nwid = 0;
2421
2422
2423 list->count = htod32(MAXCHANNEL);
2424 if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, (MAXCHANNEL+1)*4))) {
2425 kfree(channels);
2426 return error;
2427 }
2428 for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) {
2429 range->freq[i].i = dtoh32(list->element[i]);
2430
2431 ch = dtoh32(list->element[i]);
2432 if (ch <= CH_MAX_2G_CHANNEL)
2433 sf = WF_CHAN_FACTOR_2_4_G;
2434 else
2435 sf = WF_CHAN_FACTOR_5_G;
2436
2437 range->freq[i].m = wf_channel2mhz(ch, sf);
2438 range->freq[i].e = 6;
2439 }
2440 range->num_frequency = range->num_channels = i;
2441
2442
2443 range->max_qual.qual = 5;
2444
2445 range->max_qual.level = 0x100 - 200;
2446
2447 range->max_qual.noise = 0x100 - 200;
2448
2449 range->sensitivity = 65535;
2450
2451#if WIRELESS_EXT > 11
2452
2453 range->avg_qual.qual = 3;
2454
2455 range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD;
2456
2457 range->avg_qual.noise = 0x100 - 75;
2458#endif
2459
2460
2461 if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) {
2462 kfree(channels);
2463 return error;
2464 }
2465 rateset.count = dtoh32(rateset.count);
2466 range->num_bitrates = rateset.count;
2467 for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
2468 range->bitrate[i] = (rateset.rates[i]& 0x7f) * 500000;
2469 dev_wlc_intvar_get(dev, "nmode", &nmode);
2470 dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
2471
2472 if (nmode == 1 && phytype == WLC_PHY_TYPE_SSN) {
2473 dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap);
2474 dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx);
2475 dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t));
2476 ci.hw_channel = dtoh32(ci.hw_channel);
2477
2478 if (bw_cap == 0 ||
2479 (bw_cap == 2 && ci.hw_channel <= 14)) {
2480 if (sgi_tx == 0)
2481 nrate_list2copy = 0;
2482 else
2483 nrate_list2copy = 1;
2484 }
2485 if (bw_cap == 1 ||
2486 (bw_cap == 2 && ci.hw_channel >= 36)) {
2487 if (sgi_tx == 0)
2488 nrate_list2copy = 2;
2489 else
2490 nrate_list2copy = 3;
2491 }
2492 range->num_bitrates += 8;
2493 for (k = 0; i < range->num_bitrates; k++, i++) {
2494
2495 range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000;
2496 }
2497 }
2498
2499
2500 if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) {
2501 kfree(channels);
2502 return error;
2503 }
2504 i = dtoh32(i);
2505 if (i == WLC_PHY_TYPE_A)
2506 range->throughput = 24000000;
2507 else
2508 range->throughput = 1500000;
2509
2510
2511 range->min_rts = 0;
2512 range->max_rts = 2347;
2513 range->min_frag = 256;
2514 range->max_frag = 2346;
2515
2516 range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS;
2517 range->num_encoding_sizes = 4;
2518 range->encoding_size[0] = WEP1_KEY_SIZE;
2519 range->encoding_size[1] = WEP128_KEY_SIZE;
2520#if WIRELESS_EXT > 17
2521 range->encoding_size[2] = TKIP_KEY_SIZE;
2522#else
2523 range->encoding_size[2] = 0;
2524#endif
2525 range->encoding_size[3] = AES_KEY_SIZE;
2526
2527
2528 range->min_pmp = 0;
2529 range->max_pmp = 0;
2530 range->min_pmt = 0;
2531 range->max_pmt = 0;
2532 range->pmp_flags = 0;
2533 range->pm_capa = 0;
2534
2535
2536 range->num_txpower = 2;
2537 range->txpower[0] = 1;
2538 range->txpower[1] = 255;
2539 range->txpower_capa = IW_TXPOW_MWATT;
2540
2541#if WIRELESS_EXT > 10
2542 range->we_version_compiled = WIRELESS_EXT;
2543 range->we_version_source = 19;
2544
2545
2546 range->retry_capa = IW_RETRY_LIMIT;
2547 range->retry_flags = IW_RETRY_LIMIT;
2548 range->r_time_flags = 0;
2549
2550 range->min_retry = 1;
2551 range->max_retry = 255;
2552
2553 range->min_r_time = 0;
2554 range->max_r_time = 0;
2555#endif
2556
2557#if WIRELESS_EXT > 17
2558 range->enc_capa = IW_ENC_CAPA_WPA;
2559 range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
2560 range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
2561 range->enc_capa |= IW_ENC_CAPA_WPA2;
2562
2563
2564 IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
2565
2566 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
2567 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
2568 IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
2569 IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
2570 IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND);
2571#endif
2572
2573 kfree(channels);
2574
2575 return 0;
2576}
2577
2578static int
2579rssi_to_qual(int rssi)
2580{
2581 if (rssi <= WL_IW_RSSI_NO_SIGNAL)
2582 return 0;
2583 else if (rssi <= WL_IW_RSSI_VERY_LOW)
2584 return 1;
2585 else if (rssi <= WL_IW_RSSI_LOW)
2586 return 2;
2587 else if (rssi <= WL_IW_RSSI_GOOD)
2588 return 3;
2589 else if (rssi <= WL_IW_RSSI_VERY_GOOD)
2590 return 4;
2591 else
2592 return 5;
2593}
2594
2595static int
2596wl_iw_set_spy(
2597 struct net_device *dev,
2598 struct iw_request_info *info,
2599 struct iw_point *dwrq,
2600 char *extra
2601)
2602{
2603 wl_iw_t *iw = NETDEV_PRIV(dev);
2604 struct sockaddr *addr = (struct sockaddr *) extra;
2605 int i;
2606
2607 WL_TRACE(("%s: SIOCSIWSPY\n", dev->name));
2608
2609 if (!extra)
2610 return -EINVAL;
2611
2612 iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length);
2613 for (i = 0; i < iw->spy_num; i++)
2614 memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN);
2615 memset(iw->spy_qual, 0, sizeof(iw->spy_qual));
2616
2617 return 0;
2618}
2619
2620static int
2621wl_iw_get_spy(
2622 struct net_device *dev,
2623 struct iw_request_info *info,
2624 struct iw_point *dwrq,
2625 char *extra
2626)
2627{
2628 wl_iw_t *iw = NETDEV_PRIV(dev);
2629 struct sockaddr *addr = (struct sockaddr *) extra;
2630 struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num];
2631 int i;
2632
2633 WL_TRACE(("%s: SIOCGIWSPY\n", dev->name));
2634
2635 if (!extra)
2636 return -EINVAL;
2637
2638 dwrq->length = iw->spy_num;
2639 for (i = 0; i < iw->spy_num; i++) {
2640 memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN);
2641 addr[i].sa_family = AF_UNIX;
2642 memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality));
2643 iw->spy_qual[i].updated = 0;
2644 }
2645
2646 return 0;
2647}
2648
2649
2650static int
2651wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params, int *join_params_size)
2652{
2653 chanspec_t chanspec = 0;
2654
2655 if (ch != 0) {
2656
2657 join_params->params.chanspec_num = 1;
2658 join_params->params.chanspec_list[0] = ch;
2659
2660 if (join_params->params.chanspec_list[0])
2661 chanspec |= WL_CHANSPEC_BAND_2G;
2662 else
2663 chanspec |= WL_CHANSPEC_BAND_5G;
2664
2665 chanspec |= WL_CHANSPEC_BW_20;
2666 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
2667
2668
2669 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
2670 join_params->params.chanspec_num * sizeof(chanspec_t);
2671
2672
2673 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
2674 join_params->params.chanspec_list[0] |= chanspec;
2675 join_params->params.chanspec_list[0] =
2676 htodchanspec(join_params->params.chanspec_list[0]);
2677
2678 join_params->params.chanspec_num = htod32(join_params->params.chanspec_num);
2679
2680 WL_TRACE(("%s join_params->params.chanspec_list[0]= %X\n",
2681 __FUNCTION__, join_params->params.chanspec_list[0]));
2682 }
2683 return 1;
2684}
2685
2686static int
2687wl_iw_set_wap(
2688 struct net_device *dev,
2689 struct iw_request_info *info,
2690 struct sockaddr *awrq,
2691 char *extra
2692)
2693{
2694 int error = -EINVAL;
2695 wl_join_params_t join_params;
2696 int join_params_size;
2697
2698 WL_TRACE(("%s: SIOCSIWAP\n", dev->name));
2699
2700 if (awrq->sa_family != ARPHRD_ETHER) {
2701 WL_ERROR(("Invalid Header...sa_family\n"));
2702 return -EINVAL;
2703 }
2704
2705
2706 if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) {
2707 scb_val_t scbval;
2708
2709 bzero(&scbval, sizeof(scb_val_t));
2710
2711 (void) dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
2712 return 0;
2713 }
2714
2715
2716
2717 memset(&join_params, 0, sizeof(join_params));
2718 join_params_size = sizeof(join_params.ssid);
2719
2720 memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
2721 join_params.ssid.SSID_len = htod32(g_ssid.SSID_len);
2722 memcpy(&join_params.params.bssid, awrq->sa_data, ETHER_ADDR_LEN);
2723
2724
2725
2726 WL_TRACE(("%s target_channel=%d\n", __FUNCTION__, g_wl_iw_params.target_channel));
2727 wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size);
2728
2729 if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) {
2730 WL_ERROR(("%s Invalid ioctl data=%d\n", __FUNCTION__, error));
2731 return error;
2732 }
2733
2734 if (g_ssid.SSID_len) {
2735 WL_TRACE(("%s: join SSID=%s BSSID="MACSTR" ch=%d\n", __FUNCTION__,
2736 g_ssid.SSID, MAC2STR((u8 *)awrq->sa_data),
2737 g_wl_iw_params.target_channel));
2738 }
2739
2740
2741 memset(&g_ssid, 0, sizeof(g_ssid));
2742 return 0;
2743}
2744
2745static int
2746wl_iw_get_wap(
2747 struct net_device *dev,
2748 struct iw_request_info *info,
2749 struct sockaddr *awrq,
2750 char *extra
2751)
2752{
2753 WL_TRACE(("%s: SIOCGIWAP\n", dev->name));
2754
2755 awrq->sa_family = ARPHRD_ETHER;
2756 memset(awrq->sa_data, 0, ETHER_ADDR_LEN);
2757
2758
2759 (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN);
2760
2761 return 0;
2762}
2763
2764#if WIRELESS_EXT > 17
2765static int
2766wl_iw_mlme(
2767 struct net_device *dev,
2768 struct iw_request_info *info,
2769 struct sockaddr *awrq,
2770 char *extra
2771)
2772{
2773 struct iw_mlme *mlme;
2774 scb_val_t scbval;
2775 int error = -EINVAL;
2776
2777 WL_TRACE(("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name));
2778
2779 mlme = (struct iw_mlme *)extra;
2780 if (mlme == NULL) {
2781 WL_ERROR(("Invalid ioctl data.\n"));
2782 return error;
2783 }
2784
2785 scbval.val = mlme->reason_code;
2786 bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN);
2787
2788 if (mlme->cmd == IW_MLME_DISASSOC) {
2789 scbval.val = htod32(scbval.val);
2790 error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
2791 }
2792 else if (mlme->cmd == IW_MLME_DEAUTH) {
2793 scbval.val = htod32(scbval.val);
2794 error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
2795 sizeof(scb_val_t));
2796 }
2797 else {
2798 WL_ERROR(("Invalid ioctl data.\n"));
2799 return error;
2800 }
2801
2802 return error;
2803}
2804#endif
2805
2806#ifndef WL_IW_USE_ISCAN
2807static int
2808wl_iw_get_aplist(
2809 struct net_device *dev,
2810 struct iw_request_info *info,
2811 struct iw_point *dwrq,
2812 char *extra
2813)
2814{
2815 wl_scan_results_t *list;
2816 struct sockaddr *addr = (struct sockaddr *) extra;
2817 struct iw_quality qual[IW_MAX_AP];
2818 wl_bss_info_t *bi = NULL;
2819 int error, i;
2820 uint buflen = dwrq->length;
2821
2822 WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
2823
2824 if (!extra)
2825 return -EINVAL;
2826
2827
2828 list = kmalloc(buflen, GFP_KERNEL);
2829 if (!list)
2830 return -ENOMEM;
2831 memset(list, 0, buflen);
2832 list->buflen = htod32(buflen);
2833 if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) {
2834 WL_ERROR(("%d: Scan results error %d\n", __LINE__, error));
2835 kfree(list);
2836 return error;
2837 }
2838 list->buflen = dtoh32(list->buflen);
2839 list->version = dtoh32(list->version);
2840 list->count = dtoh32(list->count);
2841 if (list->version != WL_BSS_INFO_VERSION) {
2842 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
2843 __FUNCTION__, list->version));
2844 kfree(list);
2845 return -EINVAL;
2846 }
2847
2848 for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
2849 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
2850 ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
2851 buflen));
2852
2853
2854 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
2855 continue;
2856
2857
2858 memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
2859 addr[dwrq->length].sa_family = ARPHRD_ETHER;
2860 qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
2861 qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
2862 qual[dwrq->length].noise = 0x100 + bi->phy_noise;
2863
2864
2865#if WIRELESS_EXT > 18
2866 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
2867#else
2868 qual[dwrq->length].updated = 7;
2869#endif
2870
2871 dwrq->length++;
2872 }
2873
2874 kfree(list);
2875
2876 if (dwrq->length) {
2877 memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
2878
2879 dwrq->flags = 1;
2880 }
2881
2882 return 0;
2883}
2884#endif
2885
2886#ifdef WL_IW_USE_ISCAN
2887static int
2888wl_iw_iscan_get_aplist(
2889 struct net_device *dev,
2890 struct iw_request_info *info,
2891 struct iw_point *dwrq,
2892 char *extra
2893)
2894{
2895 wl_scan_results_t *list;
2896 iscan_buf_t * buf;
2897 iscan_info_t *iscan = g_iscan;
2898
2899 struct sockaddr *addr = (struct sockaddr *) extra;
2900 struct iw_quality qual[IW_MAX_AP];
2901 wl_bss_info_t *bi = NULL;
2902 int i;
2903
2904 WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
2905
2906 if (!extra)
2907 return -EINVAL;
2908
2909 if ((!iscan) || (iscan->tsk_ctl.thr_pid < 0)) {
2910 WL_ERROR(("%s error\n", __FUNCTION__));
2911 return 0;
2912 }
2913
2914 buf = iscan->list_hdr;
2915
2916 while (buf) {
2917 list = &((wl_iscan_results_t*)buf->iscan_buf)->results;
2918 if (list->version != WL_BSS_INFO_VERSION) {
2919 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
2920 __FUNCTION__, list->version));
2921 return -EINVAL;
2922 }
2923
2924 bi = NULL;
2925 for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
2926 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length))
2927 : list->bss_info;
2928 ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
2929 WLC_IW_ISCAN_MAXLEN));
2930
2931
2932 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
2933 continue;
2934
2935
2936 memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
2937 addr[dwrq->length].sa_family = ARPHRD_ETHER;
2938 qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
2939 qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
2940 qual[dwrq->length].noise = 0x100 + bi->phy_noise;
2941
2942
2943#if WIRELESS_EXT > 18
2944 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
2945#else
2946 qual[dwrq->length].updated = 7;
2947#endif
2948
2949 dwrq->length++;
2950 }
2951 buf = buf->next;
2952 }
2953 if (dwrq->length) {
2954 memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
2955
2956 dwrq->flags = 1;
2957 }
2958
2959 return 0;
2960}
2961
2962static int
2963wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
2964{
2965 int err = 0;
2966
2967 memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
2968 params->bss_type = DOT11_BSSTYPE_ANY;
2969 params->scan_type = 0;
2970 params->nprobes = -1;
2971 params->active_time = -1;
2972 params->passive_time = -1;
2973 params->home_time = -1;
2974 params->channel_num = 0;
2975
2976#if defined(CONFIG_FIRST_SCAN)
2977
2978 if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED)
2979 params->passive_time = 30;
2980#endif
2981 params->nprobes = htod32(params->nprobes);
2982 params->active_time = htod32(params->active_time);
2983 params->passive_time = htod32(params->passive_time);
2984 params->home_time = htod32(params->home_time);
2985 if (ssid && ssid->SSID_len)
2986 memcpy(&params->ssid, ssid, sizeof(wlc_ssid_t));
2987
2988 return err;
2989}
2990
2991static int
2992wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action)
2993{
2994 int err = 0;
2995
2996 iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
2997 iscan->iscan_ex_params_p->action = htod16(action);
2998 iscan->iscan_ex_params_p->scan_duration = htod16(0);
2999
3000 WL_SCAN(("%s : nprobes=%d\n", __FUNCTION__, iscan->iscan_ex_params_p->params.nprobes));
3001 WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
3002 WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
3003 WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
3004 WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
3005 WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type));
3006
3007 if ((dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p,
3008 iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
3009 WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
3010 err = -1;
3011 }
3012
3013 return err;
3014}
3015
3016static void
3017wl_iw_timerfunc(ulong data)
3018{
3019 iscan_info_t *iscan = (iscan_info_t *)data;
3020 if (iscan) {
3021 iscan->timer_on = 0;
3022 if (iscan->iscan_state != ISCAN_STATE_IDLE) {
3023 WL_TRACE(("timer trigger\n"));
3024 up(&iscan->tsk_ctl.sema);
3025 }
3026 }
3027}
3028
3029static void
3030wl_iw_set_event_mask(struct net_device *dev)
3031{
3032 char eventmask[WL_EVENTING_MASK_LEN];
3033 char iovbuf[WL_EVENTING_MASK_LEN + 12];
3034
3035 dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf));
3036 bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
3037 setbit(eventmask, WLC_E_SCAN_COMPLETE);
3038 dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN,
3039 iovbuf, sizeof(iovbuf));
3040}
3041
3042static uint32
3043wl_iw_iscan_get(iscan_info_t *iscan)
3044{
3045 iscan_buf_t * buf;
3046 iscan_buf_t * ptr;
3047 wl_iscan_results_t * list_buf;
3048 wl_iscan_results_t list;
3049 wl_scan_results_t *results;
3050 uint32 status;
3051 int res = 0;
3052
3053 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3054 if (iscan->list_cur) {
3055 buf = iscan->list_cur;
3056 iscan->list_cur = buf->next;
3057 }
3058 else {
3059 buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL);
3060 if (!buf) {
3061 WL_ERROR(("%s can't alloc iscan_buf_t : going to abort currect iscan\n",
3062 __FUNCTION__));
3063 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3064 return WL_SCAN_RESULTS_NO_MEM;
3065 }
3066 buf->next = NULL;
3067 if (!iscan->list_hdr)
3068 iscan->list_hdr = buf;
3069 else {
3070 ptr = iscan->list_hdr;
3071 while (ptr->next) {
3072 ptr = ptr->next;
3073 }
3074 ptr->next = buf;
3075 }
3076 }
3077 memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
3078 list_buf = (wl_iscan_results_t*)buf->iscan_buf;
3079 results = &list_buf->results;
3080 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
3081 results->version = 0;
3082 results->count = 0;
3083
3084 memset(&list, 0, sizeof(list));
3085 list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
3086 res = dev_iw_iovar_getbuf(
3087 iscan->dev,
3088 "iscanresults",
3089 &list,
3090 WL_ISCAN_RESULTS_FIXED_SIZE,
3091 buf->iscan_buf,
3092 WLC_IW_ISCAN_MAXLEN);
3093 if (res == 0) {
3094 results->buflen = dtoh32(results->buflen);
3095 results->version = dtoh32(results->version);
3096 results->count = dtoh32(results->count);
3097 WL_TRACE(("results->count = %d\n", results->count));
3098 WL_TRACE(("results->buflen = %d\n", results->buflen));
3099 status = dtoh32(list_buf->status);
3100 } else {
3101 WL_ERROR(("%s returns error %d\n", __FUNCTION__, res));
3102
3103 status = WL_SCAN_RESULTS_NO_MEM;
3104 }
3105 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3106 return status;
3107}
3108
3109static void
3110wl_iw_force_specific_scan(iscan_info_t *iscan)
3111{
3112 WL_TRACE(("%s force Specific SCAN for %s\n", __FUNCTION__, g_specific_ssid.SSID));
3113#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3114 rtnl_lock();
3115#endif
3116
3117 (void) dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid));
3118
3119#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3120 rtnl_unlock();
3121#endif
3122}
3123
3124static void
3125wl_iw_send_scan_complete(iscan_info_t *iscan)
3126{
3127 union iwreq_data wrqu;
3128
3129 memset(&wrqu, 0, sizeof(wrqu));
3130
3131
3132 wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL);
3133#if defined(CONFIG_FIRST_SCAN)
3134 if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED)
3135 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY;
3136#endif
3137 WL_TRACE(("Send Event ISCAN complete\n"));
3138}
3139
3140static int
3141_iscan_sysioc_thread(void *data)
3142{
3143 uint32 status;
3144
3145 tsk_ctl_t *tsk_ctl = (tsk_ctl_t *)data;
3146 iscan_info_t *iscan = (iscan_info_t *) tsk_ctl->parent;
3147
3148
3149 static bool iscan_pass_abort = FALSE;
3150
3151 DAEMONIZE("iscan_sysioc");
3152
3153 status = WL_SCAN_RESULTS_PARTIAL;
3154
3155
3156 complete(&tsk_ctl->completed);
3157
3158 while (down_interruptible(&tsk_ctl->sema) == 0) {
3159
3160 SMP_RD_BARRIER_DEPENDS();
3161 if (tsk_ctl->terminated) {
3162 break;
3163 }
3164#if defined(SOFTAP)
3165
3166 if (ap_cfg_running) {
3167 WL_TRACE(("%s skipping SCAN ops in AP mode !!!\n", __FUNCTION__));
3168 net_os_wake_unlock(iscan->dev);
3169 continue;
3170 }
3171#endif
3172
3173 if (iscan->timer_on) {
3174
3175 iscan->timer_on = 0;
3176 del_timer_sync(&iscan->timer);
3177 }
3178
3179#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3180 rtnl_lock();
3181#endif
3182 status = wl_iw_iscan_get(iscan);
3183#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3184 rtnl_unlock();
3185#endif
3186
3187 if (g_scan_specified_ssid && (iscan_pass_abort == TRUE)) {
3188 WL_TRACE(("%s Get results from specific scan status=%d\n", __FUNCTION__, status));
3189 wl_iw_send_scan_complete(iscan);
3190 iscan_pass_abort = FALSE;
3191 status = -1;
3192 }
3193
3194 switch (status) {
3195 case WL_SCAN_RESULTS_PARTIAL:
3196 WL_TRACE(("iscanresults incomplete\n"));
3197#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3198 rtnl_lock();
3199#endif
3200
3201 wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
3202#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3203 rtnl_unlock();
3204#endif
3205
3206 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
3207 iscan->timer_on = 1;
3208 break;
3209 case WL_SCAN_RESULTS_SUCCESS:
3210 WL_TRACE(("iscanresults complete\n"));
3211 iscan->iscan_state = ISCAN_STATE_IDLE;
3212 wl_iw_send_scan_complete(iscan);
3213 break;
3214 case WL_SCAN_RESULTS_PENDING:
3215 WL_TRACE(("iscanresults pending\n"));
3216
3217 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
3218 iscan->timer_on = 1;
3219 break;
3220 case WL_SCAN_RESULTS_ABORTED:
3221 WL_TRACE(("iscanresults aborted\n"));
3222 iscan->iscan_state = ISCAN_STATE_IDLE;
3223 if (g_scan_specified_ssid == 0)
3224 wl_iw_send_scan_complete(iscan);
3225 else {
3226 iscan_pass_abort = TRUE;
3227 wl_iw_force_specific_scan(iscan);
3228 }
3229 break;
3230 case WL_SCAN_RESULTS_NO_MEM:
3231 WL_TRACE(("iscanresults can't alloc memory: skip\n"));
3232 iscan->iscan_state = ISCAN_STATE_IDLE;
3233 break;
3234 default:
3235 WL_TRACE(("iscanresults returned unknown status %d\n", status));
3236 break;
3237 }
3238
3239 net_os_wake_unlock(iscan->dev);
3240 }
3241
3242 if (iscan->timer_on) {
3243 iscan->timer_on = 0;
3244 del_timer_sync(&iscan->timer);
3245 }
3246 complete_and_exit(&tsk_ctl->completed, 0);
3247}
3248#endif
3249
3250#if !defined(CSCAN)
3251
3252static void
3253wl_iw_set_ss_cache_timer_flag(void)
3254{
3255 g_ss_cache_ctrl.m_timer_expired = 1;
3256 WL_TRACE(("%s called\n", __FUNCTION__));
3257}
3258
3259
3260static int
3261wl_iw_init_ss_cache_ctrl(void)
3262{
3263 WL_TRACE(("%s :\n", __FUNCTION__));
3264 g_ss_cache_ctrl.m_prev_scan_mode = 0;
3265 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
3266 g_ss_cache_ctrl.m_cache_head = NULL;
3267 g_ss_cache_ctrl.m_link_down = 0;
3268 g_ss_cache_ctrl.m_timer_expired = 0;
3269 memset(g_ss_cache_ctrl.m_active_bssid, 0, ETHER_ADDR_LEN);
3270
3271 g_ss_cache_ctrl.m_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
3272 if (!g_ss_cache_ctrl.m_timer) {
3273 return -ENOMEM;
3274 }
3275 g_ss_cache_ctrl.m_timer->function = (void *)wl_iw_set_ss_cache_timer_flag;
3276 init_timer(g_ss_cache_ctrl.m_timer);
3277
3278 return 0;
3279}
3280
3281
3282
3283static void
3284wl_iw_free_ss_cache(void)
3285{
3286 wl_iw_ss_cache_t *node, *cur;
3287 wl_iw_ss_cache_t **spec_scan_head;
3288
3289 WL_TRACE(("%s called\n", __FUNCTION__));
3290
3291 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3292 spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3293 node = *spec_scan_head;
3294
3295 for (;node;) {
3296 WL_TRACE(("%s : SSID - %s\n", __FUNCTION__, node->bss_info->SSID));
3297 cur = node;
3298 node = cur->next;
3299 kfree(cur);
3300 }
3301 *spec_scan_head = NULL;
3302 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3303}
3304
3305
3306
3307static int
3308wl_iw_run_ss_cache_timer(int kick_off)
3309{
3310 struct timer_list **timer;
3311
3312 timer = &g_ss_cache_ctrl.m_timer;
3313
3314 if (*timer) {
3315 if (kick_off) {
3316#ifdef CONFIG_PRESCANNED
3317 (*timer)->expires = jiffies + 70000 * HZ / 1000;
3318#else
3319 (*timer)->expires = jiffies + 30000 * HZ / 1000;
3320#endif
3321 add_timer(*timer);
3322 WL_TRACE(("%s : timer starts \n", __FUNCTION__));
3323 } else {
3324 del_timer_sync(*timer);
3325 WL_TRACE(("%s : timer stops \n", __FUNCTION__));
3326 }
3327 }
3328
3329 return 0;
3330}
3331
3332
3333static void
3334wl_iw_release_ss_cache_ctrl(void)
3335{
3336 WL_TRACE(("%s :\n", __FUNCTION__));
3337 wl_iw_free_ss_cache();
3338 wl_iw_run_ss_cache_timer(0);
3339 if (g_ss_cache_ctrl.m_timer) {
3340 kfree(g_ss_cache_ctrl.m_timer);
3341 }
3342}
3343
3344
3345
3346static void
3347wl_iw_reset_ss_cache(void)
3348{
3349 wl_iw_ss_cache_t *node, *prev, *cur;
3350 wl_iw_ss_cache_t **spec_scan_head;
3351
3352 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3353 spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3354 node = *spec_scan_head;
3355 prev = node;
3356
3357 for (;node;) {
3358 WL_TRACE(("%s : node SSID %s \n", __FUNCTION__, node->bss_info->SSID));
3359 if (!node->dirty) {
3360 cur = node;
3361 if (cur == *spec_scan_head) {
3362 *spec_scan_head = cur->next;
3363 prev = *spec_scan_head;
3364 }
3365 else {
3366 prev->next = cur->next;
3367 }
3368 node = cur->next;
3369
3370 WL_TRACE(("%s : Del node : SSID %s\n", __FUNCTION__, cur->bss_info->SSID));
3371 kfree(cur);
3372 continue;
3373 }
3374
3375 node->dirty = 0;
3376 prev = node;
3377 node = node->next;
3378 }
3379 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3380}
3381
3382
3383static int
3384wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list)
3385{
3386
3387 wl_iw_ss_cache_t *node, *prev, *leaf;
3388 wl_iw_ss_cache_t **spec_scan_head;
3389 wl_bss_info_t *bi = NULL;
3390 int i;
3391
3392
3393 if (!ss_list->count) {
3394 return 0;
3395 }
3396
3397 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3398 spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3399
3400 for (i = 0; i < ss_list->count; i++) {
3401
3402 node = *spec_scan_head;
3403 prev = node;
3404
3405 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
3406
3407 WL_TRACE(("%s : find %d with specific SSID %s\n", __FUNCTION__, i, bi->SSID));
3408 for (;node;) {
3409 if (!memcmp(&node->bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
3410
3411 WL_TRACE(("dirty marked : SSID %s\n", bi->SSID));
3412 node->dirty = 1;
3413 break;
3414 }
3415 prev = node;
3416 node = node->next;
3417 }
3418
3419 if (node) {
3420 continue;
3421 }
3422
3423 leaf = kmalloc(bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL);
3424 if (!leaf) {
3425 WL_ERROR(("Memory alloc failure %d\n",
3426 bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN));
3427 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3428 return -ENOMEM;
3429 }
3430
3431 memcpy(leaf->bss_info, bi, bi->length);
3432 leaf->next = NULL;
3433 leaf->dirty = 1;
3434 leaf->count = 1;
3435 leaf->version = ss_list->version;
3436
3437 if (!prev) {
3438 *spec_scan_head = leaf;
3439 }
3440 else {
3441 prev->next = leaf;
3442 }
3443 }
3444 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3445 return 0;
3446}
3447
3448
3449static int
3450wl_iw_merge_scan_cache(struct iw_request_info *info, char *extra, uint buflen_from_user,
3451__u16 *merged_len)
3452{
3453 wl_iw_ss_cache_t *node;
3454 wl_scan_results_t *list_merge;
3455
3456 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3457 node = g_ss_cache_ctrl.m_cache_head;
3458 for (;node;) {
3459 list_merge = (wl_scan_results_t *)&node->buflen;
3460 WL_TRACE(("%s: Cached Specific APs list=%d\n", __FUNCTION__, list_merge->count));
3461 if (buflen_from_user - *merged_len > 0) {
3462 *merged_len += (__u16) wl_iw_get_scan_prep(list_merge, info,
3463 extra + *merged_len, buflen_from_user - *merged_len);
3464 }
3465 else {
3466 WL_TRACE(("%s: exit with break\n", __FUNCTION__));
3467 break;
3468 }
3469 node = node->next;
3470 }
3471 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3472 return 0;
3473}
3474
3475
3476static int
3477wl_iw_delete_bss_from_ss_cache(void *addr)
3478{
3479
3480 wl_iw_ss_cache_t *node, *prev;
3481 wl_iw_ss_cache_t **spec_scan_head;
3482
3483 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
3484 spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3485 node = *spec_scan_head;
3486 prev = node;
3487 for (;node;) {
3488 if (!memcmp(&node->bss_info->BSSID, addr, ETHER_ADDR_LEN)) {
3489 if (node == *spec_scan_head) {
3490 *spec_scan_head = node->next;
3491 }
3492 else {
3493 prev->next = node->next;
3494 }
3495
3496 WL_TRACE(("%s : Del node : %s\n", __FUNCTION__, node->bss_info->SSID));
3497 kfree(node);
3498 break;
3499 }
3500
3501 prev = node;
3502 node = node->next;
3503 }
3504
3505 memset(addr, 0, ETHER_ADDR_LEN);
3506 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
3507 return 0;
3508}
3509
3510#endif
3511
3512static int
3513wl_iw_set_scan(
3514 struct net_device *dev,
3515 struct iw_request_info *info,
3516 union iwreq_data *wrqu,
3517 char *extra
3518)
3519{
3520 int error;
3521 WL_TRACE(("\n:%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name));
3522
3523#ifdef OEM_CHROMIUMOS
3524 g_set_essid_before_scan = FALSE;
3525#endif
3526
3527#if defined(CSCAN)
3528 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__));
3529 return -EINVAL;
3530#endif
3531
3532#if defined(SOFTAP)
3533
3534 if (ap_cfg_running) {
3535 WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
3536 return 0;
3537 }
3538#endif
3539
3540
3541 if (g_onoff == G_WLAN_SET_OFF)
3542 return 0;
3543
3544
3545 memset(&g_specific_ssid, 0, sizeof(g_specific_ssid));
3546#ifndef WL_IW_USE_ISCAN
3547
3548 g_scan_specified_ssid = 0;
3549#endif
3550
3551#if WIRELESS_EXT > 17
3552
3553 if (wrqu->data.length == sizeof(struct iw_scan_req)) {
3554 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
3555 struct iw_scan_req *req = (struct iw_scan_req *)extra;
3556#if defined(CONFIG_FIRST_SCAN)
3557 if (g_first_broadcast_scan != BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
3558
3559 WL_TRACE(("%s Ignoring SC %s first BC is not done = %d\n",
3560 __FUNCTION__, req->essid,
3561 g_first_broadcast_scan));
3562 return -EBUSY;
3563 }
3564#endif
3565 if (g_scan_specified_ssid) {
3566 WL_TRACE(("%s Specific SCAN is not done ignore scan for = %s \n",
3567 __FUNCTION__, req->essid));
3568
3569 return -EBUSY;
3570 }
3571 else {
3572 g_specific_ssid.SSID_len = MIN(sizeof(g_specific_ssid.SSID),
3573 req->essid_len);
3574 memcpy(g_specific_ssid.SSID, req->essid, g_specific_ssid.SSID_len);
3575 g_specific_ssid.SSID_len = htod32(g_specific_ssid.SSID_len);
3576 g_scan_specified_ssid = 1;
3577 WL_TRACE(("### Specific scan ssid=%s len=%d\n",
3578 g_specific_ssid.SSID, g_specific_ssid.SSID_len));
3579 }
3580 }
3581 }
3582#endif
3583
3584 if ((error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)))) {
3585 WL_TRACE(("#### Set SCAN for %s failed with %d\n", g_specific_ssid.SSID, error));
3586
3587 g_scan_specified_ssid = 0;
3588 return -EBUSY;
3589 }
3590
3591 return 0;
3592}
3593
3594#ifdef WL_IW_USE_ISCAN
3595int
3596wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
3597{
3598 wlc_ssid_t ssid;
3599 iscan_info_t *iscan = g_iscan;
3600
3601#if defined(CONFIG_FIRST_SCAN)
3602
3603 if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_IDLE) {
3604 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_STARTED;
3605 WL_TRACE(("%s: First Brodcast scan was forced\n", __FUNCTION__));
3606 }
3607 else if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) {
3608 WL_TRACE(("%s: ignore ISCAN request first BS is not done yet\n", __FUNCTION__));
3609 return 0;
3610 }
3611#endif
3612
3613#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3614 if (flag)
3615 rtnl_lock();
3616#endif
3617
3618 dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &iscan->scan_flag, sizeof(iscan->scan_flag));
3619 wl_iw_set_event_mask(dev);
3620
3621 WL_TRACE(("+++: Set Broadcast ISCAN\n"));
3622
3623 memset(&ssid, 0, sizeof(ssid));
3624
3625 iscan->list_cur = iscan->list_hdr;
3626 iscan->iscan_state = ISCAN_STATE_SCANING;
3627
3628 memset(&iscan->iscan_ex_params_p->params, 0, iscan->iscan_ex_param_size);
3629 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, &ssid);
3630 wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
3631
3632#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3633 if (flag)
3634 rtnl_unlock();
3635#endif
3636
3637 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
3638
3639 iscan->timer_on = 1;
3640
3641 return 0;
3642}
3643
3644static int
3645wl_iw_iscan_set_scan(
3646 struct net_device *dev,
3647 struct iw_request_info *info,
3648 union iwreq_data *wrqu,
3649 char *extra
3650)
3651{
3652 wlc_ssid_t ssid;
3653 iscan_info_t *iscan = g_iscan;
3654 int ret = 0;
3655
3656 WL_TRACE_SCAN(("%s: SIOCSIWSCAN : ISCAN\n", dev->name));
3657
3658#if defined(CSCAN)
3659 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__));
3660 return -EINVAL;
3661#endif
3662
3663 net_os_wake_lock(dev);
3664
3665
3666#if defined(SOFTAP)
3667 if (ap_cfg_running) {
3668 WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
3669 goto set_scan_end;
3670 }
3671#endif
3672
3673 if (g_onoff == G_WLAN_SET_OFF) {
3674 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
3675 goto set_scan_end;
3676 }
3677
3678#ifdef PNO_SUPPORT
3679
3680 if (dhd_dev_get_pno_status(dev)) {
3681 WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__));
3682 }
3683#endif
3684
3685
3686 if ((!iscan) || (iscan->tsk_ctl.thr_pid < 0)) {
3687 WL_ERROR(("%s error \n", __FUNCTION__));
3688 goto set_scan_end;
3689 }
3690
3691 if (g_scan_specified_ssid) {
3692 WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n",
3693 __FUNCTION__));
3694 ret = EBUSY;
3695 goto set_scan_end;
3696 }
3697
3698
3699 memset(&ssid, 0, sizeof(ssid));
3700
3701#if WIRELESS_EXT > 17
3702
3703 if (wrqu->data.length == sizeof(struct iw_scan_req)) {
3704 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
3705 int as = 0;
3706 struct iw_scan_req *req = (struct iw_scan_req *)extra;
3707
3708 ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len);
3709 memcpy(ssid.SSID, req->essid, ssid.SSID_len);
3710 ssid.SSID_len = htod32(ssid.SSID_len);
3711 dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as));
3712 wl_iw_set_event_mask(dev);
3713 ret = wl_iw_set_scan(dev, info, wrqu, extra);
3714 goto set_scan_end;
3715 }
3716 else {
3717 g_scan_specified_ssid = 0;
3718
3719 if (iscan->iscan_state == ISCAN_STATE_SCANING) {
3720 WL_TRACE(("%s ISCAN already in progress \n", __FUNCTION__));
3721 goto set_scan_end;
3722 }
3723 }
3724 }
3725#endif
3726
3727#if defined(CONFIG_FIRST_SCAN) && !defined(CSCAN)
3728 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
3729 if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) {
3730
3731 WL_ERROR(("%s Clean up First scan flag which is %d\n",
3732 __FUNCTION__, g_first_broadcast_scan));
3733 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
3734 }
3735 else {
3736 WL_ERROR(("%s Ignoring Broadcast Scan:First Scan is not done yet %d\n",
3737 __FUNCTION__, g_first_counter_scans));
3738 ret = -EBUSY;
3739 goto set_scan_end;
3740 }
3741 }
3742#endif
3743
3744 wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
3745
3746set_scan_end:
3747 net_os_wake_unlock(dev);
3748 return ret;
3749}
3750#endif
3751
3752#if WIRELESS_EXT > 17
3753static bool
3754ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len)
3755{
3756
3757
3758 uint8 *ie = *wpaie;
3759
3760
3761 if ((ie[1] >= 6) &&
3762 !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
3763 return TRUE;
3764 }
3765
3766
3767 ie += ie[1] + 2;
3768
3769 *tlvs_len -= (int)(ie - *tlvs);
3770
3771 *tlvs = ie;
3772 return FALSE;
3773}
3774
3775static bool
3776ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len)
3777{
3778
3779
3780 uint8 *ie = *wpsie;
3781
3782
3783 if ((ie[1] >= 4) &&
3784 !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
3785 return TRUE;
3786 }
3787
3788
3789 ie += ie[1] + 2;
3790
3791 *tlvs_len -= (int)(ie - *tlvs);
3792
3793 *tlvs = ie;
3794 return FALSE;
3795}
3796#endif
3797
3798
3799static int
3800wl_iw_handle_scanresults_ies(char **event_p, char *end,
3801 struct iw_request_info *info, wl_bss_info_t *bi)
3802{
3803#if WIRELESS_EXT > 17
3804 struct iw_event iwe;
3805 char *event;
3806
3807 event = *event_p;
3808 if (bi->ie_length) {
3809
3810 bcm_tlv_t *ie;
3811 uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3812 int ptr_len = bi->ie_length;
3813
3814 if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) {
3815 iwe.cmd = IWEVGENIE;
3816 iwe.u.data.length = ie->len + 2;
3817 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3818 }
3819 ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3820
3821 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
3822
3823 if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
3824 iwe.cmd = IWEVGENIE;
3825 iwe.u.data.length = ie->len + 2;
3826 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3827 break;
3828 }
3829 }
3830
3831 ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3832 ptr_len = bi->ie_length;
3833 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
3834 if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
3835 iwe.cmd = IWEVGENIE;
3836 iwe.u.data.length = ie->len + 2;
3837 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3838 break;
3839 }
3840 }
3841
3842 *event_p = event;
3843 }
3844#endif
3845
3846 return 0;
3847}
3848
3849#ifndef CSCAN
3850static uint
3851wl_iw_get_scan_prep(
3852 wl_scan_results_t *list,
3853 struct iw_request_info *info,
3854 char *extra,
3855 short max_size)
3856{
3857 int i, j;
3858 struct iw_event iwe;
3859 wl_bss_info_t *bi = NULL;
3860 char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value;
3861 int ret = 0;
3862
3863 if (!list) {
3864 WL_ERROR(("%s: Null list pointer", __FUNCTION__));
3865 return ret;
3866 }
3867
3868
3869
3870 for (i = 0; i < list->count && i < IW_MAX_AP; i++) {
3871 if (list->version != WL_BSS_INFO_VERSION) {
3872 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
3873 __FUNCTION__, list->version));
3874 return ret;
3875 }
3876
3877 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
3878
3879 WL_TRACE(("%s : %s\n", __FUNCTION__, bi->SSID));
3880
3881
3882 iwe.cmd = SIOCGIWAP;
3883 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
3884 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
3885 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
3886
3887 iwe.u.data.length = dtoh32(bi->SSID_len);
3888 iwe.cmd = SIOCGIWESSID;
3889 iwe.u.data.flags = 1;
3890 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
3891
3892
3893 if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
3894 iwe.cmd = SIOCGIWMODE;
3895 if (dtoh16(bi->capability) & DOT11_CAP_ESS)
3896 iwe.u.mode = IW_MODE_INFRA;
3897 else
3898 iwe.u.mode = IW_MODE_ADHOC;
3899 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
3900 }
3901
3902
3903 iwe.cmd = SIOCGIWFREQ;
3904 iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
3905 CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ?
3906 WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
3907 iwe.u.freq.e = 6;
3908 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
3909
3910
3911 iwe.cmd = IWEVQUAL;
3912 iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
3913 iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
3914 iwe.u.qual.noise = 0x100 + bi->phy_noise;
3915 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
3916
3917
3918 wl_iw_handle_scanresults_ies(&event, end, info, bi);
3919
3920
3921 iwe.cmd = SIOCGIWENCODE;
3922 if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
3923 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
3924 else
3925 iwe.u.data.flags = IW_ENCODE_DISABLED;
3926 iwe.u.data.length = 0;
3927 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
3928
3929
3930 if (bi->rateset.count) {
3931 if (((event -extra) + IW_EV_LCP_LEN) <= (uintptr)end) {
3932 value = event + IW_EV_LCP_LEN;
3933 iwe.cmd = SIOCGIWRATE;
3934
3935 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
3936 for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
3937 iwe.u.bitrate.value =
3938 (bi->rateset.rates[j] & 0x7f) * 500000;
3939 value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
3940 IW_EV_PARAM_LEN);
3941 }
3942 event = value;
3943 }
3944 }
3945 }
3946
3947 if ((ret = (event - extra)) < 0) {
3948 WL_ERROR(("==> Wrong size\n"));
3949 ret = 0;
3950 }
3951
3952 WL_TRACE(("%s: size=%d bytes prepared \n", __FUNCTION__, (unsigned int)(event - extra)));
3953 return (uint)ret;
3954}
3955
3956static int
3957wl_iw_get_scan(
3958 struct net_device *dev,
3959 struct iw_request_info *info,
3960 struct iw_point *dwrq,
3961 char *extra
3962)
3963{
3964 channel_info_t ci;
3965 wl_scan_results_t *list_merge;
3966 wl_scan_results_t *list = (wl_scan_results_t *) g_scan;
3967 int error;
3968 uint buflen_from_user = dwrq->length;
3969 uint len = G_SCAN_RESULTS;
3970 __u16 len_ret = 0;
3971#if !defined(CSCAN)
3972 __u16 merged_len = 0;
3973#endif
3974#if defined(WL_IW_USE_ISCAN)
3975 iscan_info_t *iscan = g_iscan;
3976 iscan_buf_t * p_buf;
3977#if !defined(CSCAN)
3978 uint32 counter = 0;
3979#endif
3980#endif
3981
3982 WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user));
3983
3984 if (!extra) {
3985 WL_TRACE(("%s: wl_iw_get_scan return -EINVAL\n", dev->name));
3986 return -EINVAL;
3987 }
3988
3989
3990 if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
3991 return error;
3992 ci.scan_channel = dtoh32(ci.scan_channel);
3993 if (ci.scan_channel)
3994 return -EAGAIN;
3995
3996#if !defined(CSCAN)
3997 if (g_ss_cache_ctrl.m_timer_expired) {
3998 wl_iw_free_ss_cache();
3999 g_ss_cache_ctrl.m_timer_expired ^= 1;
4000 }
4001 if ((!g_scan_specified_ssid && g_ss_cache_ctrl.m_prev_scan_mode) ||
4002 g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) {
4003 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
4004
4005 wl_iw_reset_ss_cache();
4006 }
4007 g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
4008 if (g_scan_specified_ssid) {
4009 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
4010 }
4011 else {
4012 g_ss_cache_ctrl.m_cons_br_scan_cnt++;
4013 }
4014#endif
4015
4016
4017
4018 if (g_scan_specified_ssid) {
4019
4020 list = kmalloc(len, GFP_KERNEL);
4021 if (!list) {
4022 WL_TRACE(("%s: wl_iw_get_scan return -ENOMEM\n", dev->name));
4023 g_scan_specified_ssid = 0;
4024 return -ENOMEM;
4025 }
4026 }
4027
4028 memset(list, 0, len);
4029 list->buflen = htod32(len);
4030 if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len))) {
4031 WL_ERROR(("%s: %s : Scan_results ERROR %d\n", dev->name, __FUNCTION__, error));
4032 dwrq->length = len;
4033 if (g_scan_specified_ssid) {
4034 g_scan_specified_ssid = 0;
4035 kfree(list);
4036 }
4037 return 0;
4038 }
4039 list->buflen = dtoh32(list->buflen);
4040 list->version = dtoh32(list->version);
4041 list->count = dtoh32(list->count);
4042
4043
4044 if (list->version != WL_BSS_INFO_VERSION) {
4045 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
4046 __FUNCTION__, list->version));
4047 if (g_scan_specified_ssid) {
4048 g_scan_specified_ssid = 0;
4049 kfree(list);
4050 }
4051 return -EINVAL;
4052 }
4053
4054#if !defined(CSCAN)
4055 if (g_scan_specified_ssid) {
4056
4057 wl_iw_add_bss_to_ss_cache(list);
4058 kfree(list);
4059 }
4060#endif
4061
4062#if !defined(CSCAN)
4063 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
4064#if defined(WL_IW_USE_ISCAN)
4065 if (g_scan_specified_ssid)
4066 WL_TRACE(("%s: Specified scan APs from scan=%d\n", __FUNCTION__, list->count));
4067 p_buf = iscan->list_hdr;
4068
4069 while (p_buf != iscan->list_cur) {
4070 list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
4071 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
4072 counter += list_merge->count;
4073 if (list_merge->count > 0)
4074 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info,
4075 extra+len_ret, buflen_from_user -len_ret);
4076 p_buf = p_buf->next;
4077 }
4078 WL_TRACE(("%s merged with total Bcast APs=%d\n", __FUNCTION__, counter));
4079#else
4080 list_merge = (wl_scan_results_t *) g_scan;
4081 len_ret = (__u16) wl_iw_get_scan_prep(list_merge, info, extra, buflen_from_user);
4082#endif
4083 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
4084 if (g_ss_cache_ctrl.m_link_down) {
4085
4086 wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid);
4087 }
4088
4089 wl_iw_merge_scan_cache(info, extra+len_ret, buflen_from_user-len_ret, &merged_len);
4090 len_ret += merged_len;
4091 wl_iw_run_ss_cache_timer(0);
4092 wl_iw_run_ss_cache_timer(1);
4093#else
4094
4095
4096 if (g_scan_specified_ssid) {
4097 WL_TRACE(("%s: Specified scan APs in the list =%d\n", __FUNCTION__, list->count));
4098 len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
4099 kfree(list);
4100
4101#if defined(WL_IW_USE_ISCAN)
4102 p_buf = iscan->list_hdr;
4103
4104 while (p_buf != iscan->list_cur) {
4105 list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
4106 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
4107 if (list_merge->count > 0)
4108 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info,
4109 extra+len_ret, buflen_from_user -len_ret);
4110 p_buf = p_buf->next;
4111 }
4112#else
4113 list_merge = (wl_scan_results_t *) g_scan;
4114 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
4115 if (list_merge->count > 0)
4116 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, extra+len_ret,
4117 buflen_from_user -len_ret);
4118#endif
4119 }
4120 else {
4121 list = (wl_scan_results_t *) g_scan;
4122 len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
4123 }
4124#endif
4125
4126#if defined(WL_IW_USE_ISCAN)
4127
4128 g_scan_specified_ssid = 0;
4129#endif
4130
4131 if ((len_ret + WE_ADD_EVENT_FIX) < buflen_from_user)
4132 len = len_ret;
4133
4134 dwrq->length = len;
4135 dwrq->flags = 0;
4136
4137 WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, list->count));
4138 return 0;
4139}
4140#endif
4141
4142#if defined(WL_IW_USE_ISCAN)
4143static int
4144wl_iw_iscan_get_scan(
4145 struct net_device *dev,
4146 struct iw_request_info *info,
4147 struct iw_point *dwrq,
4148 char *extra
4149)
4150{
4151 wl_scan_results_t *list;
4152 struct iw_event iwe;
4153 wl_bss_info_t *bi = NULL;
4154 int ii, j;
4155 int apcnt;
4156 char *event = extra, *end = extra + dwrq->length, *value;
4157 iscan_info_t *iscan = g_iscan;
4158 iscan_buf_t * p_buf;
4159 uint32 counter = 0;
4160 uint8 channel;
4161#if !defined(CSCAN)
4162 __u16 merged_len = 0;
4163 uint buflen_from_user = dwrq->length;
4164#endif
4165
4166 WL_TRACE(("%s %s buflen_from_user %d:\n", dev->name, __FUNCTION__, dwrq->length));
4167
4168#if defined(SOFTAP)
4169 if (ap_cfg_running) {
4170 WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
4171 return -EINVAL;
4172 }
4173#endif
4174
4175 if (!extra) {
4176 WL_TRACE(("%s: INVALID SIOCGIWSCAN GET bad parameter\n", dev->name));
4177 return -EINVAL;
4178 }
4179
4180#if defined(CONFIG_FIRST_SCAN)
4181 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_READY) {
4182 WL_TRACE(("%s %s: first ISCAN results are NOT ready yet \n",
4183 dev->name, __FUNCTION__));
4184 return -EAGAIN;
4185 }
4186#endif
4187
4188 if ((!iscan) || (iscan->tsk_ctl.thr_pid < 0)) {
4189 WL_ERROR(("%ssysioc_pid\n", __FUNCTION__));
4190 return EAGAIN;
4191 }
4192
4193
4194
4195#if !defined(CSCAN)
4196 if (g_ss_cache_ctrl.m_timer_expired) {
4197 wl_iw_free_ss_cache();
4198 g_ss_cache_ctrl.m_timer_expired ^= 1;
4199 }
4200 if (g_scan_specified_ssid) {
4201 return wl_iw_get_scan(dev, info, dwrq, extra);
4202 }
4203 else {
4204 if (g_ss_cache_ctrl.m_link_down) {
4205
4206 wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid);
4207 }
4208 if (g_ss_cache_ctrl.m_prev_scan_mode || g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) {
4209 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
4210
4211 wl_iw_reset_ss_cache();
4212 }
4213 g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
4214 g_ss_cache_ctrl.m_cons_br_scan_cnt++;
4215 }
4216#endif
4217
4218 WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name));
4219 apcnt = 0;
4220 p_buf = iscan->list_hdr;
4221
4222 while (p_buf != iscan->list_cur) {
4223 list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
4224
4225 counter += list->count;
4226
4227 if (list->version != WL_BSS_INFO_VERSION) {
4228 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
4229 __FUNCTION__, list->version));
4230 return -EINVAL;
4231 }
4232
4233 bi = NULL;
4234 for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) {
4235 bi = (bi ?
4236 (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) :
4237 list->bss_info);
4238 ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
4239 WLC_IW_ISCAN_MAXLEN));
4240
4241
4242 if (event + ETHER_ADDR_LEN + bi->SSID_len +
4243 IW_EV_UINT_LEN + IW_EV_FREQ_LEN + IW_EV_QUAL_LEN >= end)
4244 return -E2BIG;
4245
4246 iwe.cmd = SIOCGIWAP;
4247 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
4248 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
4249 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
4250
4251
4252 iwe.u.data.length = dtoh32(bi->SSID_len);
4253 iwe.cmd = SIOCGIWESSID;
4254 iwe.u.data.flags = 1;
4255 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
4256
4257
4258 if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
4259 iwe.cmd = SIOCGIWMODE;
4260 if (dtoh16(bi->capability) & DOT11_CAP_ESS)
4261 iwe.u.mode = IW_MODE_INFRA;
4262 else
4263 iwe.u.mode = IW_MODE_ADHOC;
4264 event = IWE_STREAM_ADD_EVENT(info, event, end,
4265 &iwe, IW_EV_UINT_LEN);
4266 }
4267
4268
4269 iwe.cmd = SIOCGIWFREQ;
4270 channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
4271 iwe.u.freq.m = wf_channel2mhz(channel,
4272 channel <= CH_MAX_2G_CHANNEL ?
4273 WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
4274 iwe.u.freq.e = 6;
4275 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
4276
4277
4278 iwe.cmd = IWEVQUAL;
4279 iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
4280 iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
4281 iwe.u.qual.noise = 0x100 + bi->phy_noise;
4282 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
4283
4284
4285 wl_iw_handle_scanresults_ies(&event, end, info, bi);
4286
4287
4288 iwe.cmd = SIOCGIWENCODE;
4289 if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
4290 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
4291 else
4292 iwe.u.data.flags = IW_ENCODE_DISABLED;
4293 iwe.u.data.length = 0;
4294 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
4295
4296
4297 if (bi->rateset.count) {
4298 if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end)
4299 return -E2BIG;
4300
4301 value = event + IW_EV_LCP_LEN;
4302 iwe.cmd = SIOCGIWRATE;
4303
4304 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
4305 for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
4306 iwe.u.bitrate.value =
4307 (bi->rateset.rates[j] & 0x7f) * 500000;
4308 value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
4309 IW_EV_PARAM_LEN);
4310 }
4311 event = value;
4312 }
4313 }
4314 p_buf = p_buf->next;
4315 }
4316
4317 dwrq->length = event - extra;
4318 dwrq->flags = 0;
4319
4320#if !defined(CSCAN)
4321
4322 wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len);
4323 dwrq->length += merged_len;
4324 wl_iw_run_ss_cache_timer(0);
4325 wl_iw_run_ss_cache_timer(1);
4326#endif
4327
4328#if defined(CONFIG_FIRST_SCAN)
4329 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
4330#endif
4331
4332 WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter));
4333
4334 return 0;
4335}
4336#endif
4337
4338#define WL_JOIN_PARAMS_MAX 1600
4339#ifdef CONFIG_PRESCANNED
4340static int
4341check_prescan(wl_join_params_t *join_params, int *join_params_size)
4342{
4343 int cnt = 0;
4344 int indx = 0;
4345 wl_iw_ss_cache_t *node = NULL;
4346 wl_bss_info_t *bi = NULL;
4347 iscan_info_t *iscan = g_iscan;
4348 iscan_buf_t * buf;
4349 wl_scan_results_t *list;
4350 char *destbuf;
4351
4352 buf = iscan->list_hdr;
4353
4354 while (buf) {
4355 list = &((wl_iscan_results_t*)buf->iscan_buf)->results;
4356 bi = NULL;
4357 for (indx = 0; indx < list->count; indx++) {
4358 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length))
4359 : list->bss_info;
4360 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
4361 continue;
4362 if ((dtoh32(bi->SSID_len) != join_params->ssid.SSID_len) ||
4363 memcmp(bi->SSID, join_params->ssid.SSID,
4364 join_params->ssid.SSID_len))
4365 continue;
4366 memcpy(&join_params->params.chanspec_list[cnt],
4367 &bi->chanspec, sizeof(chanspec_t));
4368 WL_ERROR(("iscan : chanspec :%d, count %d \n", bi->chanspec, cnt));
4369 cnt++;
4370 }
4371 buf = buf->next;
4372 }
4373
4374 if (!cnt) {
4375 MUTEX_LOCK_WL_SCAN_SET();
4376 node = g_ss_cache_ctrl.m_cache_head;
4377 for (; node; ) {
4378 if (!memcmp(&node->bss_info->SSID, join_params->ssid.SSID,
4379 join_params->ssid.SSID_len)) {
4380 memcpy(&join_params->params.chanspec_list[cnt],
4381 &node->bss_info->chanspec, sizeof(chanspec_t));
4382 WL_ERROR(("cache_scan : chanspec :%d, count %d \n",
4383 (int)node->bss_info->chanspec, cnt));
4384 cnt++;
4385 }
4386 node = node->next;
4387 }
4388 MUTEX_UNLOCK_WL_SCAN_SET();
4389 }
4390
4391 if (!cnt) {
4392 return 0;
4393 }
4394
4395 destbuf = (char *)&join_params->params.chanspec_list[cnt];
4396 *join_params_size = destbuf - (char*)join_params;
4397 join_params->ssid.SSID_len = htod32(g_ssid.SSID_len);
4398 memcpy(&(join_params->params.bssid), &ether_bcast, ETHER_ADDR_LEN);
4399 join_params->params.chanspec_num = htod32(cnt);
4400
4401 if ((*join_params_size) > WL_JOIN_PARAMS_MAX) {
4402 WL_ERROR(("can't fit bssids for all %d APs found\n", cnt));
4403 kfree(join_params);
4404 return 0;
4405 }
4406
4407 WL_ERROR(("Passing %d channel/bssid pairs.\n", cnt));
4408 return cnt;
4409}
4410#endif
4411
4412static int
4413wl_iw_set_essid(
4414 struct net_device *dev,
4415 struct iw_request_info *info,
4416 struct iw_point *dwrq,
4417 char *extra
4418)
4419{
4420 int error;
4421 wl_join_params_t *join_params;
4422 int join_params_size;
4423
4424 WL_TRACE(("%s: SIOCSIWESSID\n", dev->name));
4425
4426 RETURN_IF_EXTRA_NULL(extra);
4427
4428#ifdef OEM_CHROMIUMOS
4429 if (g_set_essid_before_scan)
4430 return -EAGAIN;
4431#endif
4432 if (!(join_params = kmalloc(WL_JOIN_PARAMS_MAX, GFP_KERNEL))) {
4433 WL_ERROR(("allocation failed for join_params size is %d\n", WL_JOIN_PARAMS_MAX));
4434 return -ENOMEM;
4435 }
4436
4437 memset(join_params, 0, WL_JOIN_PARAMS_MAX);
4438
4439
4440 memset(&g_ssid, 0, sizeof(g_ssid));
4441
4442 if (dwrq->length && extra) {
4443#if WIRELESS_EXT > 20
4444 g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length);
4445#else
4446 g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length-1);
4447#endif
4448 memcpy(g_ssid.SSID, extra, g_ssid.SSID_len);
4449
4450#ifdef CONFIG_PRESCANNED
4451 memcpy(join_params->ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
4452 join_params->ssid.SSID_len = g_ssid.SSID_len;
4453
4454 if (check_prescan(join_params, &join_params_size)) {
4455 if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID,
4456 join_params, join_params_size))) {
4457 WL_ERROR(("Invalid ioctl data=%d\n", error));
4458 kfree(join_params);
4459 return error;
4460 }
4461 kfree(join_params);
4462 return 0;
4463 } else {
4464 WL_ERROR(("No matched found\n Trying to join to specific channel\n"));
4465 }
4466#endif
4467 } else {
4468
4469 g_ssid.SSID_len = 0;
4470 }
4471 g_ssid.SSID_len = htod32(g_ssid.SSID_len);
4472
4473
4474 memset(join_params, 0, sizeof(*join_params));
4475 join_params_size = sizeof(join_params->ssid);
4476
4477 memcpy(join_params->ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
4478 join_params->ssid.SSID_len = htod32(g_ssid.SSID_len);
4479 memcpy(&(join_params->params.bssid), &ether_bcast, ETHER_ADDR_LEN);
4480
4481
4482
4483 wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, join_params, &join_params_size);
4484
4485 if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, join_params, join_params_size))) {
4486 WL_ERROR(("Invalid ioctl data=%d\n", error));
4487 return error;
4488 }
4489
4490 if (g_ssid.SSID_len) {
4491 WL_ERROR(("%s: join SSID=%s ch=%d\n", __FUNCTION__,
4492 g_ssid.SSID, g_wl_iw_params.target_channel));
4493 }
4494 kfree(join_params);
4495 return 0;
4496}
4497
4498static int
4499wl_iw_get_essid(
4500 struct net_device *dev,
4501 struct iw_request_info *info,
4502 struct iw_point *dwrq,
4503 char *extra
4504)
4505{
4506 wlc_ssid_t ssid;
4507 int error;
4508
4509 WL_TRACE(("%s: SIOCGIWESSID\n", dev->name));
4510
4511 if (!extra)
4512 return -EINVAL;
4513
4514 if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) {
4515 WL_ERROR(("Error getting the SSID\n"));
4516 return error;
4517 }
4518
4519 ssid.SSID_len = dtoh32(ssid.SSID_len);
4520
4521
4522 memcpy(extra, ssid.SSID, ssid.SSID_len);
4523
4524 dwrq->length = ssid.SSID_len;
4525
4526 dwrq->flags = 1;
4527
4528 return 0;
4529}
4530
4531static int
4532wl_iw_set_nick(
4533 struct net_device *dev,
4534 struct iw_request_info *info,
4535 struct iw_point *dwrq,
4536 char *extra
4537)
4538{
4539 wl_iw_t *iw = NETDEV_PRIV(dev);
4540
4541 WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name));
4542
4543 if (!extra)
4544 return -EINVAL;
4545
4546
4547 if (dwrq->length > sizeof(iw->nickname))
4548 return -E2BIG;
4549
4550 memcpy(iw->nickname, extra, dwrq->length);
4551 iw->nickname[dwrq->length - 1] = '\0';
4552
4553 return 0;
4554}
4555
4556static int
4557wl_iw_get_nick(
4558 struct net_device *dev,
4559 struct iw_request_info *info,
4560 struct iw_point *dwrq,
4561 char *extra
4562)
4563{
4564 wl_iw_t *iw = NETDEV_PRIV(dev);
4565
4566 WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name));
4567
4568 if (!extra)
4569 return -EINVAL;
4570
4571 strcpy(extra, iw->nickname);
4572 dwrq->length = strlen(extra) + 1;
4573
4574 return 0;
4575}
4576
4577static int
4578wl_iw_set_rate(
4579 struct net_device *dev,
4580 struct iw_request_info *info,
4581 struct iw_param *vwrq,
4582 char *extra
4583)
4584{
4585 wl_rateset_t rateset;
4586 int error, rate, i, error_bg, error_a;
4587
4588 WL_TRACE(("%s: SIOCSIWRATE\n", dev->name));
4589
4590
4591 if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
4592 return error;
4593
4594 rateset.count = dtoh32(rateset.count);
4595
4596 if (vwrq->value < 0) {
4597
4598 rate = rateset.rates[rateset.count - 1] & 0x7f;
4599 } else if (vwrq->value < rateset.count) {
4600
4601 rate = rateset.rates[vwrq->value] & 0x7f;
4602 } else {
4603
4604 rate = vwrq->value / 500000;
4605 }
4606
4607 if (vwrq->fixed) {
4608
4609 error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate);
4610 error_a = dev_wlc_intvar_set(dev, "a_rate", rate);
4611
4612 if (error_bg && error_a)
4613 return (error_bg | error_a);
4614 } else {
4615
4616
4617 error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0);
4618
4619 error_a = dev_wlc_intvar_set(dev, "a_rate", 0);
4620
4621 if (error_bg && error_a)
4622 return (error_bg | error_a);
4623
4624
4625 for (i = 0; i < rateset.count; i++)
4626 if ((rateset.rates[i] & 0x7f) > rate)
4627 break;
4628 rateset.count = htod32(i);
4629
4630
4631 if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset))))
4632 return error;
4633 }
4634
4635 return 0;
4636}
4637
4638static int
4639wl_iw_get_rate(
4640 struct net_device *dev,
4641 struct iw_request_info *info,
4642 struct iw_param *vwrq,
4643 char *extra
4644)
4645{
4646 int error, rate;
4647
4648 WL_TRACE(("%s: SIOCGIWRATE\n", dev->name));
4649
4650
4651 if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate))))
4652 return error;
4653 rate = dtoh32(rate);
4654 vwrq->value = rate * 500000;
4655
4656 return 0;
4657}
4658
4659static int
4660wl_iw_set_rts(
4661 struct net_device *dev,
4662 struct iw_request_info *info,
4663 struct iw_param *vwrq,
4664 char *extra
4665)
4666{
4667 int error, rts;
4668
4669 WL_TRACE(("%s: SIOCSIWRTS\n", dev->name));
4670
4671 if (vwrq->disabled)
4672 rts = DOT11_DEFAULT_RTS_LEN;
4673 else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN)
4674 return -EINVAL;
4675 else
4676 rts = vwrq->value;
4677
4678 if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts)))
4679 return error;
4680
4681 return 0;
4682}
4683
4684static int
4685wl_iw_get_rts(
4686 struct net_device *dev,
4687 struct iw_request_info *info,
4688 struct iw_param *vwrq,
4689 char *extra
4690)
4691{
4692 int error, rts;
4693
4694 WL_TRACE(("%s: SIOCGIWRTS\n", dev->name));
4695
4696 if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts)))
4697 return error;
4698
4699 vwrq->value = rts;
4700 vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN);
4701 vwrq->fixed = 1;
4702
4703 return 0;
4704}
4705
4706static int
4707wl_iw_set_frag(
4708 struct net_device *dev,
4709 struct iw_request_info *info,
4710 struct iw_param *vwrq,
4711 char *extra
4712)
4713{
4714 int error, frag;
4715
4716 WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name));
4717
4718 if (vwrq->disabled)
4719 frag = DOT11_DEFAULT_FRAG_LEN;
4720 else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN)
4721 return -EINVAL;
4722 else
4723 frag = vwrq->value;
4724
4725 if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag)))
4726 return error;
4727
4728 return 0;
4729}
4730
4731static int
4732wl_iw_get_frag(
4733 struct net_device *dev,
4734 struct iw_request_info *info,
4735 struct iw_param *vwrq,
4736 char *extra
4737)
4738{
4739 int error, fragthreshold;
4740
4741 WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name));
4742
4743 if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold)))
4744 return error;
4745
4746 vwrq->value = fragthreshold;
4747 vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN);
4748 vwrq->fixed = 1;
4749
4750 return 0;
4751}
4752
4753static int
4754wl_iw_set_txpow(
4755 struct net_device *dev,
4756 struct iw_request_info *info,
4757 struct iw_param *vwrq,
4758 char *extra
4759)
4760{
4761 int error, disable;
4762 uint16 txpwrmw;
4763 WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name));
4764
4765
4766 disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
4767 disable += WL_RADIO_SW_DISABLE << 16;
4768
4769 disable = htod32(disable);
4770 if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable))))
4771 return error;
4772
4773
4774 if (disable & WL_RADIO_SW_DISABLE)
4775 return 0;
4776
4777
4778 if (!(vwrq->flags & IW_TXPOW_MWATT))
4779 return -EINVAL;
4780
4781
4782 if (vwrq->value < 0)
4783 return 0;
4784
4785 if (vwrq->value > 0xffff) txpwrmw = 0xffff;
4786 else txpwrmw = (uint16)vwrq->value;
4787
4788
4789 error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw)));
4790 return error;
4791}
4792
4793static int
4794wl_iw_get_txpow(
4795 struct net_device *dev,
4796 struct iw_request_info *info,
4797 struct iw_param *vwrq,
4798 char *extra
4799)
4800{
4801 int error, disable, txpwrdbm;
4802 uint8 result;
4803
4804 WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name));
4805
4806 if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) ||
4807 (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm)))
4808 return error;
4809
4810 disable = dtoh32(disable);
4811 result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE);
4812 vwrq->value = (int32)bcm_qdbm_to_mw(result);
4813 vwrq->fixed = 0;
4814 vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0;
4815 vwrq->flags = IW_TXPOW_MWATT;
4816
4817 return 0;
4818}
4819
4820#if WIRELESS_EXT > 10
4821static int
4822wl_iw_set_retry(
4823 struct net_device *dev,
4824 struct iw_request_info *info,
4825 struct iw_param *vwrq,
4826 char *extra
4827)
4828{
4829 int error, lrl, srl;
4830
4831 WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name));
4832
4833
4834 if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
4835 return -EINVAL;
4836
4837
4838 if (vwrq->flags & IW_RETRY_LIMIT) {
4839
4840
4841#if WIRELESS_EXT > 20
4842 if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) ||
4843 !((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) {
4844#else
4845 if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) {
4846#endif
4847 lrl = htod32(vwrq->value);
4848 if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl))))
4849 return error;
4850 }
4851
4852
4853#if WIRELESS_EXT > 20
4854 if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) ||
4855 !((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) {
4856#else
4857 if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) {
4858#endif
4859 srl = htod32(vwrq->value);
4860 if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl))))
4861 return error;
4862 }
4863 }
4864 return 0;
4865}
4866
4867static int
4868wl_iw_get_retry(
4869 struct net_device *dev,
4870 struct iw_request_info *info,
4871 struct iw_param *vwrq,
4872 char *extra
4873)
4874{
4875 int error, lrl, srl;
4876
4877 WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name));
4878
4879 vwrq->disabled = 0;
4880
4881
4882 if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
4883 return -EINVAL;
4884
4885
4886 if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) ||
4887 (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl))))
4888 return error;
4889
4890 lrl = dtoh32(lrl);
4891 srl = dtoh32(srl);
4892
4893
4894 if (vwrq->flags & IW_RETRY_MAX) {
4895 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
4896 vwrq->value = lrl;
4897 } else {
4898 vwrq->flags = IW_RETRY_LIMIT;
4899 vwrq->value = srl;
4900 if (srl != lrl)
4901 vwrq->flags |= IW_RETRY_MIN;
4902 }
4903
4904 return 0;
4905}
4906#endif
4907
4908static int
4909wl_iw_set_encode(
4910 struct net_device *dev,
4911 struct iw_request_info *info,
4912 struct iw_point *dwrq,
4913 char *extra
4914)
4915{
4916 wl_wsec_key_t key;
4917 int error, val, wsec;
4918
4919 WL_TRACE(("%s: SIOCSIWENCODE index %d, len %d, flags %04x (%s%s%s%s%s)\n",
4920 dev->name, dwrq->flags & IW_ENCODE_INDEX, dwrq->length, dwrq->flags,
4921 dwrq->flags & IW_ENCODE_NOKEY ? "NOKEY" : "",
4922 dwrq->flags & IW_ENCODE_DISABLED ? " DISABLED" : "",
4923 dwrq->flags & IW_ENCODE_RESTRICTED ? " RESTRICTED" : "",
4924 dwrq->flags & IW_ENCODE_OPEN ? " OPEN" : "",
4925 dwrq->flags & IW_ENCODE_TEMP ? " TEMP" : ""));
4926
4927 memset(&key, 0, sizeof(key));
4928
4929 if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
4930
4931 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
4932 val = htod32(key.index);
4933 if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
4934 return error;
4935 val = dtoh32(val);
4936 if (val)
4937 break;
4938 }
4939
4940 if (key.index == DOT11_MAX_DEFAULT_KEYS)
4941 key.index = 0;
4942 } else {
4943 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
4944 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
4945 return -EINVAL;
4946 }
4947
4948
4949 if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) {
4950
4951 val = htod32(key.index);
4952 if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val))))
4953 return error;
4954 } else {
4955 key.len = dwrq->length;
4956
4957 if (dwrq->length > sizeof(key.data))
4958 return -EINVAL;
4959
4960 memcpy(key.data, extra, dwrq->length);
4961
4962 key.flags = WL_PRIMARY_KEY;
4963 switch (key.len) {
4964 case WEP1_KEY_SIZE:
4965 key.algo = CRYPTO_ALGO_WEP1;
4966 break;
4967 case WEP128_KEY_SIZE:
4968 key.algo = CRYPTO_ALGO_WEP128;
4969 break;
4970#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
4971 case TKIP_KEY_SIZE:
4972 key.algo = CRYPTO_ALGO_TKIP;
4973 break;
4974#endif
4975 case AES_KEY_SIZE:
4976 key.algo = CRYPTO_ALGO_AES_CCM;
4977 break;
4978 default:
4979 return -EINVAL;
4980 }
4981
4982
4983 swap_key_from_BE(&key);
4984 if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))
4985 return error;
4986 }
4987
4988
4989 val = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED;
4990
4991 if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec)))
4992 return error;
4993
4994 wsec &= ~(WEP_ENABLED);
4995 wsec |= val;
4996
4997 if ((error = dev_wlc_intvar_set(dev, "wsec", wsec)))
4998 return error;
4999
5000
5001 val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0;
5002 val = htod32(val);
5003 if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val))))
5004 return error;
5005
5006 return 0;
5007}
5008
5009static int
5010wl_iw_get_encode(
5011 struct net_device *dev,
5012 struct iw_request_info *info,
5013 struct iw_point *dwrq,
5014 char *extra
5015)
5016{
5017 wl_wsec_key_t key;
5018 int error, val, wsec, auth;
5019
5020 WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name));
5021
5022
5023 bzero(&key, sizeof(wl_wsec_key_t));
5024
5025 if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
5026
5027 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
5028 val = key.index;
5029 if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
5030 return error;
5031 val = dtoh32(val);
5032 if (val)
5033 break;
5034 }
5035 } else
5036 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5037
5038 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
5039 key.index = 0;
5040
5041
5042
5043 if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) ||
5044 (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth))))
5045 return error;
5046
5047 swap_key_to_BE(&key);
5048
5049 wsec = dtoh32(wsec);
5050 auth = dtoh32(auth);
5051
5052 dwrq->length = MIN(DOT11_MAX_KEY_SIZE, key.len);
5053
5054
5055 dwrq->flags = key.index + 1;
5056 if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) {
5057
5058 dwrq->flags |= IW_ENCODE_DISABLED;
5059 }
5060 if (auth) {
5061
5062 dwrq->flags |= IW_ENCODE_RESTRICTED;
5063 }
5064
5065
5066 if (dwrq->length && extra)
5067 memcpy(extra, key.data, dwrq->length);
5068
5069 return 0;
5070}
5071
5072static int
5073wl_iw_set_power(
5074 struct net_device *dev,
5075 struct iw_request_info *info,
5076 struct iw_param *vwrq,
5077 char *extra
5078)
5079{
5080 int error, pm;
5081
5082 WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name));
5083
5084 pm = vwrq->disabled ? PM_OFF : PM_MAX;
5085
5086 pm = htod32(pm);
5087 if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm))))
5088 return error;
5089
5090 return 0;
5091}
5092
5093static int
5094wl_iw_get_power(
5095 struct net_device *dev,
5096 struct iw_request_info *info,
5097 struct iw_param *vwrq,
5098 char *extra
5099)
5100{
5101 int error, pm;
5102
5103 WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name));
5104
5105 if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))))
5106 return error;
5107
5108 pm = dtoh32(pm);
5109 vwrq->disabled = pm ? 0 : 1;
5110 vwrq->flags = IW_POWER_ALL_R;
5111
5112 return 0;
5113}
5114
5115#if WIRELESS_EXT > 17
5116static int
5117wl_iw_set_wpaie(
5118 struct net_device *dev,
5119 struct iw_request_info *info,
5120 struct iw_point *iwp,
5121 char *extra
5122)
5123{
5124
5125 WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name));
5126
5127 RETURN_IF_EXTRA_NULL(extra);
5128
5129#ifdef DHD_DEBUG
5130 {
5131 int i;
5132
5133 for (i = 0; i < iwp->length; i++)
5134 WL_TRACE(("%02X ", extra[i]));
5135 WL_TRACE(("\n"));
5136 }
5137#endif
5138
5139 dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
5140
5141 return 0;
5142}
5143
5144static int
5145wl_iw_get_wpaie(
5146 struct net_device *dev,
5147 struct iw_request_info *info,
5148 struct iw_point *iwp,
5149 char *extra
5150)
5151{
5152 WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name));
5153 iwp->length = 64;
5154 dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
5155 return 0;
5156}
5157
5158static int
5159wl_iw_set_encodeext(
5160 struct net_device *dev,
5161 struct iw_request_info *info,
5162 struct iw_point *dwrq,
5163 char *extra
5164)
5165{
5166 wl_wsec_key_t key;
5167 int error;
5168 struct iw_encode_ext *iwe;
5169
5170 WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name));
5171
5172 RETURN_IF_EXTRA_NULL(extra);
5173
5174 memset(&key, 0, sizeof(key));
5175 iwe = (struct iw_encode_ext *)extra;
5176
5177
5178 if (dwrq->flags & IW_ENCODE_DISABLED) {
5179
5180 }
5181
5182
5183 key.index = 0;
5184 if (dwrq->flags & IW_ENCODE_INDEX)
5185 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5186
5187 key.len = iwe->key_len;
5188
5189
5190 if (!ETHER_ISMULTI(iwe->addr.sa_data))
5191 bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN);
5192
5193
5194 if (key.len == 0) {
5195 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
5196 WL_WSEC(("Changing the the primary Key to %d\n", key.index));
5197
5198 key.index = htod32(key.index);
5199 error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
5200 &key.index, sizeof(key.index));
5201 if (error)
5202 return error;
5203 }
5204
5205 else {
5206 swap_key_from_BE(&key);
5207 dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
5208 }
5209 }
5210 else {
5211 if (iwe->key_len > sizeof(key.data))
5212 return -EINVAL;
5213
5214 WL_WSEC(("Setting the key index %d\n", key.index));
5215 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
5216 WL_WSEC(("key is a Primary Key\n"));
5217 key.flags = WL_PRIMARY_KEY;
5218 }
5219
5220 bcopy((void *)iwe->key, key.data, iwe->key_len);
5221
5222 if (iwe->alg == IW_ENCODE_ALG_TKIP) {
5223 uint8 keybuf[8];
5224 bcopy(&key.data[24], keybuf, sizeof(keybuf));
5225 bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
5226 bcopy(keybuf, &key.data[16], sizeof(keybuf));
5227 }
5228
5229
5230 if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
5231 uchar *ivptr;
5232 ivptr = (uchar *)iwe->rx_seq;
5233 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
5234 (ivptr[3] << 8) | ivptr[2];
5235 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
5236 key.iv_initialized = TRUE;
5237 }
5238
5239 switch (iwe->alg) {
5240 case IW_ENCODE_ALG_NONE:
5241 key.algo = CRYPTO_ALGO_OFF;
5242 break;
5243 case IW_ENCODE_ALG_WEP:
5244 if (iwe->key_len == WEP1_KEY_SIZE)
5245 key.algo = CRYPTO_ALGO_WEP1;
5246 else
5247 key.algo = CRYPTO_ALGO_WEP128;
5248 break;
5249 case IW_ENCODE_ALG_TKIP:
5250 key.algo = CRYPTO_ALGO_TKIP;
5251 break;
5252 case IW_ENCODE_ALG_CCMP:
5253 key.algo = CRYPTO_ALGO_AES_CCM;
5254 break;
5255 default:
5256 break;
5257 }
5258 swap_key_from_BE(&key);
5259
5260 dhd_wait_pend8021x(dev);
5261
5262 error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
5263 if (error)
5264 return error;
5265 }
5266 return 0;
5267}
5268
5269#if WIRELESS_EXT > 17
5270struct {
5271 pmkid_list_t pmkids;
5272 pmkid_t foo[MAXPMKID-1];
5273} pmkid_list;
5274
5275static int
5276wl_iw_set_pmksa(
5277 struct net_device *dev,
5278 struct iw_request_info *info,
5279 struct iw_param *vwrq,
5280 char *extra
5281)
5282{
5283 struct iw_pmksa *iwpmksa;
5284 uint i;
5285 int ret = 0;
5286 char eabuf[ETHER_ADDR_STR_LEN];
5287 pmkid_t * pmkid_array = pmkid_list.pmkids.pmkid;
5288
5289 WL_WSEC(("%s: SIOCSIWPMKSA\n", dev->name));
5290
5291 RETURN_IF_EXTRA_NULL(extra);
5292
5293 iwpmksa = (struct iw_pmksa *)extra;
5294 bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
5295
5296 if (iwpmksa->cmd == IW_PMKSA_FLUSH) {
5297 WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"));
5298 bzero((char *)&pmkid_list, sizeof(pmkid_list));
5299 }
5300
5301 else if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
5302 {
5303 pmkid_list_t pmkid, *pmkidptr;
5304 uint j;
5305 pmkidptr = &pmkid;
5306
5307 bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID,
5308 ETHER_ADDR_LEN);
5309 bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN);
5310
5311 WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ",
5312 bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID,
5313 eabuf)));
5314 for (j = 0; j < WPA2_PMKID_LEN; j++)
5315 WL_WSEC(("%02x ", pmkidptr->pmkid[0].PMKID[j]));
5316 WL_WSEC(("\n"));
5317 }
5318
5319 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
5320 if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_array[i].BSSID,
5321 ETHER_ADDR_LEN))
5322 break;
5323
5324 if ((pmkid_list.pmkids.npmkid > 0) && (i < pmkid_list.pmkids.npmkid)) {
5325 bzero(&pmkid_array[i], sizeof(pmkid_t));
5326 for (; i < (pmkid_list.pmkids.npmkid - 1); i++) {
5327 bcopy(&pmkid_array[i+1].BSSID,
5328 &pmkid_array[i].BSSID,
5329 ETHER_ADDR_LEN);
5330 bcopy(&pmkid_array[i+1].PMKID,
5331 &pmkid_array[i].PMKID,
5332 WPA2_PMKID_LEN);
5333 }
5334 pmkid_list.pmkids.npmkid--;
5335 }
5336 else
5337 ret = -EINVAL;
5338 }
5339
5340 else if (iwpmksa->cmd == IW_PMKSA_ADD) {
5341 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
5342 if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_array[i].BSSID,
5343 ETHER_ADDR_LEN))
5344 break;
5345 if (i < MAXPMKID) {
5346 bcopy(&iwpmksa->bssid.sa_data[0],
5347 &pmkid_array[i].BSSID,
5348 ETHER_ADDR_LEN);
5349 bcopy(&iwpmksa->pmkid[0], &pmkid_array[i].PMKID,
5350 WPA2_PMKID_LEN);
5351 if (i == pmkid_list.pmkids.npmkid)
5352 pmkid_list.pmkids.npmkid++;
5353 }
5354 else
5355 ret = -EINVAL;
5356
5357 {
5358 uint j;
5359 uint k;
5360 k = pmkid_list.pmkids.npmkid;
5361 WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ",
5362 bcm_ether_ntoa(&pmkid_array[k].BSSID,
5363 eabuf)));
5364 for (j = 0; j < WPA2_PMKID_LEN; j++)
5365 WL_WSEC(("%02x ", pmkid_array[k].PMKID[j]));
5366 WL_WSEC(("\n"));
5367 }
5368 }
5369 WL_WSEC(("PRINTING pmkid LIST - No of elements %d", pmkid_list.pmkids.npmkid));
5370 for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
5371 uint j;
5372 WL_WSEC(("\nPMKID[%d]: %s = ", i,
5373 bcm_ether_ntoa(&pmkid_array[i].BSSID,
5374 eabuf)));
5375 for (j = 0; j < WPA2_PMKID_LEN; j++)
5376 WL_WSEC(("%02x ", pmkid_array[i].PMKID[j]));
5377 }
5378 WL_WSEC(("\n"));
5379
5380 if (!ret)
5381 ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list,
5382 sizeof(pmkid_list));
5383 return ret;
5384}
5385#endif
5386
5387static int
5388wl_iw_get_encodeext(
5389 struct net_device *dev,
5390 struct iw_request_info *info,
5391 struct iw_param *vwrq,
5392 char *extra
5393)
5394{
5395 WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name));
5396 return 0;
5397}
5398
5399
5400static uint32
5401wl_iw_create_wpaauth_wsec(struct net_device *dev)
5402{
5403 wl_iw_t *iw = NETDEV_PRIV(dev);
5404 uint32 wsec;
5405
5406
5407 if (iw->pcipher & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
5408 wsec = WEP_ENABLED;
5409 else if (iw->pcipher & IW_AUTH_CIPHER_TKIP)
5410 wsec = TKIP_ENABLED;
5411 else if (iw->pcipher & IW_AUTH_CIPHER_CCMP)
5412 wsec = AES_ENABLED;
5413 else
5414 wsec = 0;
5415
5416
5417 if (iw->gcipher & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
5418 wsec |= WEP_ENABLED;
5419 else if (iw->gcipher & IW_AUTH_CIPHER_TKIP)
5420 wsec |= TKIP_ENABLED;
5421 else if (iw->gcipher & IW_AUTH_CIPHER_CCMP)
5422 wsec |= AES_ENABLED;
5423
5424
5425 if (wsec == 0 && iw->privacy_invoked)
5426 wsec = WEP_ENABLED;
5427
5428 WL_INFORM(("%s: returning wsec of %d\n", __FUNCTION__, wsec));
5429
5430 return wsec;
5431}
5432
5433static int
5434wl_iw_set_wpaauth(
5435 struct net_device *dev,
5436 struct iw_request_info *info,
5437 struct iw_param *vwrq,
5438 char *extra
5439)
5440{
5441 int error = 0;
5442 int paramid;
5443 int paramval;
5444 int val = 0;
5445 wl_iw_t *iw = NETDEV_PRIV(dev);
5446
5447 paramid = vwrq->flags & IW_AUTH_INDEX;
5448 paramval = vwrq->value;
5449
5450 WL_TRACE(("%s: SIOCSIWAUTH, %s(%d), paramval = 0x%0x\n",
5451 dev->name,
5452 paramid == IW_AUTH_WPA_VERSION ? "IW_AUTH_WPA_VERSION" :
5453 paramid == IW_AUTH_CIPHER_PAIRWISE ? "IW_AUTH_CIPHER_PAIRWISE" :
5454 paramid == IW_AUTH_CIPHER_GROUP ? "IW_AUTH_CIPHER_GROUP" :
5455 paramid == IW_AUTH_KEY_MGMT ? "IW_AUTH_KEY_MGMT" :
5456 paramid == IW_AUTH_TKIP_COUNTERMEASURES ? "IW_AUTH_TKIP_COUNTERMEASURES" :
5457 paramid == IW_AUTH_DROP_UNENCRYPTED ? "IW_AUTH_DROP_UNENCRYPTED" :
5458 paramid == IW_AUTH_80211_AUTH_ALG ? "IW_AUTH_80211_AUTH_ALG" :
5459 paramid == IW_AUTH_WPA_ENABLED ? "IW_AUTH_WPA_ENABLED" :
5460 paramid == IW_AUTH_RX_UNENCRYPTED_EAPOL ? "IW_AUTH_RX_UNENCRYPTED_EAPOL" :
5461 paramid == IW_AUTH_ROAMING_CONTROL ? "IW_AUTH_ROAMING_CONTROL" :
5462 paramid == IW_AUTH_PRIVACY_INVOKED ? "IW_AUTH_PRIVACY_INVOKED" :
5463 "UNKNOWN",
5464 paramid, paramval));
5465
5466#if defined(SOFTAP)
5467 if (ap_cfg_running) {
5468 WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
5469 return 0;
5470 }
5471#endif
5472
5473 switch (paramid) {
5474 case IW_AUTH_WPA_VERSION:
5475
5476 iw->wpaversion = paramval;
5477 break;
5478
5479 case IW_AUTH_CIPHER_PAIRWISE:
5480 iw->pcipher = paramval;
5481 val = wl_iw_create_wpaauth_wsec(dev);
5482 if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
5483 return error;
5484 break;
5485
5486 case IW_AUTH_CIPHER_GROUP:
5487 iw->gcipher = paramval;
5488 val = wl_iw_create_wpaauth_wsec(dev);
5489 if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
5490 return error;
5491 break;
5492
5493 case IW_AUTH_KEY_MGMT:
5494 if (paramval & IW_AUTH_KEY_MGMT_PSK) {
5495 if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA)
5496 val = WPA_AUTH_PSK;
5497 else if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA2)
5498 val = WPA2_AUTH_PSK;
5499 else
5500 val = WPA_AUTH_DISABLED;
5501 } else if (paramval & IW_AUTH_KEY_MGMT_802_1X) {
5502 if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA)
5503 val = WPA_AUTH_UNSPECIFIED;
5504 else if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA2)
5505 val = WPA2_AUTH_UNSPECIFIED;
5506 else
5507 val = WPA_AUTH_DISABLED;
5508 }
5509 else
5510 val = WPA_AUTH_DISABLED;
5511
5512 WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
5513 if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
5514 return error;
5515 break;
5516
5517 case IW_AUTH_TKIP_COUNTERMEASURES:
5518 dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)&paramval, 1);
5519 break;
5520
5521 case IW_AUTH_80211_AUTH_ALG:
5522
5523 WL_INFORM(("Setting the D11auth %d\n", paramval));
5524 if (paramval == IW_AUTH_ALG_OPEN_SYSTEM)
5525 val = 0;
5526 else if (paramval == IW_AUTH_ALG_SHARED_KEY)
5527 val = 1;
5528 else if (paramval == (IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY))
5529 val = 2;
5530 else
5531 error = 1;
5532 if (!error && (error = dev_wlc_intvar_set(dev, "auth", val)))
5533 return error;
5534 break;
5535
5536 case IW_AUTH_WPA_ENABLED:
5537 if (paramval == 0) {
5538 iw->privacy_invoked = 0;
5539 iw->pcipher = 0;
5540 iw->gcipher = 0;
5541 val = wl_iw_create_wpaauth_wsec(dev);
5542 if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
5543 return error;
5544 WL_INFORM(("%s: %d: setting wpa_auth to %d, wsec to %d\n",
5545 __FUNCTION__, __LINE__, paramval, val));
5546 dev_wlc_intvar_set(dev, "wpa_auth", paramval);
5547 return error;
5548 }
5549
5550
5551 break;
5552
5553 case IW_AUTH_DROP_UNENCRYPTED:
5554 if ((error = dev_wlc_intvar_set(dev, "wsec_restrict", paramval)))
5555 return error;
5556 break;
5557
5558 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
5559 dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
5560 break;
5561
5562#if WIRELESS_EXT > 17
5563 case IW_AUTH_ROAMING_CONTROL:
5564 WL_INFORM(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
5565
5566 break;
5567
5568 case IW_AUTH_PRIVACY_INVOKED:
5569 iw->privacy_invoked = paramval;
5570 val = wl_iw_create_wpaauth_wsec(dev);
5571 if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
5572 return error;
5573 break;
5574
5575#endif
5576 default:
5577 break;
5578 }
5579 return 0;
5580}
5581#define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
5582
5583static int
5584wl_iw_get_wpaauth(
5585 struct net_device *dev,
5586 struct iw_request_info *info,
5587 struct iw_param *vwrq,
5588 char *extra
5589)
5590{
5591 int error;
5592 int paramid;
5593 int paramval = 0;
5594 int val;
5595 wl_iw_t *iw = NETDEV_PRIV(dev);
5596
5597 WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name));
5598
5599 paramid = vwrq->flags & IW_AUTH_INDEX;
5600
5601 switch (paramid) {
5602 case IW_AUTH_WPA_VERSION:
5603 paramval = iw->wpaversion;
5604 break;
5605
5606 case IW_AUTH_CIPHER_PAIRWISE:
5607 paramval = iw->pcipher;
5608 break;
5609
5610 case IW_AUTH_CIPHER_GROUP:
5611 paramval = iw->gcipher;
5612 break;
5613
5614 case IW_AUTH_KEY_MGMT:
5615
5616 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
5617 return error;
5618 if (VAL_PSK(val))
5619 paramval = IW_AUTH_KEY_MGMT_PSK;
5620 else
5621 paramval = IW_AUTH_KEY_MGMT_802_1X;
5622
5623 break;
5624
5625 case IW_AUTH_TKIP_COUNTERMEASURES:
5626 dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)&paramval, 1);
5627 break;
5628
5629 case IW_AUTH_DROP_UNENCRYPTED:
5630 dev_wlc_intvar_get(dev, "wsec_restrict", &paramval);
5631 break;
5632
5633 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
5634 dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
5635 break;
5636
5637 case IW_AUTH_80211_AUTH_ALG:
5638
5639 if ((error = dev_wlc_intvar_get(dev, "auth", &val)))
5640 return error;
5641 if (!val)
5642 paramval = IW_AUTH_ALG_OPEN_SYSTEM;
5643 else
5644 paramval = IW_AUTH_ALG_SHARED_KEY;
5645 break;
5646 case IW_AUTH_WPA_ENABLED:
5647 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
5648 return error;
5649 if (val)
5650 paramval = TRUE;
5651 else
5652 paramval = FALSE;
5653 break;
5654#if WIRELESS_EXT > 17
5655 case IW_AUTH_ROAMING_CONTROL:
5656 WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
5657
5658 break;
5659 case IW_AUTH_PRIVACY_INVOKED:
5660 paramval = iw->privacy_invoked;
5661 break;
5662
5663#endif
5664 }
5665 vwrq->value = paramval;
5666 return 0;
5667}
5668#endif
5669
5670
5671#ifdef SOFTAP
5672
5673static int ap_macmode = MACLIST_MODE_DISABLED;
5674static struct mflist ap_black_list;
5675
5676static int
5677wl_iw_parse_wep(char *keystr, wl_wsec_key_t *key)
5678{
5679 char hex[] = "XX";
5680 unsigned char *data = key->data;
5681
5682 switch (strlen(keystr)) {
5683 case 5:
5684 case 13:
5685 case 16:
5686 key->len = strlen(keystr);
5687 memcpy(data, keystr, key->len + 1);
5688 break;
5689 case 12:
5690 case 28:
5691 case 34:
5692 case 66:
5693
5694 if (!strnicmp(keystr, "0x", 2))
5695 keystr += 2;
5696 else
5697 return -1;
5698
5699 case 10:
5700 case 26:
5701 case 32:
5702 case 64:
5703 key->len = strlen(keystr) / 2;
5704 while (*keystr) {
5705 strncpy(hex, keystr, 2);
5706 *data++ = (char) bcm_strtoul(hex, NULL, 16);
5707 keystr += 2;
5708 }
5709 break;
5710 default:
5711 return -1;
5712 }
5713
5714 switch (key->len) {
5715 case 5:
5716 key->algo = CRYPTO_ALGO_WEP1;
5717 break;
5718 case 13:
5719 key->algo = CRYPTO_ALGO_WEP128;
5720 break;
5721 case 16:
5722
5723 key->algo = CRYPTO_ALGO_AES_CCM;
5724 break;
5725 case 32:
5726 key->algo = CRYPTO_ALGO_TKIP;
5727 break;
5728 default:
5729 return -1;
5730 }
5731
5732
5733 key->flags |= WL_PRIMARY_KEY;
5734
5735 return 0;
5736}
5737
5738#ifdef EXT_WPA_CRYPTO
5739#define SHA1HashSize 20
5740extern void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
5741 int iterations, u8 *buf, size_t buflen);
5742
5743#else
5744
5745#define SHA1HashSize 20
5746static int
5747pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
5748 int iterations, u8 *buf, size_t buflen)
5749{
5750 WL_ERROR(("WARNING: %s is not implemented !!!\n", __FUNCTION__));
5751 return -1;
5752}
5753
5754#endif
5755
5756
5757static int
5758dev_iw_write_cfg1_bss_var(struct net_device *dev, int val)
5759{
5760 struct {
5761 int cfg;
5762 int val;
5763 } bss_setbuf;
5764
5765 int bss_set_res;
5766 char smbuf[WLC_IOCTL_SMLEN];
5767 memset(smbuf, 0, sizeof(smbuf));
5768
5769 bss_setbuf.cfg = 1;
5770 bss_setbuf.val = val;
5771
5772 bss_set_res = dev_iw_iovar_setbuf(dev, "bss",
5773 &bss_setbuf, sizeof(bss_setbuf), smbuf, sizeof(smbuf));
5774 WL_TRACE(("%s: bss_set_result:%d set with %d\n", __FUNCTION__, bss_set_res, val));
5775
5776 return bss_set_res;
5777}
5778
5779
5780
5781#ifndef AP_ONLY
5782static int
5783wl_bssiovar_mkbuf(
5784 const char *iovar,
5785 int bssidx,
5786 void *param,
5787 int paramlen,
5788 void *bufptr,
5789 int buflen,
5790 int *perr)
5791{
5792 const char *prefix = "bsscfg:";
5793 int8* p;
5794 uint prefixlen;
5795 uint namelen;
5796 uint iolen;
5797
5798 prefixlen = strlen(prefix);
5799 namelen = strlen(iovar) + 1;
5800 iolen = prefixlen + namelen + sizeof(int) + paramlen;
5801
5802
5803 if (buflen < 0 || iolen > (uint)buflen) {
5804 *perr = BCME_BUFTOOSHORT;
5805 return 0;
5806 }
5807
5808 p = (int8*)bufptr;
5809
5810
5811 memcpy(p, prefix, prefixlen);
5812 p += prefixlen;
5813
5814
5815 memcpy(p, iovar, namelen);
5816 p += namelen;
5817
5818
5819 bssidx = htod32(bssidx);
5820 memcpy(p, &bssidx, sizeof(int32));
5821 p += sizeof(int32);
5822
5823
5824 if (paramlen)
5825 memcpy(p, param, paramlen);
5826
5827 *perr = 0;
5828 return iolen;
5829}
5830#endif
5831
5832
5833
5834
5835#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
5836
5837
5838#if defined(CSCAN)
5839
5840
5841
5842static int
5843wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan)
5844{
5845 int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
5846 int err = 0;
5847 char *p;
5848 int i;
5849 iscan_info_t *iscan = g_iscan;
5850
5851 WL_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan));
5852
5853 if ((!dev) && (!g_iscan) && (!iscan->iscan_ex_params_p)) {
5854 WL_ERROR(("%s error exit\n", __FUNCTION__));
5855 err = -1;
5856 goto exit;
5857 }
5858
5859#ifdef PNO_SUPPORT
5860
5861 if (dhd_dev_get_pno_status(dev)) {
5862 WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__));
5863 }
5864#endif
5865
5866 params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
5867
5868
5869 if (nssid > 0) {
5870 i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16);
5871 i = ROUNDUP(i, sizeof(uint32));
5872 if (i + nssid * sizeof(wlc_ssid_t) > params_size) {
5873 printf("additional ssids exceed params_size\n");
5874 err = -1;
5875 goto exit;
5876 }
5877
5878 p = ((char*)&iscan->iscan_ex_params_p->params) + i;
5879 memcpy(p, ssids_local, nssid * sizeof(wlc_ssid_t));
5880 p += nssid * sizeof(wlc_ssid_t);
5881 } else {
5882 p = (char*)iscan->iscan_ex_params_p->params.channel_list + nchan * sizeof(uint16);
5883 }
5884
5885
5886 iscan->iscan_ex_params_p->params.channel_num =
5887 htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) |
5888 (nchan & WL_SCAN_PARAMS_COUNT_MASK));
5889
5890 nssid = (uint)
5891 ((iscan->iscan_ex_params_p->params.channel_num >> WL_SCAN_PARAMS_NSSID_SHIFT) &
5892 WL_SCAN_PARAMS_COUNT_MASK);
5893
5894
5895 params_size = (int) (p - (char*)iscan->iscan_ex_params_p + nssid * sizeof(wlc_ssid_t));
5896 iscan->iscan_ex_param_size = params_size;
5897
5898 iscan->list_cur = iscan->list_hdr;
5899 iscan->iscan_state = ISCAN_STATE_SCANING;
5900 wl_iw_set_event_mask(dev);
5901 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
5902
5903 iscan->timer_on = 1;
5904
5905#ifdef SCAN_DUMP
5906 {
5907 int i;
5908 WL_SCAN(("\n### List of SSIDs to scan ###\n"));
5909 for (i = 0; i < nssid; i++) {
5910 if (!ssids_local[i].SSID_len)
5911 WL_SCAN(("%d: Broadcast scan\n", i));
5912 else
5913 WL_SCAN(("%d: scan for %s size =%d\n", i,
5914 ssids_local[i].SSID, ssids_local[i].SSID_len));
5915 }
5916 WL_SCAN(("### List of channels to scan ###\n"));
5917 for (i = 0; i < nchan; i++)
5918 {
5919 WL_SCAN(("%d ", iscan->iscan_ex_params_p->params.channel_list[i]));
5920 }
5921 WL_SCAN(("\nnprobes=%d\n", iscan->iscan_ex_params_p->params.nprobes));
5922 WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
5923 WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
5924 WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
5925 WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
5926 WL_SCAN(("\n###################\n"));
5927 }
5928#endif
5929
5930 if (params_size > WLC_IOCTL_MEDLEN) {
5931 WL_ERROR(("Set ISCAN for %s due to params_size=%d \n",
5932 __FUNCTION__, params_size));
5933 err = -1;
5934 }
5935
5936 if ((err = dev_iw_iovar_setbuf(dev, "iscan", iscan->iscan_ex_params_p,
5937 iscan->iscan_ex_param_size,
5938 iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
5939 WL_TRACE(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
5940 err = -1;
5941 }
5942
5943exit:
5944 return err;
5945}
5946
5947
5948static int
5949iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info,
5950 union iwreq_data *wrqu, char *ext)
5951{
5952 int res;
5953 char *extra = NULL;
5954 iscan_info_t *iscan = g_iscan;
5955 wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
5956 int nssid = 0;
5957 int nchan = 0;
5958 char *str_ptr;
5959
5960 WL_TRACE(("%s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
5961 __FUNCTION__, info->cmd, info->flags,
5962 wrqu->data.pointer, wrqu->data.length));
5963
5964 if (g_onoff == G_WLAN_SET_OFF) {
5965 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
5966 return -ENODEV;
5967 }
5968
5969 if (wrqu->data.length == 0) {
5970 WL_ERROR(("IWPRIV argument len = 0\n"));
5971 return -EINVAL;
5972 }
5973
5974 if (!iscan->iscan_ex_params_p) {
5975 return -EFAULT;
5976 }
5977
5978 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
5979 return -ENOMEM;
5980
5981 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
5982 res = -EFAULT;
5983 goto exit_proc;
5984 }
5985
5986 extra[wrqu->data.length] = 0;
5987 WL_ERROR(("Got str param in iw_point:\n %s\n", extra));
5988
5989 str_ptr = extra;
5990
5991
5992 if (strncmp(str_ptr, GET_SSID, strlen(GET_SSID))) {
5993 WL_ERROR(("%s Error: extracting SSID='' string\n", __FUNCTION__));
5994 res = -EINVAL;
5995 goto exit_proc;
5996 }
5997
5998 str_ptr += strlen(GET_SSID);
5999 nssid = wl_iw_parse_ssid_list(&str_ptr, ssids_local, nssid,
6000 WL_SCAN_PARAMS_SSID_MAX);
6001 if (nssid == -1) {
6002 WL_ERROR(("%s wrong ssid list", __FUNCTION__));
6003 res = -EINVAL;
6004 goto exit_proc;
6005 }
6006
6007 memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
6008 ASSERT(iscan->iscan_ex_param_size < WLC_IOCTL_MAXLEN);
6009
6010
6011 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
6012 iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
6013 iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
6014 iscan->iscan_ex_params_p->scan_duration = htod16(0);
6015
6016
6017 if ((nchan = wl_iw_parse_channel_list(&str_ptr,
6018 &iscan->iscan_ex_params_p->params.channel_list[0],
6019 WL_NUMCHANNELS)) == -1) {
6020 WL_ERROR(("%s missing channel list\n", __FUNCTION__));
6021 res = -EINVAL;
6022 goto exit_proc;
6023 }
6024
6025
6026 get_parameter_from_string(&str_ptr,
6027 GET_NPROBE, PTYPE_INTDEC,
6028 &iscan->iscan_ex_params_p->params.nprobes, 2);
6029
6030 get_parameter_from_string(&str_ptr, GET_ACTIVE_ASSOC_DWELL, PTYPE_INTDEC,
6031 &iscan->iscan_ex_params_p->params.active_time, 4);
6032
6033 get_parameter_from_string(&str_ptr, GET_PASSIVE_ASSOC_DWELL, PTYPE_INTDEC,
6034 &iscan->iscan_ex_params_p->params.passive_time, 4);
6035
6036 get_parameter_from_string(&str_ptr, GET_HOME_DWELL, PTYPE_INTDEC,
6037 &iscan->iscan_ex_params_p->params.home_time, 4);
6038
6039 get_parameter_from_string(&str_ptr, GET_SCAN_TYPE, PTYPE_INTDEC,
6040 &iscan->iscan_ex_params_p->params.scan_type, 1);
6041
6042
6043 res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
6044
6045exit_proc:
6046 kfree(extra);
6047
6048 return res;
6049}
6050
6051
6052static int
6053wl_iw_set_cscan(
6054 struct net_device *dev,
6055 struct iw_request_info *info,
6056 union iwreq_data *wrqu,
6057 char *extra
6058)
6059{
6060 int res = -1;
6061 iscan_info_t *iscan = g_iscan;
6062 wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
6063 int nssid = 0;
6064 int nchan = 0;
6065 cscan_tlv_t *cscan_tlv_temp;
6066 char type;
6067 char *str_ptr;
6068 int tlv_size_left;
6069#ifdef TLV_DEBUG
6070 int i;
6071 char tlv_in_example[] = {
6072 'C', 'S', 'C', 'A', 'N', ' ',
6073 0x53, 0x01, 0x00, 0x00,
6074 'S',
6075 0x00,
6076 'S',
6077 0x04,
6078 'B', 'R', 'C', 'M',
6079 'C',
6080 0x06,
6081 'P',
6082 0x94,
6083 0x11,
6084 'T',
6085 0x01
6086 };
6087#endif
6088
6089 WL_TRACE(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
6090 __FUNCTION__, info->cmd, info->flags,
6091 wrqu->data.pointer, wrqu->data.length));
6092
6093 net_os_wake_lock(dev);
6094
6095 if (g_onoff == G_WLAN_SET_OFF) {
6096 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
6097 goto exit_proc;
6098 }
6099
6100 if (wrqu->data.length < (strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))) {
6101 WL_ERROR(("%s argument=%d less %d\n", __FUNCTION__,
6102 wrqu->data.length, (int)(strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))));
6103 goto exit_proc;
6104 }
6105
6106#ifdef TLV_DEBUG
6107 memcpy(extra, tlv_in_example, sizeof(tlv_in_example));
6108 wrqu->data.length = sizeof(tlv_in_example);
6109 for (i = 0; i < wrqu->data.length; i++)
6110 printf("%02X ", extra[i]);
6111 printf("\n");
6112#endif
6113
6114 str_ptr = extra;
6115 str_ptr += strlen(CSCAN_COMMAND);
6116 tlv_size_left = wrqu->data.length - strlen(CSCAN_COMMAND);
6117
6118 cscan_tlv_temp = (cscan_tlv_t *)str_ptr;
6119 memset(ssids_local, 0, sizeof(ssids_local));
6120
6121 if ((cscan_tlv_temp->prefix == CSCAN_TLV_PREFIX) &&
6122 (cscan_tlv_temp->version == CSCAN_TLV_VERSION) &&
6123 (cscan_tlv_temp->subver == CSCAN_TLV_SUBVERSION))
6124 {
6125 str_ptr += sizeof(cscan_tlv_t);
6126 tlv_size_left -= sizeof(cscan_tlv_t);
6127
6128
6129 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
6130 WL_SCAN_PARAMS_SSID_MAX, &tlv_size_left)) <= 0) {
6131 WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
6132 goto exit_proc;
6133 }
6134 else {
6135
6136 memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
6137
6138
6139 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
6140 iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
6141 iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
6142 iscan->iscan_ex_params_p->scan_duration = htod16(0);
6143
6144
6145 while (tlv_size_left > 0)
6146 {
6147 type = str_ptr[0];
6148 switch (type) {
6149 case CSCAN_TLV_TYPE_CHANNEL_IE:
6150
6151 if ((nchan = wl_iw_parse_channel_list_tlv(&str_ptr,
6152 &iscan->iscan_ex_params_p->params.channel_list[0],
6153 WL_NUMCHANNELS, &tlv_size_left)) == -1) {
6154 WL_ERROR(("%s missing channel list\n",
6155 __FUNCTION__));
6156 goto exit_proc;
6157 }
6158 break;
6159 case CSCAN_TLV_TYPE_NPROBE_IE:
6160 if ((res = wl_iw_parse_data_tlv(&str_ptr,
6161 &iscan->iscan_ex_params_p->params.nprobes,
6162 sizeof(iscan->iscan_ex_params_p->params.nprobes),
6163 type, sizeof(char), &tlv_size_left)) == -1) {
6164 WL_ERROR(("%s return %d\n",
6165 __FUNCTION__, res));
6166 goto exit_proc;
6167 }
6168 break;
6169 case CSCAN_TLV_TYPE_ACTIVE_IE:
6170 if ((res = wl_iw_parse_data_tlv(&str_ptr,
6171 &iscan->iscan_ex_params_p->params.active_time,
6172 sizeof(iscan->iscan_ex_params_p->params.active_time),
6173 type, sizeof(short), &tlv_size_left)) == -1) {
6174 WL_ERROR(("%s return %d\n",
6175 __FUNCTION__, res));
6176 goto exit_proc;
6177 }
6178 break;
6179 case CSCAN_TLV_TYPE_PASSIVE_IE:
6180 if ((res = wl_iw_parse_data_tlv(&str_ptr,
6181 &iscan->iscan_ex_params_p->params.passive_time,
6182 sizeof(iscan->iscan_ex_params_p->params.passive_time),
6183 type, sizeof(short), &tlv_size_left)) == -1) {
6184 WL_ERROR(("%s return %d\n",
6185 __FUNCTION__, res));
6186 goto exit_proc;
6187 }
6188 break;
6189 case CSCAN_TLV_TYPE_HOME_IE:
6190 if ((res = wl_iw_parse_data_tlv(&str_ptr,
6191 &iscan->iscan_ex_params_p->params.home_time,
6192 sizeof(iscan->iscan_ex_params_p->params.home_time),
6193 type, sizeof(short), &tlv_size_left)) == -1) {
6194 WL_ERROR(("%s return %d\n",
6195 __FUNCTION__, res));
6196 goto exit_proc;
6197 }
6198 break;
6199 case CSCAN_TLV_TYPE_STYPE_IE:
6200 if ((res = wl_iw_parse_data_tlv(&str_ptr,
6201 &iscan->iscan_ex_params_p->params.scan_type,
6202 sizeof(iscan->iscan_ex_params_p->params.scan_type),
6203 type, sizeof(char), &tlv_size_left)) == -1) {
6204 WL_ERROR(("%s return %d\n",
6205 __FUNCTION__, res));
6206 goto exit_proc;
6207 }
6208 break;
6209
6210 default :
6211 WL_ERROR(("%s get unkwown type %X\n",
6212 __FUNCTION__, type));
6213 goto exit_proc;
6214 break;
6215 }
6216 }
6217 }
6218 }
6219 else {
6220 WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
6221 goto exit_proc;
6222 }
6223
6224#if defined(CONFIG_FIRST_SCAN)
6225 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
6226 if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) {
6227
6228 WL_ERROR(("%s Clean up First scan flag which is %d\n",
6229 __FUNCTION__, g_first_broadcast_scan));
6230 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
6231 }
6232 else {
6233 WL_ERROR(("%s Ignoring CSCAN : First Scan is not done yet %d\n",
6234 __FUNCTION__, g_first_counter_scans));
6235 goto exit_proc;
6236 }
6237 }
6238#endif
6239
6240
6241 res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
6242
6243exit_proc:
6244 net_os_wake_unlock(dev);
6245 return res;
6246}
6247
6248#endif
6249
6250#ifdef CONFIG_WPS2
6251static int
6252wl_iw_del_wps_probe_req_ie(
6253 struct net_device *dev,
6254 struct iw_request_info *info,
6255 union iwreq_data *wrqu,
6256 char *extra
6257)
6258{
6259 int ret;
6260 vndr_ie_setbuf_t *ie_delbuf;
6261
6262 if (g_wps_probe_req_ie) {
6263 ie_delbuf = (vndr_ie_setbuf_t *)(g_wps_probe_req_ie + strlen("vndr_ie "));
6264 strncpy(ie_delbuf->cmd, "del", 3);
6265 ie_delbuf->cmd[3] = '\0';
6266
6267 ret = dev_wlc_ioctl(dev, WLC_SET_VAR, g_wps_probe_req_ie, g_wps_probe_req_ie_len);
6268 if (ret) {
6269 WL_ERROR(("ioctl failed %d \n", ret));
6270 }
6271
6272 kfree(g_wps_probe_req_ie);
6273 g_wps_probe_req_ie = NULL;
6274 g_wps_probe_req_ie_len = 0;
6275 }
6276
6277 return 0;
6278}
6279
6280static int
6281wl_iw_add_wps_probe_req_ie(
6282 struct net_device *dev,
6283 struct iw_request_info *info,
6284 union iwreq_data *wrqu,
6285 char *extra
6286)
6287{
6288 char *str_ptr = NULL;
6289 char *bufptr = NULL;
6290 uint buflen, datalen, iecount, pktflag, iolen, total_len;
6291 int ret = 0;
6292 vndr_ie_setbuf_t *ie_setbuf = NULL;
6293
6294 if (!g_wps_probe_req_ie) {
6295 ret = -1;
6296 str_ptr = extra;
6297 str_ptr += WPS_PROBE_REQ_IE_CMD_LENGTH;
6298 datalen = wrqu->data.length - WPS_PROBE_REQ_IE_CMD_LENGTH;
6299
6300
6301
6302 buflen = sizeof(vndr_ie_setbuf_t) + datalen - sizeof(vndr_ie_t);
6303 ie_setbuf = (vndr_ie_setbuf_t *)kmalloc(buflen, GFP_KERNEL);
6304 if (!ie_setbuf) {
6305 WL_ERROR(("memory alloc failure ie_setbuf\n"));
6306 return ret;
6307 }
6308
6309 memset(ie_setbuf, 0x00, buflen);
6310
6311
6312 strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1);
6313 ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
6314
6315
6316 iecount = htod32(1);
6317 memcpy((void *)&ie_setbuf->vndr_ie_buffer.iecount, &iecount, sizeof(int));
6318
6319
6320 pktflag = 0x10;
6321 memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].pktflag,
6322 &pktflag, sizeof(uint32));
6323
6324 memcpy((void *)&ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data,
6325 str_ptr, datalen);
6326
6327 total_len = strlen("vndr_ie ") + buflen;
6328 bufptr = (char *)kmalloc(total_len, GFP_KERNEL);
6329 if (!bufptr) {
6330 WL_ERROR(("memory alloc failure bufptr\n"));
6331 goto fail;
6332 }
6333
6334 iolen = bcm_mkiovar("vndr_ie", (char *)ie_setbuf, buflen, bufptr, total_len);
6335 if (iolen == 0) {
6336 WL_ERROR(("Buffer length is illegal\n"));
6337 goto fail2;
6338 }
6339
6340 ret = dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen);
6341 if (ret) {
6342 WL_ERROR(("ioctl failed\n"));
6343 goto fail2;
6344 }
6345
6346 g_wps_probe_req_ie = (char *)kmalloc(iolen, GFP_KERNEL);
6347 if (!g_wps_probe_req_ie) {
6348 WL_ERROR(("memory alloc failure g_wps_probe_req_ie\n"));
6349 goto fail2;
6350 }
6351
6352 memcpy(g_wps_probe_req_ie, bufptr, iolen);
6353 g_wps_probe_req_ie_len = iolen;
6354 }
6355
6356fail2:
6357 if (bufptr) {
6358 kfree(bufptr);
6359 bufptr = NULL;
6360 }
6361fail:
6362 if (ie_setbuf) {
6363 kfree(ie_setbuf);
6364 ie_setbuf = NULL;
6365 }
6366 return ret;
6367}
6368#endif
6369
6370
6371#ifdef SOFTAP
6372#ifndef AP_ONLY
6373
6374
6375static int
6376thr_wait_for_2nd_eth_dev(void *data)
6377{
6378 wl_iw_t *iw;
6379 int ret = 0;
6380 unsigned long flags = 0;
6381
6382 tsk_ctl_t *tsk_ctl = (tsk_ctl_t *)data;
6383 struct net_device *dev = (struct net_device *)tsk_ctl->parent;
6384 iw = *(wl_iw_t **)netdev_priv(dev);
6385
6386 DAEMONIZE("wl0_eth_wthread");
6387
6388
6389 WL_SOFTAP(("\n>%s threda started:, PID:%x\n", __FUNCTION__, current->pid));
6390
6391#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
6392 if (!iw) {
6393 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
6394 tsk_ctl->thr_pid = -1;
6395 complete(&tsk_ctl->completed);
6396 return -1;
6397 }
6398 DHD_OS_WAKE_LOCK(iw->pub);
6399 complete(&tsk_ctl->completed);
6400 if (down_timeout(&tsk_ctl->sema, msecs_to_jiffies(1000)) != 0) {
6401#else
6402 if (down_interruptible(&tsk_ctl->sema) != 0) {
6403#endif
6404 WL_ERROR(("\n%s: sap_eth_sema timeout \n", __FUNCTION__));
6405 ret = -1;
6406 goto fail;
6407 }
6408
6409 SMP_RD_BARRIER_DEPENDS();
6410 if (tsk_ctl->terminated) {
6411 ret = -1;
6412 goto fail;
6413 }
6414
6415 flags = dhd_os_spin_lock(iw->pub);
6416 if (!ap_net_dev) {
6417 WL_ERROR((" ap_net_dev is null !!!"));
6418 ret = -1;
6419 dhd_os_spin_unlock(iw->pub, flags);
6420 goto fail;
6421 }
6422
6423 WL_SOFTAP(("\n>%s: Thread:'softap ethdev IF:%s is detected!'\n\n",
6424 __FUNCTION__, ap_net_dev->name));
6425
6426 ap_cfg_running = TRUE;
6427
6428 dhd_os_spin_unlock(iw->pub, flags);
6429 bcm_mdelay(500);
6430
6431
6432 wl_iw_send_priv_event(priv_dev, "AP_SET_CFG_OK");
6433
6434fail:
6435
6436 DHD_OS_WAKE_UNLOCK(iw->pub);
6437
6438 WL_SOFTAP(("\n>%s, thread completed\n", __FUNCTION__));
6439
6440 complete_and_exit(&tsk_ctl->completed, 0);
6441 return ret;
6442}
6443#endif
6444#ifndef AP_ONLY
6445static int last_auto_channel = 6;
6446#endif
6447
6448static int
6449get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap)
6450{
6451 int chosen = 0;
6452 wl_uint32_list_t request;
6453 int retry = 0;
6454 int updown = 0;
6455 int ret = 0;
6456 wlc_ssid_t null_ssid;
6457 int res = 0;
6458#ifndef AP_ONLY
6459 int iolen = 0;
6460 int mkvar_err = 0;
6461 int bsscfg_index = 1;
6462 char buf[WLC_IOCTL_SMLEN];
6463#endif
6464 WL_SOFTAP(("Enter %s\n", __FUNCTION__));
6465
6466#ifndef AP_ONLY
6467 if (ap_cfg_running) {
6468 ap->channel = last_auto_channel;
6469 return res;
6470 }
6471#endif
6472
6473 memset(&null_ssid, 0, sizeof(wlc_ssid_t));
6474 res |= dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown));
6475
6476#ifdef AP_ONLY
6477 res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid));
6478#else
6479
6480 iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&null_ssid),
6481 null_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err);
6482 ASSERT(iolen);
6483 res |= dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen);
6484
6485#endif
6486
6487 request.count = htod32(0);
6488 ret = dev_wlc_ioctl(dev, WLC_START_CHANNEL_SEL, &request, sizeof(request));
6489 if (ret < 0) {
6490 WL_ERROR(("can't start auto channel scan\n"));
6491 goto fail;
6492 }
6493
6494 get_channel_retry:
6495 bcm_mdelay(350);
6496
6497 ret = dev_wlc_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
6498 if (ret < 0 || dtoh32(chosen) == 0) {
6499 if (retry++ < 15) {
6500 goto get_channel_retry;
6501 } else {
6502 if (ret < 0) {
6503 WL_ERROR(("can't get auto channel sel, err = %d, "
6504 "chosen = 0x%04X\n", ret, (uint16)chosen));
6505 goto fail;
6506 } else {
6507 ap->channel = (uint16)last_auto_channel;
6508 WL_ERROR(("auto channel sel timed out. we get channel %d\n",
6509 ap->channel));
6510 }
6511 }
6512 }
6513
6514 if (chosen) {
6515 ap->channel = (uint16)chosen & 0x00FF;
6516 WL_SOFTAP(("%s: Got auto channel = %d, attempt:%d\n",
6517 __FUNCTION__, ap->channel, retry));
6518 }
6519
6520 if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown))) < 0) {
6521 WL_ERROR(("%s fail to set up err =%d\n", __FUNCTION__, res));
6522 goto fail;
6523 }
6524
6525#ifndef AP_ONLY
6526 if (!res || !ret)
6527 last_auto_channel = ap->channel;
6528#endif
6529
6530fail :
6531 if (ret < 0) {
6532 WL_TRACE(("%s: return value %d\n", __FUNCTION__, ret));
6533 return ret;
6534 }
6535 return res;
6536}
6537
6538
6539static int
6540set_ap_cfg(struct net_device *dev, struct ap_profile *ap)
6541{
6542 int updown = 0;
6543 int channel = 0;
6544
6545 wlc_ssid_t ap_ssid;
6546 int max_assoc = 8;
6547
6548 int res = 0;
6549 int apsta_var = 0;
6550#ifndef AP_ONLY
6551 int mpc = 0;
6552 int iolen = 0;
6553 int mkvar_err = 0;
6554 int bsscfg_index = 1;
6555 char buf[WLC_IOCTL_SMLEN];
6556#endif
6557
6558 if (!dev) {
6559 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
6560 return -1;
6561 }
6562
6563 net_os_wake_lock(dev);
6564 DHD_OS_MUTEX_LOCK(&wl_softap_lock);
6565
6566 WL_SOFTAP(("wl_iw: set ap profile:\n"));
6567 WL_SOFTAP((" ssid = '%s'\n", ap->ssid));
6568 WL_SOFTAP((" security = '%s'\n", ap->sec));
6569 if (ap->key[0] != '\0')
6570 WL_SOFTAP((" key = '%s'\n", ap->key));
6571 WL_SOFTAP((" channel = %d\n", ap->channel));
6572 WL_SOFTAP((" max scb = %d\n", ap->max_scb));
6573
6574#ifdef AP_ONLY
6575 if (ap_cfg_running) {
6576 wl_iw_softap_deassoc_stations(dev, NULL);
6577 ap_cfg_running = FALSE;
6578 }
6579#endif
6580
6581
6582 if (ap_cfg_running == FALSE) {
6583
6584#ifndef AP_ONLY
6585
6586
6587 sema_init(&ap_eth_ctl.sema, 0);
6588
6589 mpc = 0;
6590 if ((res = dev_wlc_intvar_set(dev, "mpc", mpc))) {
6591 WL_ERROR(("%s fail to set mpc\n", __FUNCTION__));
6592 goto fail;
6593 }
6594#endif
6595
6596 updown = 0;
6597 if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown)))) {
6598 WL_ERROR(("%s fail to set updown\n", __FUNCTION__));
6599 goto fail;
6600 }
6601
6602#ifdef AP_ONLY
6603
6604 apsta_var = 0;
6605 if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) {
6606 WL_ERROR(("%s fail to set apsta_var 0\n", __FUNCTION__));
6607 goto fail;
6608 }
6609 apsta_var = 1;
6610 if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) {
6611 WL_ERROR(("%s fail to set apsta_var 1\n", __FUNCTION__));
6612 goto fail;
6613 }
6614 res = dev_wlc_ioctl(dev, WLC_GET_AP, &apsta_var, sizeof(apsta_var));
6615#else
6616
6617 apsta_var = 1;
6618 iolen = wl_bssiovar_mkbuf("apsta",
6619 bsscfg_index, &apsta_var, sizeof(apsta_var)+4,
6620 buf, sizeof(buf), &mkvar_err);
6621 ASSERT(iolen);
6622 if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) < 0) {
6623 WL_ERROR(("%s fail to set apsta \n", __FUNCTION__));
6624 goto fail;
6625 }
6626 WL_TRACE(("\n>in %s: apsta set result: %d \n", __FUNCTION__, res));
6627
6628
6629 mpc = 0;
6630 if ((res = dev_wlc_intvar_set(dev, "mpc", mpc))) {
6631 WL_ERROR(("%s fail to set mpc\n", __FUNCTION__));
6632 goto fail;
6633 }
6634
6635
6636#endif
6637
6638 updown = 1;
6639 if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown))) < 0) {
6640 WL_ERROR(("%s fail to set apsta \n", __FUNCTION__));
6641 goto fail;
6642 }
6643
6644 } else {
6645
6646 if (!ap_net_dev) {
6647 WL_ERROR(("%s: ap_net_dev is null\n", __FUNCTION__));
6648 goto fail;
6649 }
6650
6651 res = wl_iw_softap_deassoc_stations(ap_net_dev, NULL);
6652
6653
6654 if ((res = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) {
6655 WL_ERROR(("%s fail to set bss down\n", __FUNCTION__));
6656 goto fail;
6657 }
6658 }
6659
6660
6661 if (strlen(ap->country_code)) {
6662 WL_ERROR(("%s: Igonored: Country MUST be specified"
6663 "COUNTRY command with \n", __FUNCTION__));
6664 } else {
6665 WL_SOFTAP(("%s: Country code is not specified,"
6666 " will use Radio's default\n",
6667 __FUNCTION__));
6668
6669 }
6670 iolen = wl_bssiovar_mkbuf("closednet",
6671 bsscfg_index, &ap->closednet, sizeof(ap->closednet)+4,
6672 buf, sizeof(buf), &mkvar_err);
6673 ASSERT(iolen);
6674 if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) < 0) {
6675 WL_ERROR(("%s failed to set 'closednet'for apsta \n", __FUNCTION__));
6676 goto fail;
6677 }
6678
6679
6680 if ((ap->channel == 0) && (get_softap_auto_channel(dev, ap) < 0)) {
6681 ap->channel = 1;
6682 WL_ERROR(("%s auto channel failed, use channel=%d\n",
6683 __FUNCTION__, ap->channel));
6684 }
6685
6686 channel = ap->channel;
6687 if ((res = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel)))) {
6688 WL_ERROR(("%s fail to set channel\n", __FUNCTION__));
6689 }
6690
6691
6692 if (ap_cfg_running == FALSE) {
6693 updown = 0;
6694 if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)))) {
6695 WL_ERROR(("%s fail to set up\n", __FUNCTION__));
6696 goto fail;
6697 }
6698 }
6699
6700 max_assoc = ap->max_scb;
6701 if ((res = dev_wlc_intvar_set(dev, "maxassoc", max_assoc))) {
6702 WL_ERROR(("%s fail to set maxassoc\n", __FUNCTION__));
6703 goto fail;
6704 }
6705
6706 ap_ssid.SSID_len = strlen(ap->ssid);
6707 strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len);
6708
6709
6710#ifdef AP_ONLY
6711 if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) {
6712 WL_ERROR(("ERROR:%d in:%s, wl_iw_set_ap_security is skipped\n",
6713 res, __FUNCTION__));
6714 goto fail;
6715 }
6716 wl_iw_send_priv_event(dev, "ASCII_CMD=AP_BSS_START");
6717 ap_cfg_running = TRUE;
6718#else
6719
6720 iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&ap_ssid),
6721 ap_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err);
6722 ASSERT(iolen);
6723 if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) != 0) {
6724 WL_ERROR(("ERROR:%d in:%s, Security & BSS reconfiguration is skipped\n",
6725 res, __FUNCTION__));
6726 goto fail;
6727 }
6728 if (ap_cfg_running == FALSE) {
6729
6730 PROC_START(thr_wait_for_2nd_eth_dev, dev, &ap_eth_ctl, 0);
6731 } else {
6732 ap_eth_ctl.thr_pid = -1;
6733
6734 if (ap_net_dev == NULL) {
6735 WL_ERROR(("%s ERROR: ap_net_dev is NULL !!!\n", __FUNCTION__));
6736 goto fail;
6737 }
6738
6739 WL_ERROR(("%s: %s Configure security & restart AP bss \n",
6740 __FUNCTION__, ap_net_dev->name));
6741
6742
6743 if ((res = wl_iw_set_ap_security(ap_net_dev, &my_ap)) < 0) {
6744 WL_ERROR(("%s fail to set security : %d\n", __FUNCTION__, res));
6745 goto fail;
6746 }
6747
6748
6749 if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0) {
6750 WL_ERROR(("%s fail to set bss up\n", __FUNCTION__));
6751 goto fail;
6752 }
6753 }
6754#endif
6755fail:
6756 WL_SOFTAP(("%s exit with %d\n", __FUNCTION__, res));
6757
6758 DHD_OS_MUTEX_UNLOCK(&wl_softap_lock);
6759 net_os_wake_unlock(dev);
6760
6761 return res;
6762}
6763#endif
6764
6765
6766
6767static int
6768wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap)
6769{
6770 int wsec = 0;
6771 int wpa_auth = 0;
6772 int res = 0;
6773 int i;
6774 char *ptr;
6775#ifdef AP_ONLY
6776 int mpc = 0;
6777 wlc_ssid_t ap_ssid;
6778#endif
6779 wl_wsec_key_t key;
6780
6781 WL_SOFTAP(("\nsetting SOFTAP security mode:\n"));
6782 WL_SOFTAP(("wl_iw: set ap profile:\n"));
6783 WL_SOFTAP((" ssid = '%s'\n", ap->ssid));
6784 WL_SOFTAP((" security = '%s'\n", ap->sec));
6785 if (ap->key[0] != '\0')
6786 WL_SOFTAP((" key = '%s'\n", ap->key));
6787 WL_SOFTAP((" channel = %d\n", ap->channel));
6788 WL_SOFTAP((" max scb = %d\n", ap->max_scb));
6789
6790
6791 if (strnicmp(ap->sec, "open", strlen("open")) == 0) {
6792
6793
6794 wsec = 0;
6795 res = dev_wlc_intvar_set(dev, "wsec", wsec);
6796 wpa_auth = WPA_AUTH_DISABLED;
6797 res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
6798
6799 WL_SOFTAP(("=====================\n"));
6800 WL_SOFTAP((" wsec & wpa_auth set 'OPEN', result:&d %d\n", res));
6801 WL_SOFTAP(("=====================\n"));
6802
6803 } else if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) {
6804
6805
6806 memset(&key, 0, sizeof(key));
6807
6808 wsec = WEP_ENABLED;
6809 res = dev_wlc_intvar_set(dev, "wsec", wsec);
6810
6811 key.index = 0;
6812 if (wl_iw_parse_wep(ap->key, &key)) {
6813 WL_SOFTAP(("wep key parse err!\n"));
6814 return -1;
6815 }
6816
6817 key.index = htod32(key.index);
6818 key.len = htod32(key.len);
6819 key.algo = htod32(key.algo);
6820 key.flags = htod32(key.flags);
6821
6822 res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
6823
6824 wpa_auth = WPA_AUTH_DISABLED;
6825 res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
6826
6827 WL_SOFTAP(("=====================\n"));
6828 WL_SOFTAP((" wsec & auth set 'WEP', result:&d %d\n", res));
6829 WL_SOFTAP(("=====================\n"));
6830
6831 } else if (strnicmp(ap->sec, "wpa2-psk", strlen("wpa2-psk")) == 0) {
6832
6833
6834
6835 wsec_pmk_t psk;
6836 size_t key_len;
6837
6838 wsec = AES_ENABLED;
6839 dev_wlc_intvar_set(dev, "wsec", wsec);
6840
6841 key_len = strlen(ap->key);
6842 if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) {
6843 WL_SOFTAP(("passphrase must be between %d and %d characters long\n",
6844 WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN));
6845 return -1;
6846 }
6847
6848
6849 if (key_len < WSEC_MAX_PSK_LEN) {
6850 unsigned char output[2*SHA1HashSize];
6851 char key_str_buf[WSEC_MAX_PSK_LEN+1];
6852
6853
6854 memset(output, 0, sizeof(output));
6855 pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32);
6856
6857 ptr = key_str_buf;
6858 for (i = 0; i < (WSEC_MAX_PSK_LEN/8); i++) {
6859
6860 sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4],
6861 (uint)output[i*4+1], (uint)output[i*4+2],
6862 (uint)output[i*4+3]);
6863 ptr += 8;
6864 }
6865 WL_SOFTAP(("%s: passphase = %s\n", __FUNCTION__, key_str_buf));
6866
6867 psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN);
6868 memcpy(psk.key, key_str_buf, psk.key_len);
6869 } else {
6870 psk.key_len = htod16((ushort) key_len);
6871 memcpy(psk.key, ap->key, key_len);
6872 }
6873 psk.flags = htod16(WSEC_PASSPHRASE);
6874 dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk));
6875
6876 wpa_auth = WPA2_AUTH_PSK;
6877 dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
6878
6879 } else if (strnicmp(ap->sec, "wpa-psk", strlen("wpa-psk")) == 0) {
6880
6881
6882 wsec_pmk_t psk;
6883 size_t key_len;
6884
6885 wsec = TKIP_ENABLED;
6886 res = dev_wlc_intvar_set(dev, "wsec", wsec);
6887
6888 key_len = strlen(ap->key);
6889 if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) {
6890 WL_SOFTAP(("passphrase must be between %d and %d characters long\n",
6891 WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN));
6892 return -1;
6893 }
6894
6895
6896 if (key_len < WSEC_MAX_PSK_LEN) {
6897 unsigned char output[2*SHA1HashSize];
6898 char key_str_buf[WSEC_MAX_PSK_LEN+1];
6899 bzero(output, 2*SHA1HashSize);
6900
6901 WL_SOFTAP(("%s: do passhash...\n", __FUNCTION__));
6902
6903 pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32);
6904
6905 ptr = key_str_buf;
6906 for (i = 0; i < (WSEC_MAX_PSK_LEN/8); i++) {
6907 WL_SOFTAP(("[%02d]: %08x\n", i, *((unsigned int*)&output[i*4])));
6908
6909 sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4],
6910 (uint)output[i*4+1], (uint)output[i*4+2],
6911 (uint)output[i*4+3]);
6912 ptr += 8;
6913 }
6914 printk("%s: passphase = %s\n", __FUNCTION__, key_str_buf);
6915
6916 psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN);
6917 memcpy(psk.key, key_str_buf, psk.key_len);
6918 } else {
6919 psk.key_len = htod16((ushort) key_len);
6920 memcpy(psk.key, ap->key, key_len);
6921 }
6922
6923 psk.flags = htod16(WSEC_PASSPHRASE);
6924 res |= dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk));
6925
6926 wpa_auth = WPA_AUTH_PSK;
6927 res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
6928
6929 WL_SOFTAP((" wsec & auth set 'wpa-psk' (TKIP), result:&d %d\n", res));
6930 }
6931
6932#ifdef AP_ONLY
6933 ap_ssid.SSID_len = strlen(ap->ssid);
6934 strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len);
6935 res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &ap_ssid, sizeof(ap_ssid));
6936 mpc = 0;
6937 res |= dev_wlc_intvar_set(dev, "mpc", mpc);
6938 if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) {
6939 res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
6940 }
6941#endif
6942 return res;
6943}
6944
6945
6946
6947static int
6948get_parameter_from_string(
6949 char **str_ptr, const char *token,
6950 int param_type, void *dst, int param_max_len)
6951{
6952 char int_str[7] = "0";
6953 int parm_str_len;
6954 char *param_str_begin;
6955 char *param_str_end;
6956 char *orig_str = *str_ptr;
6957
6958 if ((*str_ptr) && !strncmp(*str_ptr, token, strlen(token))) {
6959
6960 strsep(str_ptr, "=,");
6961 param_str_begin = *str_ptr;
6962 strsep(str_ptr, "=,");
6963
6964 if (*str_ptr == NULL) {
6965
6966 parm_str_len = strlen(param_str_begin);
6967 } else {
6968 param_str_end = *str_ptr-1;
6969 parm_str_len = param_str_end - param_str_begin;
6970 }
6971
6972 WL_TRACE((" 'token:%s', len:%d, ", token, parm_str_len));
6973
6974 if (parm_str_len > param_max_len) {
6975 WL_ERROR((" WARNING: extracted param len:%d is > MAX:%d\n",
6976 parm_str_len, param_max_len));
6977
6978 parm_str_len = param_max_len;
6979 }
6980
6981 switch (param_type) {
6982
6983 case PTYPE_INTDEC: {
6984
6985 int *pdst_int = dst;
6986 char *eptr;
6987
6988 if (parm_str_len > sizeof(int_str))
6989 parm_str_len = sizeof(int_str);
6990
6991 memcpy(int_str, param_str_begin, parm_str_len);
6992
6993 *pdst_int = simple_strtoul(int_str, &eptr, 10);
6994
6995 WL_TRACE((" written as integer:%d\n", *pdst_int));
6996 }
6997 break;
6998 case PTYPE_STR_HEX: {
6999 u8 *buf = dst;
7000
7001 param_max_len = param_max_len >> 1;
7002 hstr_2_buf(param_str_begin, buf, param_max_len);
7003 dhd_print_buf(buf, param_max_len, 0);
7004 }
7005 break;
7006 default:
7007
7008 memcpy(dst, param_str_begin, parm_str_len);
7009 *((char *)dst + parm_str_len) = 0;
7010 WL_ERROR((" written as a string:%s\n", (char *)dst));
7011 break;
7012
7013 }
7014
7015 return 0;
7016 } else {
7017 WL_ERROR(("\n %s: ERROR: can't find token:%s in str:%s \n",
7018 __FUNCTION__, token, orig_str));
7019
7020 return -1;
7021 }
7022}
7023
7024static int wl_iw_softap_deassoc_stations(struct net_device *dev, u8 *mac)
7025{
7026 int i;
7027 int res = 0;
7028 char mac_buf[128] = {0};
7029 char z_mac[6] = {0, 0, 0, 0, 0, 0};
7030 char *sta_mac;
7031 struct maclist *assoc_maclist = (struct maclist *) mac_buf;
7032 bool deauth_all = FALSE;
7033
7034
7035 if (mac == NULL) {
7036 deauth_all = TRUE;
7037 sta_mac = z_mac;
7038 } else {
7039 sta_mac = mac;
7040 }
7041
7042 memset(assoc_maclist, 0, sizeof(mac_buf));
7043 assoc_maclist->count = 8;
7044
7045 res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 128);
7046 if (res != 0) {
7047 WL_SOFTAP(("%s: Error:%d Couldn't get ASSOC List\n", __FUNCTION__, res));
7048 return res;
7049 }
7050
7051 if (assoc_maclist->count)
7052 for (i = 0; i < assoc_maclist->count; i++) {
7053 scb_val_t scbval;
7054 scbval.val = htod32(1);
7055
7056 bcopy(&assoc_maclist->ea[i], &scbval.ea, ETHER_ADDR_LEN);
7057
7058 if (deauth_all || (memcmp(&scbval.ea, sta_mac, ETHER_ADDR_LEN) == 0)) {
7059
7060 WL_SOFTAP(("%s, deauth STA:%d \n", __FUNCTION__, i));
7061 res |= dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
7062 &scbval, sizeof(scb_val_t));
7063 }
7064 } else WL_SOFTAP(("%s: No Stations \n", __FUNCTION__));
7065
7066 if (res != 0) {
7067 WL_ERROR(("%s: Error:%d\n", __FUNCTION__, res));
7068 } else if (assoc_maclist->count) {
7069
7070 bcm_mdelay(200);
7071 }
7072 return res;
7073}
7074
7075
7076
7077static int
7078iwpriv_softap_stop(struct net_device *dev,
7079 struct iw_request_info *info,
7080 union iwreq_data *wrqu,
7081 char *ext)
7082{
7083 int res = 0;
7084
7085 WL_SOFTAP(("got iwpriv AP_BSS_STOP \n"));
7086
7087 if ((!dev) && (!ap_net_dev)) {
7088 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
7089 return res;
7090 }
7091
7092 net_os_wake_lock(dev);
7093 DHD_OS_MUTEX_LOCK(&wl_softap_lock);
7094
7095 if ((ap_cfg_running == TRUE)) {
7096#ifdef AP_ONLY
7097 wl_iw_softap_deassoc_stations(dev, NULL);
7098#else
7099 wl_iw_softap_deassoc_stations(ap_net_dev, NULL);
7100 if ((res = dev_iw_write_cfg1_bss_var(dev, 2)) < 0)
7101 WL_ERROR(("%s failed to del BSS err = %d", __FUNCTION__, res));
7102#endif
7103
7104
7105 bcm_mdelay(100);
7106
7107 wrqu->data.length = 0;
7108 ap_cfg_running = FALSE;
7109 } else
7110 WL_ERROR(("%s: was called when SoftAP is OFF : move on\n", __FUNCTION__));
7111
7112 WL_SOFTAP(("%s Done with %d\n", __FUNCTION__, res));
7113 DHD_OS_MUTEX_UNLOCK(&wl_softap_lock);
7114 net_os_wake_unlock(dev);
7115
7116 return res;
7117}
7118
7119
7120
7121static int
7122iwpriv_fw_reload(struct net_device *dev,
7123 struct iw_request_info *info,
7124 union iwreq_data *wrqu,
7125 char *ext)
7126{
7127 int ret = -1;
7128 char extra[256];
7129 char *fwstr = fw_path ;
7130
7131 WL_SOFTAP(("current firmware_path[]=%s\n", fwstr));
7132
7133 WL_TRACE((">Got FW_RELOAD cmd:"
7134 "info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d, "
7135 "fw_path:%p, len:%d \n",
7136 info->cmd, info->flags,
7137 wrqu->data.pointer, wrqu->data.length, fwstr, strlen(fwstr)));
7138
7139 if ((wrqu->data.length > 4) && (wrqu->data.length < sizeof(extra))) {
7140 char *str_ptr;
7141
7142 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
7143 ret = -EFAULT;
7144 goto exit_proc;
7145 }
7146
7147
7148 extra[wrqu->data.length] = 8;
7149 str_ptr = extra;
7150
7151 if (get_parameter_from_string(&str_ptr,
7152 "FW_PATH=", PTYPE_STRING, fwstr, 255) != 0) {
7153 WL_ERROR(("Error: extracting FW_PATH='' string\n"));
7154 goto exit_proc;
7155 }
7156
7157 if (strstr(fwstr, "apsta") != NULL) {
7158 WL_SOFTAP(("GOT APSTA FIRMWARE\n"));
7159 ap_fw_loaded = TRUE;
7160 } else {
7161 WL_SOFTAP(("GOT STA FIRMWARE\n"));
7162 ap_fw_loaded = FALSE;
7163 }
7164
7165 WL_SOFTAP(("SET firmware_path[]=%s , str_p:%p\n", fwstr, fwstr));
7166 ret = 0;
7167 } else {
7168 WL_ERROR(("Error: ivalid param len:%d\n", wrqu->data.length));
7169 }
7170
7171exit_proc:
7172 return ret;
7173}
7174
7175#ifdef SOFTAP
7176
7177static int
7178iwpriv_wpasupp_loop_tst(struct net_device *dev,
7179 struct iw_request_info *info,
7180 union iwreq_data *wrqu,
7181 char *ext)
7182{
7183 int res = 0;
7184 char *params = NULL;
7185
7186 WL_TRACE((">Got IWPRIV wp_supp loopback cmd test:"
7187 "info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n",
7188 info->cmd, info->flags,
7189 wrqu->data.pointer, wrqu->data.length));
7190
7191 if (wrqu->data.length != 0) {
7192
7193 if (!(params = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
7194 return -ENOMEM;
7195
7196
7197 if (copy_from_user(params, wrqu->data.pointer, wrqu->data.length)) {
7198 kfree(params);
7199 return -EFAULT;
7200 }
7201
7202 params[wrqu->data.length] = 0;
7203 WL_SOFTAP(("\n>> copied from user:\n %s\n", params));
7204 } else {
7205 WL_ERROR(("ERROR param length is 0\n"));
7206 return -EFAULT;
7207 }
7208
7209
7210 res = wl_iw_send_priv_event(dev, params);
7211 kfree(params);
7212
7213 return res;
7214}
7215#endif
7216
7217
7218static int
7219iwpriv_en_ap_bss(
7220 struct net_device *dev,
7221 struct iw_request_info *info,
7222 void *wrqu,
7223 char *extra)
7224{
7225 int res = 0;
7226
7227 if (!dev) {
7228 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
7229 return -1;
7230 }
7231
7232 net_os_wake_lock(dev);
7233 DHD_OS_MUTEX_LOCK(&wl_softap_lock);
7234
7235 WL_TRACE(("%s: rcvd IWPRIV IOCTL: for dev:%s\n", __FUNCTION__, dev->name));
7236
7237
7238#ifndef AP_ONLY
7239 if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) {
7240 WL_ERROR((" %s ERROR setting SOFTAP security in :%d\n", __FUNCTION__, res));
7241 }
7242 else {
7243
7244 if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0)
7245 WL_ERROR(("%s fail to set bss up err=%d\n", __FUNCTION__, res));
7246 else
7247
7248 bcm_mdelay(100);
7249 }
7250
7251#endif
7252 WL_SOFTAP(("%s done with res %d \n", __FUNCTION__, res));
7253
7254 DHD_OS_MUTEX_UNLOCK(&wl_softap_lock);
7255 net_os_wake_unlock(dev);
7256
7257 return res;
7258}
7259
7260static int
7261get_assoc_sta_list(struct net_device *dev, char *buf, int len)
7262{
7263
7264 WL_TRACE(("%s: dev_wlc_ioctl(dev:%p, cmd:%d, buf:%p, len:%d)\n",
7265 __FUNCTION__, dev, WLC_GET_ASSOCLIST, buf, len));
7266
7267 return dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, buf, len);
7268
7269}
7270
7271
7272void check_error(int res, const char *msg, const char *func, int line)
7273{
7274 if (res != 0)
7275 WL_ERROR(("%s, %d function:%s, line:%d\n", msg, res, func, line));
7276}
7277
7278static int
7279set_ap_mac_list(struct net_device *dev, void *buf)
7280{
7281 struct mac_list_set *mac_list_set = (struct mac_list_set *)buf;
7282 struct maclist *maclist = (struct maclist *)&mac_list_set->mac_list;
7283 int length;
7284 int i;
7285 int mac_mode = mac_list_set->mode;
7286 int ioc_res = 0;
7287 ap_macmode = mac_list_set->mode;
7288
7289
7290 bzero(&ap_black_list, sizeof(struct mflist));
7291
7292 if (mac_mode == MACLIST_MODE_DISABLED) {
7293
7294 ioc_res = dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode));
7295 check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__);
7296 WL_SOFTAP(("%s: MAC filtering disabled\n", __FUNCTION__));
7297 } else {
7298
7299 scb_val_t scbval;
7300 char mac_buf[256] = {0};
7301 struct maclist *assoc_maclist = (struct maclist *) mac_buf;
7302
7303
7304 bcopy(maclist, &ap_black_list, sizeof(ap_black_list));
7305
7306
7307 ioc_res = dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode));
7308 check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__);
7309
7310
7311 length = sizeof(maclist->count) + maclist->count*ETHER_ADDR_LEN;
7312 dev_wlc_ioctl(dev, WLC_SET_MACLIST, maclist, length);
7313
7314 WL_SOFTAP(("%s: applied MAC List, mode:%d, length %d:\n",
7315 __FUNCTION__, mac_mode, length));
7316
7317 for (i = 0; i < maclist->count; i++)
7318 WL_SOFTAP(("mac %d: %02X:%02X:%02X:%02X:%02X:%02X\n",
7319 i, maclist->ea[i].octet[0], maclist->ea[i].octet[1],
7320 maclist->ea[i].octet[2],
7321 maclist->ea[i].octet[3], maclist->ea[i].octet[4],
7322 maclist->ea[i].octet[5]));
7323
7324
7325 assoc_maclist->count = 8;
7326 ioc_res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 256);
7327 check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__);
7328 WL_SOFTAP((" Cur assoc clients:%d\n", assoc_maclist->count));
7329
7330
7331 if (assoc_maclist->count)
7332 for (i = 0; i < assoc_maclist->count; i++) {
7333 int j;
7334 bool assoc_mac_matched = FALSE;
7335
7336 WL_SOFTAP(("\n Cheking assoc STA: "));
7337 dhd_print_buf(&assoc_maclist->ea[i], 6, 7);
7338 WL_SOFTAP(("with the b/w list:"));
7339
7340 for (j = 0; j < maclist->count; j++)
7341 if (!bcmp(&assoc_maclist->ea[i], &maclist->ea[j],
7342 ETHER_ADDR_LEN)) {
7343
7344 assoc_mac_matched = TRUE;
7345 break;
7346 }
7347
7348
7349 if (((mac_mode == MACLIST_MODE_ALLOW) && !assoc_mac_matched) ||
7350 ((mac_mode == MACLIST_MODE_DENY) && assoc_mac_matched)) {
7351
7352 WL_SOFTAP(("b-match or w-mismatch,"
7353 " do deauth/disassoc \n"));
7354 scbval.val = htod32(1);
7355 bcopy(&assoc_maclist->ea[i], &scbval.ea,
7356 ETHER_ADDR_LEN);
7357 ioc_res = dev_wlc_ioctl(dev,
7358 WLC_SCB_DEAUTHENTICATE_FOR_REASON,
7359 &scbval, sizeof(scb_val_t));
7360 check_error(ioc_res,
7361 "ioctl ERROR:",
7362 __FUNCTION__, __LINE__);
7363
7364 } else {
7365 WL_SOFTAP((" no b/w list hits, let it be\n"));
7366 }
7367 } else {
7368 WL_SOFTAP(("No ASSOC CLIENTS\n"));
7369 }
7370
7371 }
7372
7373 WL_SOFTAP(("%s iocres:%d\n", __FUNCTION__, ioc_res));
7374 return ioc_res;
7375}
7376#endif
7377
7378
7379
7380#ifdef SOFTAP
7381#define PARAM_OFFSET PROFILE_OFFSET
7382
7383static int
7384wl_iw_process_private_ascii_cmd(
7385 struct net_device *dev,
7386 struct iw_request_info *info,
7387 union iwreq_data *dwrq,
7388 char *cmd_str)
7389{
7390 int ret = 0;
7391 char *sub_cmd = cmd_str + PROFILE_OFFSET + strlen("ASCII_CMD=");
7392
7393 WL_SOFTAP(("\n %s: ASCII_CMD: offs_0:%s, offset_32:\n'%s'\n",
7394 __FUNCTION__, cmd_str, cmd_str + PROFILE_OFFSET));
7395
7396 if (strnicmp(sub_cmd, "AP_CFG", strlen("AP_CFG")) == 0) {
7397
7398 WL_SOFTAP((" AP_CFG \n"));
7399
7400
7401 if (init_ap_profile_from_string(cmd_str+PROFILE_OFFSET, &my_ap) != 0) {
7402 WL_ERROR(("ERROR: SoftAP CFG prams !\n"));
7403 ret = -1;
7404 } else {
7405 ret = set_ap_cfg(dev, &my_ap);
7406 }
7407
7408 } else if (strnicmp(sub_cmd, "AP_BSS_START", strlen("AP_BSS_START")) == 0) {
7409
7410 WL_SOFTAP(("\n SOFTAP - ENABLE BSS \n"));
7411
7412
7413 WL_SOFTAP(("\n!!! got 'WL_AP_EN_BSS' from WPA supplicant, dev:%s\n", dev->name));
7414
7415#ifndef AP_ONLY
7416 if (ap_net_dev == NULL) {
7417 printf("\n ERROR: SOFTAP net_dev* is NULL !!!\n");
7418 } else {
7419
7420 if ((ret = iwpriv_en_ap_bss(ap_net_dev, info, dwrq, cmd_str)) < 0)
7421 WL_ERROR(("%s line %d fail to set bss up\n",
7422 __FUNCTION__, __LINE__));
7423 }
7424#else
7425 if ((ret = iwpriv_en_ap_bss(dev, info, dwrq, cmd_str)) < 0)
7426 WL_ERROR(("%s line %d fail to set bss up\n",
7427 __FUNCTION__, __LINE__));
7428#endif
7429 } else if (strnicmp(sub_cmd, "ASSOC_LST", strlen("ASSOC_LST")) == 0) {
7430
7431
7432
7433 } else if (strnicmp(sub_cmd, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) {
7434
7435 WL_SOFTAP((" \n temp DOWN SOFTAP\n"));
7436#ifndef AP_ONLY
7437 if ((ret = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) {
7438 WL_ERROR(("%s line %d fail to set bss down\n",
7439 __FUNCTION__, __LINE__));
7440 }
7441#endif
7442 }
7443
7444 return ret;
7445
7446}
7447#endif
7448
7449
7450static int
7451wl_iw_set_priv(
7452 struct net_device *dev,
7453 struct iw_request_info *info,
7454 struct iw_point *dwrq,
7455 char *ext
7456)
7457{
7458 int ret = 0;
7459 char * extra;
7460
7461 if (!(extra = kmalloc(dwrq->length, GFP_KERNEL)))
7462 return -ENOMEM;
7463
7464 if (copy_from_user(extra, dwrq->pointer, dwrq->length)) {
7465 kfree(extra);
7466 return -EFAULT;
7467 }
7468
7469 WL_TRACE(("%s: SIOCSIWPRIV request %s, info->cmd:%x, info->flags:%d\n dwrq->length:%d\n",
7470 dev->name, extra, info->cmd, info->flags, dwrq->length));
7471
7472
7473
7474 net_os_wake_lock(dev);
7475
7476 if (dwrq->length && extra) {
7477 if (strnicmp(extra, "START", strlen("START")) == 0) {
7478 wl_iw_control_wl_on(dev, info);
7479 WL_TRACE(("%s, Received regular START command\n", __FUNCTION__));
7480 }
7481
7482 if (g_onoff == G_WLAN_SET_OFF) {
7483 WL_TRACE(("%s, missing START, Fail\n", __FUNCTION__));
7484 kfree(extra);
7485 net_os_wake_unlock(dev);
7486 return -EFAULT;
7487 }
7488
7489 if (strnicmp(extra, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
7490#ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS
7491 WL_TRACE(("%s: active scan setting suppressed\n", dev->name));
7492#else
7493 ret = wl_iw_set_active_scan(dev, info, (union iwreq_data *)dwrq, extra);
7494#endif
7495 }
7496 else if (strnicmp(extra, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0)
7497#ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS
7498 WL_TRACE(("%s: passive scan setting suppressed\n", dev->name));
7499#else
7500 ret = wl_iw_set_passive_scan(dev, info, (union iwreq_data *)dwrq, extra);
7501#endif
7502 else if (strnicmp(extra, "RSSI", strlen("RSSI")) == 0)
7503 ret = wl_iw_get_rssi(dev, info, (union iwreq_data *)dwrq, extra);
7504 else if (strnicmp(extra, "LINKSPEED", strlen("LINKSPEED")) == 0)
7505 ret = wl_iw_get_link_speed(dev, info, (union iwreq_data *)dwrq, extra);
7506 else if (strnicmp(extra, "MACADDR", strlen("MACADDR")) == 0)
7507 ret = wl_iw_get_macaddr(dev, info, (union iwreq_data *)dwrq, extra);
7508 else if (strnicmp(extra, "COUNTRY", strlen("COUNTRY")) == 0)
7509 ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra);
7510 else if (strnicmp(extra, "STOP", strlen("STOP")) == 0)
7511 ret = wl_iw_control_wl_off(dev, info);
7512 else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0)
7513 ret = wl_iw_get_band(dev, info, (union iwreq_data *)dwrq, extra);
7514 else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0)
7515 ret = wl_iw_set_band(dev, info, (union iwreq_data *)dwrq, extra);
7516 else if (strnicmp(extra, DTIM_SKIP_GET_CMD, strlen(DTIM_SKIP_GET_CMD)) == 0)
7517 ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
7518 else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0)
7519 ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
7520 else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0)
7521 ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra);
7522 else if (strnicmp(extra, TXPOWER_SET_CMD, strlen(TXPOWER_SET_CMD)) == 0)
7523 ret = wl_iw_set_txpower(dev, info, (union iwreq_data *)dwrq, extra);
7524#if defined(PNO_SUPPORT)
7525 else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0)
7526 ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra);
7527 else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0)
7528 ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra);
7529 else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0)
7530 ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra);
7531#endif
7532#if defined(CSCAN)
7533
7534 else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0)
7535 ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra);
7536#endif
7537#ifdef CONFIG_WPS2
7538 else if (strnicmp(extra, WPS_ADD_PROBE_REQ_IE_CMD,
7539 strlen(WPS_ADD_PROBE_REQ_IE_CMD)) == 0)
7540 ret = wl_iw_add_wps_probe_req_ie(dev, info,
7541 (union iwreq_data *)dwrq, extra);
7542 else if (strnicmp(extra, WPS_DEL_PROBE_REQ_IE_CMD,
7543 strlen(WPS_DEL_PROBE_REQ_IE_CMD)) == 0)
7544 ret = wl_iw_del_wps_probe_req_ie(dev, info,
7545 (union iwreq_data *)dwrq, extra);
7546#endif
7547 else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
7548 ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
7549 else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0)
7550 ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra);
7551 else if (strnicmp(extra, "GETPOWER", strlen("GETPOWER")) == 0)
7552 ret = wl_iw_get_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
7553#ifdef SOFTAP
7554 else if (strnicmp(extra, "ASCII_CMD", strlen("ASCII_CMD")) == 0) {
7555 wl_iw_process_private_ascii_cmd(dev, info, (union iwreq_data *)dwrq, extra);
7556 }
7557 else if (strnicmp(extra, "AP_MAC_LIST_SET", strlen("AP_MAC_LIST_SET")) == 0) {
7558 WL_SOFTAP(("penguin, set AP_MAC_LIST_SET\n"));
7559 set_ap_mac_list(dev, (extra + PROFILE_OFFSET));
7560 }
7561#endif
7562 else {
7563 WL_ERROR(("Unknown PRIVATE command %s - ignored\n", extra));
7564 snprintf(extra, MAX_WX_STRING, "OK");
7565 dwrq->length = strlen("OK") + 1;
7566 }
7567 }
7568
7569 net_os_wake_unlock(dev);
7570
7571 if (extra) {
7572 if (copy_to_user(dwrq->pointer, extra, dwrq->length)) {
7573 kfree(extra);
7574 return -EFAULT;
7575 }
7576
7577 kfree(extra);
7578 }
7579
7580 return ret;
7581}
7582
7583static const iw_handler wl_iw_handler[] =
7584{
7585 (iw_handler) wl_iw_config_commit,
7586 (iw_handler) wl_iw_get_name,
7587 (iw_handler) NULL,
7588 (iw_handler) NULL,
7589 (iw_handler) wl_iw_set_freq,
7590 (iw_handler) wl_iw_get_freq,
7591 (iw_handler) wl_iw_set_mode,
7592 (iw_handler) wl_iw_get_mode,
7593 (iw_handler) NULL,
7594 (iw_handler) NULL,
7595 (iw_handler) NULL,
7596 (iw_handler) wl_iw_get_range,
7597 (iw_handler) wl_iw_set_priv,
7598 (iw_handler) NULL,
7599 (iw_handler) NULL,
7600 (iw_handler) NULL,
7601 (iw_handler) wl_iw_set_spy,
7602 (iw_handler) wl_iw_get_spy,
7603 (iw_handler) NULL,
7604 (iw_handler) NULL,
7605 (iw_handler) wl_iw_set_wap,
7606 (iw_handler) wl_iw_get_wap,
7607#if WIRELESS_EXT > 17
7608 (iw_handler) wl_iw_mlme,
7609#else
7610 (iw_handler) NULL,
7611#endif
7612#if defined(WL_IW_USE_ISCAN)
7613 (iw_handler) wl_iw_iscan_get_aplist,
7614#else
7615 (iw_handler) wl_iw_get_aplist,
7616#endif
7617#if WIRELESS_EXT > 13
7618#if defined(WL_IW_USE_ISCAN)
7619 (iw_handler) wl_iw_iscan_set_scan,
7620 (iw_handler) wl_iw_iscan_get_scan,
7621#else
7622 (iw_handler) wl_iw_set_scan,
7623 (iw_handler) wl_iw_get_scan,
7624#endif
7625#else
7626 (iw_handler) NULL,
7627 (iw_handler) NULL,
7628#endif
7629 (iw_handler) wl_iw_set_essid,
7630 (iw_handler) wl_iw_get_essid,
7631 (iw_handler) wl_iw_set_nick,
7632 (iw_handler) wl_iw_get_nick,
7633 (iw_handler) NULL,
7634 (iw_handler) NULL,
7635 (iw_handler) wl_iw_set_rate,
7636 (iw_handler) wl_iw_get_rate,
7637 (iw_handler) wl_iw_set_rts,
7638 (iw_handler) wl_iw_get_rts,
7639 (iw_handler) wl_iw_set_frag,
7640 (iw_handler) wl_iw_get_frag,
7641 (iw_handler) wl_iw_set_txpow,
7642 (iw_handler) wl_iw_get_txpow,
7643#if WIRELESS_EXT > 10
7644 (iw_handler) wl_iw_set_retry,
7645 (iw_handler) wl_iw_get_retry,
7646#endif
7647 (iw_handler) wl_iw_set_encode,
7648 (iw_handler) wl_iw_get_encode,
7649 (iw_handler) wl_iw_set_power,
7650 (iw_handler) wl_iw_get_power,
7651#if WIRELESS_EXT > 17
7652 (iw_handler) NULL,
7653 (iw_handler) NULL,
7654 (iw_handler) wl_iw_set_wpaie,
7655 (iw_handler) wl_iw_get_wpaie,
7656 (iw_handler) wl_iw_set_wpaauth,
7657 (iw_handler) wl_iw_get_wpaauth,
7658 (iw_handler) wl_iw_set_encodeext,
7659 (iw_handler) wl_iw_get_encodeext,
7660 (iw_handler) wl_iw_set_pmksa,
7661#endif
7662};
7663
7664#if WIRELESS_EXT > 12
7665static const iw_handler wl_iw_priv_handler[] = {
7666 NULL,
7667 (iw_handler)wl_iw_set_active_scan,
7668 NULL,
7669 (iw_handler)wl_iw_get_rssi,
7670 NULL,
7671 (iw_handler)wl_iw_set_passive_scan,
7672 NULL,
7673 (iw_handler)wl_iw_get_link_speed,
7674 NULL,
7675 (iw_handler)wl_iw_get_macaddr,
7676 NULL,
7677 (iw_handler)wl_iw_control_wl_off,
7678 NULL,
7679 (iw_handler)wl_iw_control_wl_on,
7680#ifdef SOFTAP
7681
7682
7683 NULL,
7684 (iw_handler)iwpriv_set_ap_config,
7685
7686
7687
7688 NULL,
7689 (iw_handler)iwpriv_get_assoc_list,
7690
7691
7692 NULL,
7693 (iw_handler)iwpriv_set_mac_filters,
7694
7695
7696 NULL,
7697 (iw_handler)iwpriv_en_ap_bss,
7698
7699
7700 NULL,
7701 (iw_handler)iwpriv_wpasupp_loop_tst,
7702
7703 NULL,
7704 (iw_handler)iwpriv_softap_stop,
7705
7706 NULL,
7707 (iw_handler)iwpriv_fw_reload,
7708 NULL,
7709 (iw_handler)iwpriv_set_ap_sta_disassoc,
7710#endif
7711#if defined(CSCAN)
7712
7713 NULL,
7714 (iw_handler)iwpriv_set_cscan
7715#endif
7716};
7717
7718static const struct iw_priv_args wl_iw_priv_args[] =
7719{
7720 {
7721 WL_IW_SET_ACTIVE_SCAN,
7722 0,
7723 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7724 "SCAN-ACTIVE"
7725 },
7726 {
7727 WL_IW_GET_RSSI,
7728 0,
7729 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7730 "RSSI"
7731 },
7732 {
7733 WL_IW_SET_PASSIVE_SCAN,
7734 0,
7735 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7736 "SCAN-PASSIVE"
7737 },
7738 {
7739 WL_IW_GET_LINK_SPEED,
7740 0,
7741 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7742 "LINKSPEED"
7743 },
7744 {
7745 WL_IW_GET_CURR_MACADDR,
7746 0,
7747 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7748 "Macaddr"
7749 },
7750 {
7751 WL_IW_SET_STOP,
7752 0,
7753 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7754 "STOP"
7755 },
7756 {
7757 WL_IW_SET_START,
7758 0,
7759 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7760 "START"
7761 },
7762
7763#ifdef SOFTAP
7764
7765
7766 {
7767 WL_SET_AP_CFG,
7768 IW_PRIV_TYPE_CHAR | 256,
7769 0,
7770 "AP_SET_CFG"
7771 },
7772
7773 {
7774 WL_AP_STA_LIST,
7775 IW_PRIV_TYPE_CHAR | 0,
7776 IW_PRIV_TYPE_CHAR | 1024,
7777 "AP_GET_STA_LIST"
7778 },
7779
7780 {
7781 WL_AP_MAC_FLTR,
7782 IW_PRIV_TYPE_CHAR | 256,
7783 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7784 "AP_SET_MAC_FLTR"
7785 },
7786
7787 {
7788 WL_AP_BSS_START,
7789 0,
7790 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7791 "AP_BSS_START"
7792 },
7793
7794 {
7795 AP_LPB_CMD,
7796 IW_PRIV_TYPE_CHAR | 256,
7797 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7798 "AP_LPB_CMD"
7799 },
7800
7801 {
7802 WL_AP_STOP,
7803 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7804 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7805 "AP_BSS_STOP"
7806 },
7807 {
7808 WL_FW_RELOAD,
7809 IW_PRIV_TYPE_CHAR | 256,
7810 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7811 "WL_FW_RELOAD"
7812 },
7813#endif
7814#if defined(CSCAN)
7815 {
7816 WL_COMBO_SCAN,
7817 IW_PRIV_TYPE_CHAR | 1024,
7818 0,
7819 "CSCAN"
7820 },
7821#endif
7822 };
7823
7824const struct iw_handler_def wl_iw_handler_def =
7825{
7826 .num_standard = ARRAYSIZE(wl_iw_handler),
7827 .standard = (iw_handler *) wl_iw_handler,
7828 .num_private = ARRAYSIZE(wl_iw_priv_handler),
7829 .num_private_args = ARRAY_SIZE(wl_iw_priv_args),
7830 .private = (iw_handler *)wl_iw_priv_handler,
7831 .private_args = (void *) wl_iw_priv_args,
7832
7833#if WIRELESS_EXT >= 19
7834 get_wireless_stats: dhd_get_wireless_stats,
7835#endif
7836 };
7837#endif
7838
7839
7840
7841int
7842wl_iw_ioctl(
7843 struct net_device *dev,
7844 struct ifreq *rq,
7845 int cmd
7846)
7847{
7848 struct iwreq *wrq = (struct iwreq *) rq;
7849 struct iw_request_info info;
7850 iw_handler handler;
7851 char *extra = NULL;
7852 size_t token_size = 1;
7853 int max_tokens = 0, ret = 0;
7854
7855 net_os_wake_lock(dev);
7856
7857 WL_TRACE(("\n%s, cmd:%x called via dhd->do_ioctl()entry point\n", __FUNCTION__, cmd));
7858 if (cmd < SIOCIWFIRST ||
7859 IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) ||
7860 !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) {
7861 WL_ERROR(("%s: error in cmd=%x : not supported\n", __FUNCTION__, cmd));
7862 net_os_wake_unlock(dev);
7863 return -EOPNOTSUPP;
7864 }
7865
7866 switch (cmd) {
7867
7868 case SIOCSIWESSID:
7869 case SIOCGIWESSID:
7870 case SIOCSIWNICKN:
7871 case SIOCGIWNICKN:
7872 max_tokens = IW_ESSID_MAX_SIZE + 1;
7873 break;
7874
7875 case SIOCSIWENCODE:
7876 case SIOCGIWENCODE:
7877#if WIRELESS_EXT > 17
7878 case SIOCSIWENCODEEXT:
7879 case SIOCGIWENCODEEXT:
7880#endif
7881 max_tokens = wrq->u.data.length;
7882 break;
7883
7884 case SIOCGIWRANGE:
7885
7886 max_tokens = sizeof(struct iw_range) + 500;
7887 break;
7888
7889 case SIOCGIWAPLIST:
7890 token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality);
7891 max_tokens = IW_MAX_AP;
7892 break;
7893
7894#if WIRELESS_EXT > 13
7895 case SIOCGIWSCAN:
7896#if defined(WL_IW_USE_ISCAN)
7897 if (g_iscan)
7898 max_tokens = wrq->u.data.length;
7899 else
7900#endif
7901 max_tokens = IW_SCAN_MAX_DATA;
7902 break;
7903#endif
7904
7905 case SIOCSIWSPY:
7906 token_size = sizeof(struct sockaddr);
7907 max_tokens = IW_MAX_SPY;
7908 break;
7909
7910 case SIOCGIWSPY:
7911 token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality);
7912 max_tokens = IW_MAX_SPY;
7913 break;
7914
7915#if WIRELESS_EXT > 17
7916 case SIOCSIWPMKSA:
7917 case SIOCSIWGENIE:
7918#endif
7919 case SIOCSIWPRIV:
7920 max_tokens = wrq->u.data.length;
7921 break;
7922 }
7923
7924 if (max_tokens && wrq->u.data.pointer) {
7925 if (wrq->u.data.length > max_tokens) {
7926 WL_ERROR(("%s: error in cmd=%x wrq->u.data.length=%d > max_tokens=%d\n",
7927 __FUNCTION__, cmd, wrq->u.data.length, max_tokens));
7928 ret = -E2BIG;
7929 goto wl_iw_ioctl_done;
7930 }
7931 if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) {
7932 ret = -ENOMEM;
7933 goto wl_iw_ioctl_done;
7934 }
7935
7936 if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) {
7937 kfree(extra);
7938 ret = -EFAULT;
7939 goto wl_iw_ioctl_done;
7940 }
7941 }
7942
7943 info.cmd = cmd;
7944 info.flags = 0;
7945
7946 ret = handler(dev, &info, &wrq->u, extra);
7947
7948 if (extra) {
7949 if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) {
7950 kfree(extra);
7951 ret = -EFAULT;
7952 goto wl_iw_ioctl_done;
7953 }
7954
7955 kfree(extra);
7956 }
7957
7958wl_iw_ioctl_done:
7959
7960 net_os_wake_unlock(dev);
7961
7962 return ret;
7963}
7964
7965
7966static bool
7967wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason,
7968 char* stringBuf, uint buflen)
7969{
7970 typedef struct conn_fail_event_map_t {
7971 uint32 inEvent;
7972 uint32 inStatus;
7973 uint32 inReason;
7974 const char* outName;
7975 const char* outCause;
7976 } conn_fail_event_map_t;
7977
7978
7979#define WL_IW_DONT_CARE 9999
7980 const conn_fail_event_map_t event_map [] = {
7981
7982
7983 {WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE,
7984 "Conn", "Success"},
7985 {WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE,
7986 "Conn", "NoNetworks"},
7987 {WLC_E_SET_SSID, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
7988 "Conn", "ConfigMismatch"},
7989 {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_PRUNE_ENCR_MISMATCH,
7990 "Conn", "EncrypMismatch"},
7991 {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_RSN_MISMATCH,
7992 "Conn", "RsnMismatch"},
7993 {WLC_E_AUTH, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
7994 "Conn", "AuthTimeout"},
7995 {WLC_E_AUTH, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
7996 "Conn", "AuthFail"},
7997 {WLC_E_AUTH, WLC_E_STATUS_NO_ACK, WL_IW_DONT_CARE,
7998 "Conn", "AuthNoAck"},
7999 {WLC_E_REASSOC, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
8000 "Conn", "ReassocFail"},
8001 {WLC_E_REASSOC, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
8002 "Conn", "ReassocTimeout"},
8003 {WLC_E_REASSOC, WLC_E_STATUS_ABORT, WL_IW_DONT_CARE,
8004 "Conn", "ReassocAbort"},
8005 {WLC_E_PSK_SUP, WLC_SUP_KEYED, WL_IW_DONT_CARE,
8006 "Sup", "ConnSuccess"},
8007 {WLC_E_PSK_SUP, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
8008 "Sup", "WpaHandshakeFail"},
8009 {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
8010 "Conn", "Deauth"},
8011 {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
8012 "Conn", "DisassocInd"},
8013 {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
8014 "Conn", "Disassoc"}
8015 };
8016
8017 const char* name = "";
8018 const char* cause = NULL;
8019 int i;
8020
8021
8022 for (i = 0; i < sizeof(event_map)/sizeof(event_map[0]); i++) {
8023 const conn_fail_event_map_t* row = &event_map[i];
8024 if (row->inEvent == event_type &&
8025 (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) &&
8026 (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) {
8027 name = row->outName;
8028 cause = row->outCause;
8029 break;
8030 }
8031 }
8032
8033
8034 if (cause) {
8035 memset(stringBuf, 0, buflen);
8036 snprintf(stringBuf, buflen, "%s %s %02d %02d",
8037 name, cause, status, reason);
8038 WL_INFORM(("Connection status: %s\n", stringBuf));
8039 return TRUE;
8040 } else {
8041 return FALSE;
8042 }
8043}
8044
8045#if WIRELESS_EXT > 14
8046
8047static bool
8048wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen)
8049{
8050 uint32 event = ntoh32(e->event_type);
8051 uint32 status = ntoh32(e->status);
8052 uint32 reason = ntoh32(e->reason);
8053
8054 if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) {
8055 return TRUE;
8056 }
8057 else
8058 return FALSE;
8059}
8060#endif
8061
8062#ifndef IW_CUSTOM_MAX
8063#define IW_CUSTOM_MAX 256
8064#endif
8065
8066void
8067wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
8068{
8069#if WIRELESS_EXT > 13
8070 union iwreq_data wrqu;
8071 char extra[IW_CUSTOM_MAX + 1];
8072 int cmd = 0;
8073 uint32 event_type = ntoh32(e->event_type);
8074 uint16 flags = ntoh16(e->flags);
8075 uint32 datalen = ntoh32(e->datalen);
8076 uint32 status = ntoh32(e->status);
8077 uint32 toto;
8078 memset(&wrqu, 0, sizeof(wrqu));
8079 memset(extra, 0, sizeof(extra));
8080
8081 if (!dev) {
8082 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
8083 return;
8084 }
8085
8086 net_os_wake_lock(dev);
8087
8088 WL_TRACE(("%s: dev=%s event=%d \n", __FUNCTION__, dev->name, event_type));
8089
8090
8091 switch (event_type) {
8092#if defined(SOFTAP)
8093 case WLC_E_PRUNE:
8094 if (ap_cfg_running) {
8095 char *macaddr = (char *)&e->addr;
8096 WL_SOFTAP(("PRUNE received, %02X:%02X:%02X:%02X:%02X:%02X!\n",
8097 macaddr[0], macaddr[1], macaddr[2], macaddr[3],
8098 macaddr[4], macaddr[5]));
8099
8100
8101 if (ap_macmode)
8102 {
8103 int i;
8104 for (i = 0; i < ap_black_list.count; i++) {
8105 if (!bcmp(macaddr, &ap_black_list.ea[i],
8106 sizeof(struct ether_addr))) {
8107 WL_SOFTAP(("mac in black list, ignore it\n"));
8108 break;
8109 }
8110 }
8111
8112 if (i == ap_black_list.count) {
8113
8114 char mac_buf[32] = {0};
8115 sprintf(mac_buf, "STA_BLOCK %02X:%02X:%02X:%02X:%02X:%02X",
8116 macaddr[0], macaddr[1], macaddr[2],
8117 macaddr[3], macaddr[4], macaddr[5]);
8118 wl_iw_send_priv_event(priv_dev, mac_buf);
8119 }
8120 }
8121 }
8122 break;
8123#endif
8124 case WLC_E_TXFAIL:
8125 cmd = IWEVTXDROP;
8126 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
8127 wrqu.addr.sa_family = ARPHRD_ETHER;
8128 break;
8129#if WIRELESS_EXT > 14
8130 case WLC_E_JOIN:
8131 case WLC_E_ASSOC_IND:
8132 case WLC_E_REASSOC_IND:
8133#if defined(SOFTAP)
8134 WL_SOFTAP(("STA connect received %d\n", event_type));
8135 if (ap_cfg_running) {
8136 wl_iw_send_priv_event(priv_dev, "STA_JOIN");
8137 goto wl_iw_event_end;
8138 }
8139#endif
8140 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
8141 wrqu.addr.sa_family = ARPHRD_ETHER;
8142 cmd = IWEVREGISTERED;
8143 break;
8144 case WLC_E_ROAM:
8145 if (status == WLC_E_STATUS_SUCCESS) {
8146 WL_ASSOC((" WLC_E_ROAM : success \n"));
8147 goto wl_iw_event_end;
8148 }
8149 break;
8150
8151 case WLC_E_DEAUTH_IND:
8152 case WLC_E_DISASSOC_IND:
8153#if defined(SOFTAP)
8154 WL_SOFTAP(("STA disconnect received %d\n", event_type));
8155 if (ap_cfg_running) {
8156 wl_iw_send_priv_event(priv_dev, "STA_LEAVE");
8157 goto wl_iw_event_end;
8158 }
8159#endif
8160 cmd = SIOCGIWAP;
8161 bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
8162 wrqu.addr.sa_family = ARPHRD_ETHER;
8163 bzero(&extra, ETHER_ADDR_LEN);
8164 break;
8165 case WLC_E_LINK:
8166 case WLC_E_NDIS_LINK:
8167 cmd = SIOCGIWAP;
8168 if (!(flags & WLC_EVENT_MSG_LINK)) {
8169
8170
8171#ifdef SOFTAP
8172#ifdef AP_ONLY
8173 if (ap_cfg_running) {
8174#else
8175 if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) {
8176#endif
8177
8178 WL_SOFTAP(("AP DOWN %d\n", event_type));
8179 wl_iw_send_priv_event(priv_dev, "AP_DOWN");
8180 } else {
8181 WL_TRACE(("STA_Link Down\n"));
8182 g_ss_cache_ctrl.m_link_down = 1;
8183 }
8184#else
8185 g_ss_cache_ctrl.m_link_down = 1;
8186#endif
8187 WL_TRACE(("Link Down\n"));
8188
8189 bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
8190 bzero(&extra, ETHER_ADDR_LEN);
8191 }
8192 else {
8193
8194 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
8195 g_ss_cache_ctrl.m_link_down = 0;
8196
8197 memcpy(g_ss_cache_ctrl.m_active_bssid, &e->addr, ETHER_ADDR_LEN);
8198#ifdef SOFTAP
8199
8200#ifdef AP_ONLY
8201 if (ap_cfg_running) {
8202#else
8203 if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) {
8204#endif
8205
8206 WL_SOFTAP(("AP UP %d\n", event_type));
8207 wl_iw_send_priv_event(priv_dev, "AP_UP");
8208 } else {
8209 WL_TRACE(("STA_LINK_UP\n"));
8210 }
8211#else
8212#endif
8213 WL_TRACE(("Link UP\n"));
8214
8215 }
8216 wrqu.addr.sa_family = ARPHRD_ETHER;
8217 break;
8218 case WLC_E_ACTION_FRAME:
8219 cmd = IWEVCUSTOM;
8220 if (datalen + 1 <= sizeof(extra)) {
8221 wrqu.data.length = datalen + 1;
8222 extra[0] = WLC_E_ACTION_FRAME;
8223 memcpy(&extra[1], data, datalen);
8224 WL_TRACE(("WLC_E_ACTION_FRAME len %d \n", wrqu.data.length));
8225 }
8226 break;
8227
8228 case WLC_E_ACTION_FRAME_COMPLETE:
8229 cmd = IWEVCUSTOM;
8230 memcpy(&toto, data, 4);
8231 if (sizeof(status) + 1 <= sizeof(extra)) {
8232 wrqu.data.length = sizeof(status) + 1;
8233 extra[0] = WLC_E_ACTION_FRAME_COMPLETE;
8234 memcpy(&extra[1], &status, sizeof(status));
8235 printf("wl_iw_event status %d PacketId %d \n", status, toto);
8236 printf("WLC_E_ACTION_FRAME_COMPLETE len %d \n", wrqu.data.length);
8237 }
8238 break;
8239#endif
8240#if WIRELESS_EXT > 17
8241 case WLC_E_MIC_ERROR: {
8242 struct iw_michaelmicfailure *micerrevt = (struct iw_michaelmicfailure *)&extra;
8243 cmd = IWEVMICHAELMICFAILURE;
8244 wrqu.data.length = sizeof(struct iw_michaelmicfailure);
8245 if (flags & WLC_EVENT_MSG_GROUP)
8246 micerrevt->flags |= IW_MICFAILURE_GROUP;
8247 else
8248 micerrevt->flags |= IW_MICFAILURE_PAIRWISE;
8249 memcpy(micerrevt->src_addr.sa_data, &e->addr, ETHER_ADDR_LEN);
8250 micerrevt->src_addr.sa_family = ARPHRD_ETHER;
8251
8252 break;
8253 }
8254 case WLC_E_PMKID_CACHE: {
8255 if (data)
8256 {
8257 struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra;
8258 pmkid_cand_list_t *pmkcandlist;
8259 pmkid_cand_t *pmkidcand;
8260 int count;
8261
8262 cmd = IWEVPMKIDCAND;
8263 pmkcandlist = data;
8264 count = ntoh32_ua((uint8 *)&pmkcandlist->npmkid_cand);
8265 ASSERT(count >= 0);
8266 wrqu.data.length = sizeof(struct iw_pmkid_cand);
8267 pmkidcand = pmkcandlist->pmkid_cand;
8268 while (count) {
8269 bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand));
8270 if (pmkidcand->preauth)
8271 iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH;
8272 bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data,
8273 ETHER_ADDR_LEN);
8274 wireless_send_event(dev, cmd, &wrqu, extra);
8275 pmkidcand++;
8276 count--;
8277 }
8278 }
8279 goto wl_iw_event_end;
8280 }
8281#endif
8282
8283 case WLC_E_SCAN_COMPLETE:
8284#if defined(WL_IW_USE_ISCAN)
8285 if (!g_iscan) {
8286 WL_ERROR(("Event WLC_E_SCAN_COMPLETE on g_iscan NULL!"));
8287 goto wl_iw_event_end;
8288 }
8289
8290 if ((g_iscan) && (g_iscan->tsk_ctl.thr_pid >= 0) &&
8291 (g_iscan->iscan_state != ISCAN_STATE_IDLE))
8292 {
8293 up(&g_iscan->tsk_ctl.sema);
8294 } else {
8295 cmd = SIOCGIWSCAN;
8296 wrqu.data.length = strlen(extra);
8297 WL_TRACE(("Event WLC_E_SCAN_COMPLETE from specific scan %d\n",
8298 g_iscan->iscan_state));
8299 }
8300#else
8301 cmd = SIOCGIWSCAN;
8302 wrqu.data.length = strlen(extra);
8303 WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n"));
8304#endif
8305 break;
8306
8307
8308 case WLC_E_PFN_NET_FOUND:
8309 {
8310 wl_pfn_net_info_t *netinfo;
8311 netinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) -
8312 sizeof(wl_pfn_net_info_t));
8313 WL_ERROR(("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n",
8314 __FUNCTION__, PNO_EVENT_UP, netinfo->pfnsubnet.SSID,
8315 netinfo->pfnsubnet.SSID_len));
8316 cmd = IWEVCUSTOM;
8317 memset(&wrqu, 0, sizeof(wrqu));
8318 strcpy(extra, PNO_EVENT_UP);
8319 wrqu.data.length = strlen(extra);
8320 }
8321 break;
8322
8323 default:
8324
8325 WL_TRACE(("Unknown Event %d: ignoring\n", event_type));
8326 break;
8327 }
8328 if (cmd) {
8329 if (cmd == SIOCGIWSCAN)
8330 wireless_send_event(dev, cmd, &wrqu, NULL);
8331 else
8332 wireless_send_event(dev, cmd, &wrqu, extra);
8333 }
8334
8335#if WIRELESS_EXT > 14
8336
8337 memset(extra, 0, sizeof(extra));
8338 if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) {
8339 cmd = IWEVCUSTOM;
8340 wrqu.data.length = strlen(extra);
8341 wireless_send_event(dev, cmd, &wrqu, extra);
8342 }
8343#endif
8344
8345 goto wl_iw_event_end;
8346wl_iw_event_end:
8347
8348 net_os_wake_unlock(dev);
8349#endif
8350}
8351
8352int
8353wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
8354{
8355 int res = 0;
8356 wl_cnt_t cnt;
8357 int phy_noise;
8358 int rssi;
8359 scb_val_t scb_val;
8360
8361 phy_noise = 0;
8362 if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise))))
8363 goto done;
8364
8365 phy_noise = dtoh32(phy_noise);
8366 WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise));
8367
8368 bzero(&scb_val, sizeof(scb_val_t));
8369 if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t))))
8370 goto done;
8371
8372 rssi = dtoh32(scb_val.val);
8373 WL_TRACE(("wl_iw_get_wireless_stats rssi=%d\n", rssi));
8374 if (rssi <= WL_IW_RSSI_NO_SIGNAL)
8375 wstats->qual.qual = 0;
8376 else if (rssi <= WL_IW_RSSI_VERY_LOW)
8377 wstats->qual.qual = 1;
8378 else if (rssi <= WL_IW_RSSI_LOW)
8379 wstats->qual.qual = 2;
8380 else if (rssi <= WL_IW_RSSI_GOOD)
8381 wstats->qual.qual = 3;
8382 else if (rssi <= WL_IW_RSSI_VERY_GOOD)
8383 wstats->qual.qual = 4;
8384 else
8385 wstats->qual.qual = 5;
8386
8387
8388 wstats->qual.level = 0x100 + rssi;
8389 wstats->qual.noise = 0x100 + phy_noise;
8390#if WIRELESS_EXT > 18
8391 wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
8392#else
8393 wstats->qual.updated |= 7;
8394#endif
8395
8396#if WIRELESS_EXT > 11
8397 WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n", (int)sizeof(wl_cnt_t)));
8398
8399 memset(&cnt, 0, sizeof(wl_cnt_t));
8400 res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t));
8401 if (res)
8402 {
8403 WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d\n", res));
8404 goto done;
8405 }
8406
8407 cnt.version = dtoh16(cnt.version);
8408 if (cnt.version != WL_CNT_T_VERSION) {
8409 WL_TRACE(("\tIncorrect version of counters struct: expected %d; got %d\n",
8410 WL_CNT_T_VERSION, cnt.version));
8411 goto done;
8412 }
8413
8414 wstats->discard.nwid = 0;
8415 wstats->discard.code = dtoh32(cnt.rxundec);
8416 wstats->discard.fragment = dtoh32(cnt.rxfragerr);
8417 wstats->discard.retries = dtoh32(cnt.txfail);
8418 wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant);
8419 wstats->miss.beacon = 0;
8420
8421 WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n",
8422 dtoh32(cnt.txframe), dtoh32(cnt.txbyte)));
8423 WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", dtoh32(cnt.rxfrmtoolong)));
8424 WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", dtoh32(cnt.rxbadplcp)));
8425 WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n", dtoh32(cnt.rxundec)));
8426 WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n", dtoh32(cnt.rxfragerr)));
8427 WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n", dtoh32(cnt.txfail)));
8428 WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n", dtoh32(cnt.rxrunt)));
8429 WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n", dtoh32(cnt.rxgiant)));
8430
8431#endif
8432
8433done:
8434 return res;
8435}
8436#if defined(COEX_DHCP)
8437static void
8438wl_iw_bt_flag_set(
8439 struct net_device *dev,
8440 bool set)
8441{
8442#if defined(BT_DHCP_USE_FLAGS)
8443 char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
8444 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
8445#endif
8446
8447#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
8448 rtnl_lock();
8449#endif
8450
8451
8452#if defined(BT_DHCP_eSCO_FIX)
8453
8454 set_btc_esco_params(dev, set);
8455#endif
8456
8457
8458#if defined(BT_DHCP_USE_FLAGS)
8459 WL_TRACE_COEX(("WI-FI priority boost via bt flags, set:%d\n", set));
8460 if (set == TRUE) {
8461
8462 dev_wlc_bufvar_set(dev, "btc_flags",
8463 (char *)&buf_flag7_dhcp_on[0], sizeof(buf_flag7_dhcp_on));
8464 }
8465 else {
8466
8467 dev_wlc_bufvar_set(dev, "btc_flags",
8468 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
8469 }
8470#endif
8471
8472#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
8473 rtnl_unlock();
8474#endif
8475}
8476
8477static void
8478wl_iw_bt_timerfunc(ulong data)
8479{
8480 bt_info_t *bt_local = (bt_info_t *)data;
8481 bt_local->timer_on = 0;
8482 WL_TRACE(("%s\n", __FUNCTION__));
8483
8484 up(&bt_local->tsk_ctl.sema);
8485}
8486
8487static int
8488_bt_dhcp_sysioc_thread(void *data)
8489{
8490 tsk_ctl_t *tsk_ctl = (tsk_ctl_t *)data;
8491
8492 DAEMONIZE("dhcp_sysioc");
8493
8494 complete(&tsk_ctl->completed);
8495
8496 while (down_interruptible(&tsk_ctl->sema) == 0) {
8497
8498 SMP_RD_BARRIER_DEPENDS();
8499 if (tsk_ctl->terminated) {
8500 break;
8501 }
8502
8503 if (g_bt->timer_on) {
8504 g_bt->timer_on = 0;
8505 del_timer_sync(&g_bt->timer);
8506 }
8507
8508 switch (g_bt->bt_state) {
8509 case BT_DHCP_START:
8510
8511 WL_TRACE_COEX(("%s bt_dhcp stm: started \n", __FUNCTION__));
8512 g_bt->bt_state = BT_DHCP_OPPORTUNITY_WINDOW;
8513 mod_timer(&g_bt->timer,
8514 jiffies + BT_DHCP_OPPORTUNITY_WINDOW_TIME*HZ/1000);
8515 g_bt->timer_on = 1;
8516 break;
8517
8518 case BT_DHCP_OPPORTUNITY_WINDOW:
8519 if (g_bt->dhcp_done) {
8520 WL_TRACE_COEX(("%s DHCP Done before T1 expiration\n",
8521 __FUNCTION__));
8522 goto btc_coex_idle;
8523 }
8524
8525
8526 WL_TRACE_COEX(("%s DHCP T1:%d expired\n",
8527 __FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIME));
8528
8529 if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, TRUE);
8530 g_bt->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
8531 mod_timer(&g_bt->timer, jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
8532 g_bt->timer_on = 1;
8533 break;
8534
8535 case BT_DHCP_FLAG_FORCE_TIMEOUT:
8536 if (g_bt->dhcp_done) {
8537 WL_TRACE_COEX(("%s DHCP Done before T2 expiration\n",
8538 __FUNCTION__));
8539 } else {
8540
8541 WL_TRACE_COEX(("%s DHCP wait interval T2:%d msec expired\n",
8542 __FUNCTION__, BT_DHCP_FLAG_FORCE_TIME));
8543 }
8544
8545
8546 if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE);
8547 btc_coex_idle:
8548 g_bt->bt_state = BT_DHCP_IDLE;
8549 g_bt->timer_on = 0;
8550 break;
8551
8552 default:
8553 WL_ERROR(("%s error g_status=%d !!!\n", __FUNCTION__,
8554 g_bt->bt_state));
8555 if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE);
8556 g_bt->bt_state = BT_DHCP_IDLE;
8557 g_bt->timer_on = 0;
8558 break;
8559 }
8560
8561 net_os_wake_unlock(g_bt->dev);
8562 }
8563
8564 if (g_bt->timer_on) {
8565 g_bt->timer_on = 0;
8566 del_timer_sync(&g_bt->timer);
8567 }
8568 complete_and_exit(&tsk_ctl->completed, 0);
8569}
8570
8571static void
8572wl_iw_bt_release(void)
8573{
8574 bt_info_t *bt_local = g_bt;
8575
8576 if (!bt_local) {
8577 return;
8578 }
8579
8580 if (bt_local->tsk_ctl.thr_pid >= 0) {
8581 PROC_STOP(&bt_local->tsk_ctl);
8582 }
8583 kfree(bt_local);
8584 g_bt = NULL;
8585}
8586
8587static int
8588wl_iw_bt_init(struct net_device *dev)
8589{
8590 bt_info_t *bt_dhcp = NULL;
8591
8592 bt_dhcp = kmalloc(sizeof(bt_info_t), GFP_KERNEL);
8593 if (!bt_dhcp)
8594 return -ENOMEM;
8595
8596 memset(bt_dhcp, 0, sizeof(bt_info_t));
8597
8598 g_bt = bt_dhcp;
8599 bt_dhcp->dev = dev;
8600 bt_dhcp->bt_state = BT_DHCP_IDLE;
8601
8602
8603 bt_dhcp->timer_ms = 10;
8604 init_timer(&bt_dhcp->timer);
8605 bt_dhcp->timer.data = (ulong)bt_dhcp;
8606 bt_dhcp->timer.function = wl_iw_bt_timerfunc;
8607 bt_dhcp->ts_dhcp_start = 0;
8608 bt_dhcp->ts_dhcp_ok = 0;
8609
8610 PROC_START(_bt_dhcp_sysioc_thread, bt_dhcp, &bt_dhcp->tsk_ctl, 0);
8611 if (bt_dhcp->tsk_ctl.thr_pid < 0) {
8612 WL_ERROR(("Failed in %s\n", __FUNCTION__));
8613 return -ENOMEM;
8614 }
8615
8616 return 0;
8617}
8618#endif
8619
8620int
8621wl_iw_attach(struct net_device *dev, void * dhdp)
8622{
8623#if defined(WL_IW_USE_ISCAN)
8624 int params_size = 0;
8625#endif
8626 wl_iw_t *iw;
8627#if defined(WL_IW_USE_ISCAN)
8628 iscan_info_t *iscan = NULL;
8629#endif
8630
8631 DHD_OS_MUTEX_INIT(&wl_cache_lock);
8632 DHD_OS_MUTEX_INIT(&wl_softap_lock);
8633
8634#if defined(WL_IW_USE_ISCAN)
8635 if (!dev)
8636 return 0;
8637
8638
8639 memset(&g_wl_iw_params, 0, sizeof(wl_iw_extra_params_t));
8640
8641
8642#ifdef CSCAN
8643 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) +
8644 (WL_NUMCHANNELS * sizeof(uint16)) + WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
8645#else
8646 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params));
8647#endif
8648 iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL);
8649 if (!iscan)
8650 return -ENOMEM;
8651 memset(iscan, 0, sizeof(iscan_info_t));
8652
8653
8654 iscan->iscan_ex_params_p = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL);
8655 if (!iscan->iscan_ex_params_p) {
8656 kfree(iscan);
8657 return -ENOMEM;
8658 }
8659 iscan->iscan_ex_param_size = params_size;
8660
8661
8662 g_iscan = iscan;
8663 iscan->dev = dev;
8664 iscan->iscan_state = ISCAN_STATE_IDLE;
8665
8666#if defined(CONFIG_FIRST_SCAN)
8667 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
8668 g_first_counter_scans = 0;
8669 g_iscan->scan_flag = 0;
8670#endif
8671
8672#ifdef CONFIG_WPS2
8673 g_wps_probe_req_ie = NULL;
8674 g_wps_probe_req_ie_len = 0;
8675#endif
8676
8677 iscan->timer_ms = 8000;
8678 init_timer(&iscan->timer);
8679 iscan->timer.data = (ulong)iscan;
8680 iscan->timer.function = wl_iw_timerfunc;
8681
8682 PROC_START(_iscan_sysioc_thread, iscan, &iscan->tsk_ctl, 0);
8683 if (iscan->tsk_ctl.thr_pid < 0)
8684 return -ENOMEM;
8685#endif
8686
8687 iw = *(wl_iw_t **)netdev_priv(dev);
8688 iw->pub = (dhd_pub_t *)dhdp;
8689#ifdef SOFTAP
8690 priv_dev = dev;
8691#endif
8692 g_scan = NULL;
8693
8694
8695 g_scan = (void *)kmalloc(G_SCAN_RESULTS, GFP_KERNEL);
8696 if (!g_scan)
8697 return -ENOMEM;
8698
8699 memset(g_scan, 0, G_SCAN_RESULTS);
8700 g_scan_specified_ssid = 0;
8701
8702#if !defined(CSCAN)
8703
8704 wl_iw_init_ss_cache_ctrl();
8705#endif
8706#ifdef COEX_DHCP
8707
8708 wl_iw_bt_init(dev);
8709#endif
8710
8711
8712 return 0;
8713}
8714
8715void
8716wl_iw_detach(void)
8717{
8718#if defined(WL_IW_USE_ISCAN)
8719 iscan_buf_t *buf;
8720 iscan_info_t *iscan = g_iscan;
8721
8722 if (!iscan)
8723 return;
8724 if (iscan->tsk_ctl.thr_pid >= 0) {
8725 PROC_STOP(&iscan->tsk_ctl);
8726 }
8727 DHD_OS_MUTEX_LOCK(&wl_cache_lock);
8728 while (iscan->list_hdr) {
8729 buf = iscan->list_hdr->next;
8730 kfree(iscan->list_hdr);
8731 iscan->list_hdr = buf;
8732 }
8733 kfree(iscan->iscan_ex_params_p);
8734 kfree(iscan);
8735 g_iscan = NULL;
8736 DHD_OS_MUTEX_UNLOCK(&wl_cache_lock);
8737#endif
8738
8739 if (g_scan)
8740 kfree(g_scan);
8741
8742 g_scan = NULL;
8743#ifdef CONFIG_WPS2
8744
8745 if (g_wps_probe_req_ie) {
8746 kfree(g_wps_probe_req_ie);
8747 g_wps_probe_req_ie = NULL;
8748 g_wps_probe_req_ie_len = 0;
8749 }
8750#endif
8751#if !defined(CSCAN)
8752 wl_iw_release_ss_cache_ctrl();
8753#endif
8754#ifdef COEX_DHCP
8755 wl_iw_bt_release();
8756#endif
8757
8758#ifdef SOFTAP
8759 if (ap_cfg_running) {
8760 WL_TRACE(("\n%s AP is going down\n", __FUNCTION__));
8761
8762 wl_iw_send_priv_event(priv_dev, "AP_DOWN");
8763 }
8764#endif
8765
8766}
diff --git a/drivers/net/wireless/bcmdhd/wl_iw.h b/drivers/net/wireless/bcmdhd/wl_iw.h
new file mode 100644
index 00000000000..c0cc14bdde4
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wl_iw.h
@@ -0,0 +1,306 @@
1/*
2 * Linux Wireless Extensions support
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wl_iw.h,v 1.15.80.6 2010-12-23 01:13:23 Exp $
25 */
26
27
28#ifndef _wl_iw_h_
29#define _wl_iw_h_
30
31#include <linux/wireless.h>
32
33#include <typedefs.h>
34#include <proto/ethernet.h>
35#include <wlioctl.h>
36
37#define WL_SCAN_PARAMS_SSID_MAX 10
38#define GET_SSID "SSID="
39#define GET_CHANNEL "CH="
40#define GET_NPROBE "NPROBE="
41#define GET_ACTIVE_ASSOC_DWELL "ACTIVE="
42#define GET_PASSIVE_ASSOC_DWELL "PASSIVE="
43#define GET_HOME_DWELL "HOME="
44#define GET_SCAN_TYPE "TYPE="
45
46#define BAND_GET_CMD "GETBAND"
47#define BAND_SET_CMD "SETBAND"
48#define DTIM_SKIP_GET_CMD "DTIMSKIPGET"
49#define DTIM_SKIP_SET_CMD "DTIMSKIPSET"
50#define SETSUSPEND_CMD "SETSUSPENDOPT"
51#define PNOSSIDCLR_SET_CMD "PNOSSIDCLR"
52
53#define PNOSETUP_SET_CMD "PNOSETUP "
54#define PNOENABLE_SET_CMD "PNOFORCE"
55#define PNODEBUG_SET_CMD "PNODEBUG"
56#define TXPOWER_SET_CMD "TXPOWER"
57
58#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
59#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
60
61
62typedef struct wl_iw_extra_params {
63 int target_channel;
64} wl_iw_extra_params_t;
65
66struct cntry_locales_custom {
67 char iso_abbrev[WLC_CNTRY_BUF_SZ];
68 char custom_locale[WLC_CNTRY_BUF_SZ];
69 int32 custom_locale_rev;
70};
71
72
73#define WL_IW_RSSI_MINVAL -200
74#define WL_IW_RSSI_NO_SIGNAL -91
75#define WL_IW_RSSI_VERY_LOW -80
76#define WL_IW_RSSI_LOW -70
77#define WL_IW_RSSI_GOOD -68
78#define WL_IW_RSSI_VERY_GOOD -58
79#define WL_IW_RSSI_EXCELLENT -57
80#define WL_IW_RSSI_INVALID 0
81#define MAX_WX_STRING 80
82#define isprint(c) bcm_isprint(c)
83#define WL_IW_SET_ACTIVE_SCAN (SIOCIWFIRSTPRIV+1)
84#define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3)
85#define WL_IW_SET_PASSIVE_SCAN (SIOCIWFIRSTPRIV+5)
86#define WL_IW_GET_LINK_SPEED (SIOCIWFIRSTPRIV+7)
87#define WL_IW_GET_CURR_MACADDR (SIOCIWFIRSTPRIV+9)
88#define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11)
89#define WL_IW_SET_START (SIOCIWFIRSTPRIV+13)
90
91
92#define WL_SET_AP_CFG (SIOCIWFIRSTPRIV+15)
93#define WL_AP_STA_LIST (SIOCIWFIRSTPRIV+17)
94#define WL_AP_MAC_FLTR (SIOCIWFIRSTPRIV+19)
95#define WL_AP_BSS_START (SIOCIWFIRSTPRIV+21)
96#define AP_LPB_CMD (SIOCIWFIRSTPRIV+23)
97#define WL_AP_STOP (SIOCIWFIRSTPRIV+25)
98#define WL_FW_RELOAD (SIOCIWFIRSTPRIV+27)
99#define WL_AP_STA_DISASSOC (SIOCIWFIRSTPRIV+29)
100#define WL_COMBO_SCAN (SIOCIWFIRSTPRIV+31)
101
102
103#define G_SCAN_RESULTS 8*1024
104#define WE_ADD_EVENT_FIX 0x80
105#define G_WLAN_SET_ON 0
106#define G_WLAN_SET_OFF 1
107
108#define CHECK_EXTRA_FOR_NULL(extra) \
109if (!extra) { \
110 WL_ERROR(("%s: error : extra is null pointer\n", __FUNCTION__)); \
111 return -EINVAL; \
112}
113
114typedef struct wl_iw {
115 char nickname[IW_ESSID_MAX_SIZE];
116
117 struct iw_statistics wstats;
118
119 int spy_num;
120 int wpaversion;
121 int pcipher;
122 int gcipher;
123 int privacy_invoked;
124
125 struct ether_addr spy_addr[IW_MAX_SPY];
126 struct iw_quality spy_qual[IW_MAX_SPY];
127 void *wlinfo;
128 dhd_pub_t * pub;
129} wl_iw_t;
130
131int wl_control_wl_start(struct net_device *dev);
132#define WLC_IW_SS_CACHE_MAXLEN 2048
133#define WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN 32
134#define WLC_IW_BSS_INFO_MAXLEN \
135 (WLC_IW_SS_CACHE_MAXLEN - WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN)
136
137typedef struct wl_iw_ss_cache {
138 struct wl_iw_ss_cache *next;
139 int dirty;
140 uint32 buflen;
141 uint32 version;
142 uint32 count;
143 wl_bss_info_t bss_info[1];
144} wl_iw_ss_cache_t;
145
146typedef struct wl_iw_ss_cache_ctrl {
147 wl_iw_ss_cache_t *m_cache_head;
148 int m_link_down;
149 int m_timer_expired;
150 char m_active_bssid[ETHER_ADDR_LEN];
151 uint m_prev_scan_mode;
152 uint m_cons_br_scan_cnt;
153 struct timer_list *m_timer;
154} wl_iw_ss_cache_ctrl_t;
155
156typedef enum broadcast_first_scan {
157 BROADCAST_SCAN_FIRST_IDLE = 0,
158 BROADCAST_SCAN_FIRST_STARTED,
159 BROADCAST_SCAN_FIRST_RESULT_READY,
160 BROADCAST_SCAN_FIRST_RESULT_CONSUMED
161} broadcast_first_scan_t;
162#ifdef SOFTAP
163#define SSID_LEN 33
164#define SEC_LEN 16
165#define KEY_LEN 65
166#define PROFILE_OFFSET 32
167struct ap_profile {
168 uint8 ssid[SSID_LEN];
169 uint8 sec[SEC_LEN];
170 uint8 key[KEY_LEN];
171 uint32 channel;
172 uint32 preamble;
173 uint32 max_scb;
174 uint32 closednet;
175 char country_code[WLC_CNTRY_BUF_SZ];
176};
177
178
179#define MACLIST_MODE_DISABLED 0
180#define MACLIST_MODE_DENY 1
181#define MACLIST_MODE_ALLOW 2
182struct mflist {
183 uint count;
184 struct ether_addr ea[16];
185};
186struct mac_list_set {
187 uint32 mode;
188 struct mflist mac_list;
189};
190#endif
191
192#if WIRELESS_EXT > 12
193#include <net/iw_handler.h>
194extern const struct iw_handler_def wl_iw_handler_def;
195#endif
196
197extern int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
198extern void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data);
199extern int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats);
200int wl_iw_attach(struct net_device *dev, void * dhdp);
201void wl_iw_detach(void);
202
203extern int net_os_wake_lock(struct net_device *dev);
204extern int net_os_wake_unlock(struct net_device *dev);
205extern int net_os_wake_lock_timeout(struct net_device *dev);
206extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val);
207extern int net_os_set_suspend_disable(struct net_device *dev, int val);
208extern int net_os_set_suspend(struct net_device *dev, int val);
209extern int net_os_set_dtim_skip(struct net_device *dev, int val);
210extern int net_os_send_hang_message(struct net_device *dev);
211extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec);
212
213#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
214#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \
215 iwe_stream_add_event(info, stream, ends, iwe, extra)
216#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \
217 iwe_stream_add_value(info, event, value, ends, iwe, event_len)
218#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \
219 iwe_stream_add_point(info, stream, ends, iwe, extra)
220#else
221#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \
222 iwe_stream_add_event(stream, ends, iwe, extra)
223#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \
224 iwe_stream_add_value(event, value, ends, iwe, event_len)
225#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \
226 iwe_stream_add_point(stream, ends, iwe, extra)
227#endif
228
229void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec);
230
231#define PNO_TLV_PREFIX 'S'
232#define PNO_TLV_VERSION '1'
233#define PNO_TLV_SUBVERSION '2'
234#define PNO_TLV_RESERVED '0'
235#define PNO_TLV_TYPE_SSID_IE 'S'
236#define PNO_TLV_TYPE_TIME 'T'
237#define PNO_TLV_FREQ_REPEAT 'R'
238#define PNO_TLV_FREQ_EXPO_MAX 'M'
239#define PNO_EVENT_UP "PNO_EVENT"
240
241typedef struct cmd_tlv {
242 char prefix;
243 char version;
244 char subver;
245 char reserved;
246} cmd_tlv_t;
247
248
249
250
251typedef struct cscan_tlv {
252 char prefix;
253 char version;
254 char subver;
255 char reserved;
256} cscan_tlv_t;
257
258#define CSCAN_COMMAND "CSCAN "
259#define CSCAN_TLV_PREFIX 'S'
260#define CSCAN_TLV_VERSION 1
261#define CSCAN_TLV_SUBVERSION 0
262#define CSCAN_TLV_TYPE_SSID_IE 'S'
263#define CSCAN_TLV_TYPE_CHANNEL_IE 'C'
264#define CSCAN_TLV_TYPE_NPROBE_IE 'N'
265#define CSCAN_TLV_TYPE_ACTIVE_IE 'A'
266#define CSCAN_TLV_TYPE_PASSIVE_IE 'P'
267#define CSCAN_TLV_TYPE_HOME_IE 'H'
268#define CSCAN_TLV_TYPE_STYPE_IE 'T'
269
270#ifdef SOFTAP_TLV_CFG
271
272#define SOFTAP_SET_CMD "SOFTAPSET "
273#define SOFTAP_TLV_PREFIX 'A'
274#define SOFTAP_TLV_VERSION '1'
275#define SOFTAP_TLV_SUBVERSION '0'
276#define SOFTAP_TLV_RESERVED '0'
277
278#define TLV_TYPE_SSID 'S'
279#define TLV_TYPE_SECUR 'E'
280#define TLV_TYPE_KEY 'K'
281#define TLV_TYPE_CHANNEL 'C'
282#endif
283
284extern int wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list,
285 int channel_num, int *bytes_left);
286
287extern int wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size,
288 const char token, int input_size, int *bytes_left);
289
290extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid,
291 int max, int *bytes_left);
292
293extern int wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max);
294
295extern int wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num);
296
297
298#define NETDEV_PRIV(dev) (*(wl_iw_t **)netdev_priv(dev))
299
300#ifdef CONFIG_WPS2
301#define WPS_ADD_PROBE_REQ_IE_CMD "ADD_WPS_PROBE_REQ_IE "
302#define WPS_DEL_PROBE_REQ_IE_CMD "DEL_WPS_PROBE_REQ_IE "
303#define WPS_PROBE_REQ_IE_CMD_LENGTH 21
304#endif
305
306#endif
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c
new file mode 100644
index 00000000000..bb3eaea90d0
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wldev_common.c
@@ -0,0 +1,341 @@
1/*
2 * Common function shared by Linux WEXT, cfg80211 and p2p drivers
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $
25 */
26
27#include <linux/module.h>
28#include <linux/netdevice.h>
29
30#include <wldev_common.h>
31#include <bcmutils.h>
32#include <dhd_dbg.h>
33
34#define htod32(i) i
35#define htod16(i) i
36#define dtoh32(i) i
37#define dtoh16(i) i
38#define htodchanspec(i) i
39#define dtohchanspec(i) i
40extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd);
41
42s32 wldev_ioctl(
43 struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set)
44{
45 s32 ret = 0;
46 struct wl_ioctl ioc;
47
48 memset(&ioc, 0, sizeof(ioc));
49 ioc.cmd = cmd;
50 ioc.buf = arg;
51 ioc.len = len;
52 ioc.set = set;
53
54 ret = dhd_ioctl_entry_local(dev, &ioc, cmd);
55 return ret;
56}
57
58/* Format a iovar buffer, not bsscfg indexed. The bsscfg index will be
59 * taken care of in dhd_ioctl_entry. Internal use only, not exposed to
60 * wl_iw, wl_cfg80211 and wl_cfgp2p
61 */
62static s32 wldev_mkiovar(
63 s8 *iovar_name, s8 *param, s32 paramlen,
64 s8 *iovar_buf, u32 buflen)
65{
66 s32 iolen = 0;
67
68 iolen = bcm_mkiovar(iovar_name, param, paramlen, iovar_buf, buflen);
69 return iolen;
70}
71
72s32 wldev_iovar_getbuf(
73 struct net_device *dev, s8 *iovar_name,
74 void *param, s32 paramlen, void *buf, s32 buflen)
75{
76 s32 ret = 0;
77 s32 iovar_len = 0;
78
79 iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
80 ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
81 return ret;
82}
83
84
85s32 wldev_iovar_setbuf(
86 struct net_device *dev, s8 *iovar_name,
87 void *param, s32 paramlen, void *buf, s32 buflen)
88{
89 s32 ret = 0;
90 s32 iovar_len;
91
92 iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen);
93 ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
94 return ret;
95}
96
97s32 wldev_iovar_setint(
98 struct net_device *dev, s8 *iovar, s32 val)
99{
100 s8 iovar_buf[WLC_IOCTL_SMLEN];
101
102 val = htod32(val);
103 memset(iovar_buf, 0, sizeof(iovar_buf));
104 return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf,
105 sizeof(iovar_buf));
106}
107
108
109s32 wldev_iovar_getint(
110 struct net_device *dev, s8 *iovar, s32 *pval)
111{
112 s8 iovar_buf[WLC_IOCTL_SMLEN];
113 s32 err;
114
115 memset(iovar_buf, 0, sizeof(iovar_buf));
116 err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf,
117 sizeof(iovar_buf));
118 if (err == 0)
119 {
120 memcpy(pval, iovar_buf, sizeof(*pval));
121 *pval = dtoh32(*pval);
122 }
123 return err;
124}
125
126/** Format a bsscfg indexed iovar buffer. The bsscfg index will be
127 * taken care of in dhd_ioctl_entry. Internal use only, not exposed to
128 * wl_iw, wl_cfg80211 and wl_cfgp2p
129 */
130s32 wldev_mkiovar_bsscfg(
131 const s8 *iovar_name, s8 *param, s32 paramlen,
132 s8 *iovar_buf, s32 buflen, s32 bssidx)
133{
134 const s8 *prefix = "bsscfg:";
135 s8 *p;
136 u32 prefixlen;
137 u32 namelen;
138 u32 iolen;
139
140 if (bssidx == 0) {
141 return wldev_mkiovar((s8*)iovar_name, (s8 *)param, paramlen,
142 (s8 *) iovar_buf, buflen);
143 }
144
145 prefixlen = (u32) strlen(prefix); /* lengh of bsscfg prefix */
146 namelen = (u32) strlen(iovar_name) + 1; /* lengh of iovar name + null */
147 iolen = prefixlen + namelen + sizeof(u32) + paramlen;
148
149 if (buflen < 0 || iolen > (u32)buflen)
150 {
151 DHD_ERROR(("%s: buffer is too short\n", __FUNCTION__));
152 return BCME_BUFTOOSHORT;
153 }
154
155 p = (s8 *)iovar_buf;
156
157 /* copy prefix, no null */
158 memcpy(p, prefix, prefixlen);
159 p += prefixlen;
160
161 /* copy iovar name including null */
162 memcpy(p, iovar_name, namelen);
163 p += namelen;
164
165 /* bss config index as first param */
166 bssidx = htod32(bssidx);
167 memcpy(p, &bssidx, sizeof(u32));
168 p += sizeof(u32);
169
170 /* parameter buffer follows */
171 if (paramlen)
172 memcpy(p, param, paramlen);
173
174 return iolen;
175
176}
177
178s32 wldev_iovar_getbuf_bsscfg(
179 struct net_device *dev, s8 *iovar_name,
180 void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx)
181{
182 s32 ret = 0;
183 s32 iovar_len = 0;
184
185 iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
186 ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE);
187 return ret;
188
189}
190
191s32 wldev_iovar_setbuf_bsscfg(
192 struct net_device *dev, s8 *iovar_name,
193 void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx)
194{
195 s32 ret = 0;
196 s32 iovar_len;
197
198 iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx);
199 ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE);
200 return ret;
201}
202
203s32 wldev_iovar_setint_bsscfg(
204 struct net_device *dev, s8 *iovar, s32 val, s32 bssidx)
205{
206 s8 iovar_buf[WLC_IOCTL_SMLEN];
207
208 val = htod32(val);
209 memset(iovar_buf, 0, sizeof(iovar_buf));
210 return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf,
211 sizeof(iovar_buf), bssidx);
212}
213
214
215s32 wldev_iovar_getint_bsscfg(
216 struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx)
217{
218 s8 iovar_buf[WLC_IOCTL_SMLEN];
219 s32 err;
220
221 memset(iovar_buf, 0, sizeof(iovar_buf));
222 err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf,
223 sizeof(iovar_buf), bssidx);
224 if (err == 0)
225 {
226 memcpy(pval, iovar_buf, sizeof(*pval));
227 *pval = dtoh32(*pval);
228 }
229 return err;
230}
231
232int wldev_get_link_speed(
233 struct net_device *dev, int *plink_speed)
234{
235 int error;
236
237 if (!plink_speed)
238 return -ENOMEM;
239 error = wldev_ioctl(dev, WLC_GET_RATE, plink_speed, sizeof(int), 0);
240 if (unlikely(error))
241 return error;
242
243 /* Convert internal 500Kbps to Kbps */
244 *plink_speed *= 500;
245 return error;
246}
247
248int wldev_get_rssi(
249 struct net_device *dev, int *prssi)
250{
251 scb_val_t scb_val;
252 int error;
253
254 if (!prssi)
255 return -ENOMEM;
256 bzero(&scb_val, sizeof(scb_val_t));
257
258 error = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t), 0);
259 if (unlikely(error))
260 return error;
261
262 *prssi = dtoh32(scb_val.val);
263 return error;
264}
265
266int wldev_get_ssid(
267 struct net_device *dev, wlc_ssid_t *pssid)
268{
269 int error;
270
271 if (!pssid)
272 return -ENOMEM;
273 error = wldev_ioctl(dev, WLC_GET_SSID, pssid, sizeof(wlc_ssid_t), 0);
274 if (unlikely(error))
275 return error;
276 pssid->SSID_len = dtoh32(pssid->SSID_len);
277 return error;
278}
279
280int wldev_get_band(
281 struct net_device *dev, uint *pband)
282{
283 int error;
284
285 error = wldev_ioctl(dev, WLC_GET_BAND, pband, sizeof(uint), 0);
286 return error;
287}
288
289int wldev_set_band(
290 struct net_device *dev, uint band)
291{
292 int error = -1;
293
294 if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) {
295 error = wldev_ioctl(dev, WLC_SET_BAND, &band, sizeof(band), 1);
296 }
297 return error;
298}
299
300int wldev_set_country(
301 struct net_device *dev, char *country_code)
302{
303 int error = -1;
304 wl_country_t cspec = {{0}, 0, {0}};
305 scb_val_t scbval;
306 char smbuf[WLC_IOCTL_SMLEN];
307
308 if (!country_code)
309 return error;
310
311 error = wldev_iovar_getbuf(dev, "country", &cspec, sizeof(cspec),
312 smbuf, sizeof(smbuf));
313 if (error < 0)
314 DHD_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error));
315
316 if ((error < 0) ||
317 (strncmp(country_code, smbuf, WLC_CNTRY_BUF_SZ) != 0)) {
318 bzero(&scbval, sizeof(scb_val_t));
319 error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), 1);
320 if (error < 0) {
321 DHD_ERROR(("%s: set country failed due to Disassoc error %d\n",
322 __FUNCTION__, error));
323 return error;
324 }
325 }
326 cspec.rev = -1;
327 memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
328 memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
329 get_customized_country_code((char *)&cspec.country_abbrev, &cspec);
330 error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec),
331 smbuf, sizeof(smbuf));
332 if (error < 0) {
333 DHD_ERROR(("%s: set country for %s as %s rev %d failed\n",
334 __FUNCTION__, country_code, cspec.ccode, cspec.rev));
335 return error;
336 }
337 dhd_bus_country_set(dev, &cspec);
338 DHD_INFO(("%s: set country for %s as %s rev %d\n",
339 __FUNCTION__, country_code, cspec.ccode, cspec.rev));
340 return 0;
341}
diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h
new file mode 100644
index 00000000000..46326803e21
--- /dev/null
+++ b/drivers/net/wireless/bcmdhd/wldev_common.h
@@ -0,0 +1,110 @@
1/*
2 * Common function shared by Linux WEXT, cfg80211 and p2p drivers
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $
25 */
26#ifndef __WLDEV_COMMON_H__
27#define __WLDEV_COMMON_H__
28
29#include <wlioctl.h>
30
31/** wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or
32 * netdev_ops->ndo_do_ioctl in new kernels)
33 * @dev: the net_device handle
34 */
35s32 wldev_ioctl(
36 struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set);
37
38/** Retrieve named IOVARs, this function calls wl_dev_ioctl with
39 * WLC_GET_VAR IOCTL code
40 */
41s32 wldev_iovar_getbuf(
42 struct net_device *dev, s8 *iovar_name,
43 void *param, s32 paramlen, void *buf, s32 buflen);
44
45/** Set named IOVARs, this function calls wl_dev_ioctl with
46 * WLC_SET_VAR IOCTL code
47 */
48s32 wldev_iovar_setbuf(
49 struct net_device *dev, s8 *iovar_name,
50 void *param, s32 paramlen, void *buf, s32 buflen);
51
52s32 wldev_iovar_setint(
53 struct net_device *dev, s8 *iovar, s32 val);
54
55s32 wldev_iovar_getint(
56 struct net_device *dev, s8 *iovar, s32 *pval);
57
58/** The following function can be implemented if there is a need for bsscfg
59 * indexed IOVARs
60 */
61
62s32 wldev_mkiovar_bsscfg(
63 const s8 *iovar_name, s8 *param, s32 paramlen,
64 s8 *iovar_buf, s32 buflen, s32 bssidx);
65
66/** Retrieve named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with
67 * WLC_GET_VAR IOCTL code
68 */
69s32 wldev_iovar_getbuf_bsscfg(
70 struct net_device *dev, s8 *iovar_name,
71 void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx);
72
73/** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with
74 * WLC_SET_VAR IOCTL code
75 */
76s32 wldev_iovar_setbuf_bsscfg(
77 struct net_device *dev, s8 *iovar_name,
78 void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx);
79
80s32 wldev_iovar_getint_bsscfg(
81 struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx);
82
83s32 wldev_iovar_setint_bsscfg(
84 struct net_device *dev, s8 *iovar, s32 val, s32 bssidx);
85
86extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec);
87extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec);
88extern int wldev_set_country(struct net_device *dev, char *country_code);
89extern int net_os_wake_lock(struct net_device *dev);
90extern int net_os_wake_unlock(struct net_device *dev);
91extern int net_os_wake_lock_timeout(struct net_device *dev);
92extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val);
93extern int net_os_set_dtim_skip(struct net_device *dev, int val);
94extern int net_os_set_suspend_disable(struct net_device *dev, int val);
95extern int net_os_set_suspend(struct net_device *dev, int val);
96extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid,
97 int max, int *bytes_left);
98
99/* Get the link speed from dongle, speed is in kpbs */
100int wldev_get_link_speed(struct net_device *dev, int *plink_speed);
101
102int wldev_get_rssi(struct net_device *dev, int *prssi);
103
104int wldev_get_ssid(struct net_device *dev, wlc_ssid_t *pssid);
105
106int wldev_get_band(struct net_device *dev, uint *pband);
107
108int wldev_set_band(struct net_device *dev, uint band);
109
110#endif /* __WLDEV_COMMON_H__ */