aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcm4329
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/bcm4329
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/net/wireless/bcm4329')
-rw-r--r--drivers/net/wireless/bcm4329/Kconfig82
-rw-r--r--drivers/net/wireless/bcm4329/Makefile56
-rw-r--r--drivers/net/wireless/bcm4329/aiutils.c686
-rw-r--r--drivers/net/wireless/bcm4329/bcmpcispi.c630
-rw-r--r--drivers/net/wireless/bcm4329/bcmsdh.c652
-rw-r--r--drivers/net/wireless/bcm4329/bcmsdh_linux.c735
-rw-r--r--drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c1304
-rw-r--r--drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c316
-rw-r--r--drivers/net/wireless/bcm4329/bcmsdspi.c1596
-rw-r--r--drivers/net/wireless/bcm4329/bcmsdspi_linux.c252
-rw-r--r--drivers/net/wireless/bcm4329/bcmsdstd.c3127
-rw-r--r--drivers/net/wireless/bcm4329/bcmsdstd_linux.c251
-rw-r--r--drivers/net/wireless/bcm4329/bcmutils.c1838
-rw-r--r--drivers/net/wireless/bcm4329/bcmwifi.c199
-rw-r--r--drivers/net/wireless/bcm4329/dhd.h472
-rw-r--r--drivers/net/wireless/bcm4329/dhd_bus.h93
-rw-r--r--drivers/net/wireless/bcm4329/dhd_cdc.c535
-rw-r--r--drivers/net/wireless/bcm4329/dhd_common.c2432
-rw-r--r--drivers/net/wireless/bcm4329/dhd_custom_gpio.c272
-rw-r--r--drivers/net/wireless/bcm4329/dhd_dbg.h100
-rw-r--r--drivers/net/wireless/bcm4329/dhd_linux.c3451
-rw-r--r--drivers/net/wireless/bcm4329/dhd_linux_sched.c38
-rw-r--r--drivers/net/wireless/bcm4329/dhd_proto.h102
-rw-r--r--drivers/net/wireless/bcm4329/dhd_sdio.c5841
-rw-r--r--drivers/net/wireless/bcm4329/dngl_stats.h43
-rw-r--r--drivers/net/wireless/bcm4329/hndpmu.c131
-rw-r--r--drivers/net/wireless/bcm4329/include/Makefile21
-rw-r--r--drivers/net/wireless/bcm4329/include/aidmp.h368
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmcdc.h100
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmdefs.h114
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmdevs.h124
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmendian.h205
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmpcispi.h205
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmperf.h36
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmsdbus.h117
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmsdh.h208
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmsdh_sdmmc.h122
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmsdpcm.h263
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmsdspi.h131
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmsdstd.h223
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmspi.h36
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmspibrcm.h134
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmutils.h637
-rw-r--r--drivers/net/wireless/bcm4329/include/bcmwifi.h154
-rw-r--r--drivers/net/wireless/bcm4329/include/dhdioctl.h123
-rw-r--r--drivers/net/wireless/bcm4329/include/epivers.h48
-rw-r--r--drivers/net/wireless/bcm4329/include/hndpmu.h34
-rw-r--r--drivers/net/wireless/bcm4329/include/hndrte_armtrap.h88
-rw-r--r--drivers/net/wireless/bcm4329/include/hndrte_cons.h63
-rw-r--r--drivers/net/wireless/bcm4329/include/hndsoc.h195
-rw-r--r--drivers/net/wireless/bcm4329/include/linux_osl.h322
-rw-r--r--drivers/net/wireless/bcm4329/include/linuxver.h447
-rw-r--r--drivers/net/wireless/bcm4329/include/miniopt.h77
-rw-r--r--drivers/net/wireless/bcm4329/include/msgtrace.h72
-rw-r--r--drivers/net/wireless/bcm4329/include/osl.h55
-rw-r--r--drivers/net/wireless/bcm4329/include/packed_section_end.h54
-rw-r--r--drivers/net/wireless/bcm4329/include/packed_section_start.h61
-rw-r--r--drivers/net/wireless/bcm4329/include/pcicfg.h52
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/802.11.h1433
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/802.11e.h131
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/802.1d.h49
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/bcmeth.h83
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/bcmevent.h212
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/bcmip.h157
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/eapol.h172
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/ethernet.h148
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/sdspi.h71
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/vlan.h63
-rw-r--r--drivers/net/wireless/bcm4329/include/proto/wpa.h159
-rw-r--r--drivers/net/wireless/bcm4329/include/sbchipc.h1026
-rw-r--r--drivers/net/wireless/bcm4329/include/sbconfig.h276
-rw-r--r--drivers/net/wireless/bcm4329/include/sbhnddma.h294
-rw-r--r--drivers/net/wireless/bcm4329/include/sbpcmcia.h109
-rw-r--r--drivers/net/wireless/bcm4329/include/sbsdio.h166
-rw-r--r--drivers/net/wireless/bcm4329/include/sbsdpcmdev.h288
-rw-r--r--drivers/net/wireless/bcm4329/include/sbsocram.h150
-rw-r--r--drivers/net/wireless/bcm4329/include/sdio.h566
-rw-r--r--drivers/net/wireless/bcm4329/include/sdioh.h299
-rw-r--r--drivers/net/wireless/bcm4329/include/sdiovar.h58
-rw-r--r--drivers/net/wireless/bcm4329/include/siutils.h235
-rw-r--r--drivers/net/wireless/bcm4329/include/spid.h153
-rw-r--r--drivers/net/wireless/bcm4329/include/trxhdr.h46
-rw-r--r--drivers/net/wireless/bcm4329/include/typedefs.h303
-rw-r--r--drivers/net/wireless/bcm4329/include/wlioctl.h1673
-rw-r--r--drivers/net/wireless/bcm4329/linux_osl.c625
-rw-r--r--drivers/net/wireless/bcm4329/miniopt.c163
-rw-r--r--drivers/net/wireless/bcm4329/sbutils.c1004
-rw-r--r--drivers/net/wireless/bcm4329/siutils.c1527
-rw-r--r--drivers/net/wireless/bcm4329/siutils_priv.h213
-rw-r--r--drivers/net/wireless/bcm4329/wl_iw.c8455
-rw-r--r--drivers/net/wireless/bcm4329/wl_iw.h309
91 files changed, 50739 insertions, 0 deletions
diff --git a/drivers/net/wireless/bcm4329/Kconfig b/drivers/net/wireless/bcm4329/Kconfig
new file mode 100644
index 00000000000..a04ba4c4d4c
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/Kconfig
@@ -0,0 +1,82 @@
1config BCM4329
2 tristate "Broadcom 4329 wireless cards support"
3 depends on MMC
4 select WIRELESS_EXT
5 select WEXT_PRIV
6 ---help---
7 This module adds support for wireless adapters based on
8 Broadcom 4329 chipset.
9
10 This driver uses the kernel's wireless extensions subsystem.
11
12 If you choose to build a module, it'll be called dhd. Say M if
13 unsure.
14
15config BCM4329_FIRST_SCAN
16 depends on BCM4329
17 bool "first scan support"
18 default n
19 ---help---
20 Initiate broadcast scan (active scan) just after
21 initializing with network interface.
22
23config BCM4329_FW_PATH
24 depends on BCM4329
25 string "Firmware path"
26 default "/system/etc/firmware/fw_bcm4329.bin"
27 ---help---
28 Path to the firmware file.
29
30config BCM4329_NVRAM_PATH
31 depends on BCM4329
32 string "NVRAM path"
33 default "/proc/calibration"
34 ---help---
35 Path to the calibration file.
36
37config BCM4329_WIFI_CONTROL_FUNC
38 bool "Use bcm4329_wlan device"
39 depends on BCM4329
40 default n
41 ---help---
42 Use this option to get various parameters from architecture specific
43 bcm4329_wlan platform device. Say n if unsure.
44
45if BCM4329_WIFI_CONTROL_FUNC
46
47config BCM4329_DHD_USE_STATIC_BUF
48 bool "Use static buffer"
49 depends on BCM4329
50 default n
51 ---help---
52 Use static buffer from kernel heap allocated during bcm4329_wlan
53 platform device creation.
54
55config BCM4329_HW_OOB
56 bool "Use out of band interrupt"
57 depends on BCM4329
58 default n
59 ---help---
60 Use out of band interrupt for wake on wireless.
61
62config BCM4329_OOB_INTR_ONLY
63 bool "Use out of band interrupt only"
64 depends on BCM4329
65 default n
66 ---help---
67 Use out of band interrupt for all interrupts(including SDIO interrupts).
68
69config BCM4329_GET_CUSTOM_MAC_ENABLE
70 bool "Use custom mac address"
71 depends on BCM4329
72 default n
73 ---help---
74 Use mac address provided by bcm4329_wlan platform device.
75
76config BCM4329_CSCAN_ENABLE
77 bool "Enable Combo Scan"
78 depends on BCM4329
79 default n
80 ---help---
81 Enable Combo Scan
82endif
diff --git a/drivers/net/wireless/bcm4329/Makefile b/drivers/net/wireless/bcm4329/Makefile
new file mode 100644
index 00000000000..60297ece490
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/Makefile
@@ -0,0 +1,56 @@
1# bcm4329
2DHDCFLAGS = -DLINUX -DBCMDRIVER -DBCMDONGLEHOST -DDHDTHREAD -DBCMWPA2 \
3 -DUNRELEASEDCHIP -Dlinux -DDHD_SDALIGN=64 -DMAX_HDR_READ=64 \
4 -DDHD_FIRSTREAD=64 -DDHD_GPL -DDHD_SCHED -DBDC -DTOE -DDHD_BCMEVENTS \
5 -DSHOW_EVENTS -DBCMSDIO -DDHD_GPL -DBCMLXSDMMC -DBCMPLATFORM_BUS \
6 -Wall -Wstrict-prototypes -Werror -DCUSTOMER_HW2 -DMMC_SDIO_ABORT \
7 -DDHD_DEBUG_TRAP -DSOFTAP -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT \
8 -DPKT_FILTER_SUPPORT -DSET_RANDOM_MAC_SOFTAP \
9 -DKEEP_ALIVE \
10 -Idrivers/net/wireless/bcm4329 -Idrivers/net/wireless/bcm4329/include
11
12ifeq ($(CONFIG_BCM4329_WIFI_CONTROL_FUNC),y)
13DHDCFLAGS += -DCONFIG_WIFI_CONTROL_FUNC
14endif
15
16ifeq ($(CONFIG_BCM4329_FIRST_SCAN),y)
17DHDCFLAGS += -DCONFIG_FIRST_SCAN
18endif
19
20ifeq ($(CONFIG_BCM4329_DHD_USE_STATIC_BUF),y)
21DHDCFLAGS += -DDHD_USE_STATIC_BUF
22endif
23ifeq ($(CONFIG_BCM4329_OOB_INTR_ONLY),y)
24DHDCFLAGS += -DOOB_INTR_ONLY
25endif
26ifeq ($(CONFIG_BCM4329_GET_CUSTOM_MAC_ENABLE),y)
27DHDCFLAGS += -DGET_CUSTOM_MAC_ENABLE
28endif
29ifeq ($(CONFIG_BCM4329_HW_OOB),y)
30DHDCFLAGS += -DHW_OOB
31else
32DHDCFLAGS += -DSDIO_ISR_THREAD
33endif
34ifeq ($(CONFIG_BCM4329_CSCAN_ENABLE),y)
35# implementation of PNO_SUPPORT currently requires CSCAN
36DHDCFLAGS += -DCSCAN -DPNO_SUPPORT
37endif
38
39ifeq ($(TARGET_USE_NEW_TOOLCHAIN),1)
40 # gcc-4.6.1 warns a lot more than previous compilers.
41 # The following is the minimal set of warnings that need to not error out
42 # the build for it to succeed. -Wno-error would also work, but this
43 # explicit list allows them to be fixed in smaller chunks.
44 DHDCFLAGS += -Wno-error=unused-but-set-variable
45 DHDCFLAGS += -Wno-error=array-bounds
46endif
47
48DHDOFILES = dhd_linux.o linux_osl.o bcmutils.o dhd_common.o dhd_custom_gpio.o \
49 wl_iw.o siutils.o sbutils.o aiutils.o hndpmu.o bcmwifi.o dhd_sdio.o \
50 dhd_linux_sched.o dhd_cdc.o bcmsdh_sdmmc.o bcmsdh.o bcmsdh_linux.o \
51 bcmsdh_sdmmc_linux.o
52
53obj-$(CONFIG_BCM4329) += bcm4329.o
54bcm4329-objs += $(DHDOFILES)
55EXTRA_CFLAGS = $(DHDCFLAGS)
56EXTRA_LDFLAGS += --strip-debug
diff --git a/drivers/net/wireless/bcm4329/aiutils.c b/drivers/net/wireless/bcm4329/aiutils.c
new file mode 100644
index 00000000000..df48ac0d83d
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/aiutils.c
@@ -0,0 +1,686 @@
1/*
2 * Misc utility routines for accessing chip-specific features
3 * of the SiliconBackplane-based Broadcom chips.
4 *
5 * Copyright (C) 1999-2010, 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.6.4.7.4.6 2010/04/21 20:43:47 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 <hndsoc.h>
34#include <sbchipc.h>
35#include <pcicfg.h>
36
37#include "siutils_priv.h"
38
39STATIC uint32
40get_asd(si_t *sih, uint32 *eromptr, uint sp, uint ad, uint st,
41 uint32 *addrl, uint32 *addrh, uint32 *sizel, uint32 *sizeh);
42
43
44/* EROM parsing */
45
46static uint32
47get_erom_ent(si_t *sih, uint32 *eromptr, uint32 mask, uint32 match)
48{
49 uint32 ent;
50 uint inv = 0, nom = 0;
51
52 while (TRUE) {
53 ent = R_REG(si_osh(sih), (uint32 *)(uintptr)(*eromptr));
54 *eromptr += sizeof(uint32);
55
56 if (mask == 0)
57 break;
58
59 if ((ent & ER_VALID) == 0) {
60 inv++;
61 continue;
62 }
63
64 if (ent == (ER_END | ER_VALID))
65 break;
66
67 if ((ent & mask) == match)
68 break;
69
70 nom++;
71 }
72
73 SI_MSG(("%s: Returning ent 0x%08x\n", __FUNCTION__, ent));
74 if (inv + nom)
75 SI_MSG((" after %d invalid and %d non-matching entries\n", inv, nom));
76 return ent;
77}
78
79STATIC uint32
80get_asd(si_t *sih, uint32 *eromptr, uint sp, uint ad, uint st,
81 uint32 *addrl, uint32 *addrh, uint32 *sizel, uint32 *sizeh)
82{
83 uint32 asd, sz, szd;
84
85 asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID);
86 if (((asd & ER_TAG1) != ER_ADD) ||
87 (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) ||
88 ((asd & AD_ST_MASK) != st)) {
89 /* This is not what we want, "push" it back */
90 *eromptr -= sizeof(uint32);
91 return 0;
92 }
93 *addrl = asd & AD_ADDR_MASK;
94 if (asd & AD_AG32)
95 *addrh = get_erom_ent(sih, eromptr, 0, 0);
96 else
97 *addrh = 0;
98 *sizeh = 0;
99 sz = asd & AD_SZ_MASK;
100 if (sz == AD_SZ_SZD) {
101 szd = get_erom_ent(sih, eromptr, 0, 0);
102 *sizel = szd & SD_SZ_MASK;
103 if (szd & SD_SG32)
104 *sizeh = get_erom_ent(sih, eromptr, 0, 0);
105 } else
106 *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT);
107
108 SI_MSG((" SP %d, ad %d: st = %d, 0x%08x_0x%08x @ 0x%08x_0x%08x\n",
109 sp, ad, st, *sizeh, *sizel, *addrh, *addrl));
110
111 return asd;
112}
113
114/* parse the enumeration rom to identify all cores */
115void
116ai_scan(si_t *sih, void *regs, uint devid)
117{
118 si_info_t *sii = SI_INFO(sih);
119 chipcregs_t *cc = (chipcregs_t *)regs;
120 uint32 erombase, eromptr, eromlim;
121
122 erombase = R_REG(sii->osh, &cc->eromptr);
123
124 switch (BUSTYPE(sih->bustype)) {
125 case SI_BUS:
126 eromptr = (uintptr)REG_MAP(erombase, SI_CORE_SIZE);
127 break;
128
129 case PCI_BUS:
130 /* Set wrappers address */
131 sii->curwrap = (void *)((uintptr)regs + SI_CORE_SIZE);
132
133 /* Now point the window at the erom */
134 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, erombase);
135 eromptr = (uint32)(uintptr)regs;
136 break;
137
138 case SPI_BUS:
139 case SDIO_BUS:
140 eromptr = erombase;
141 break;
142
143 case PCMCIA_BUS:
144 default:
145 SI_ERROR(("Don't know how to do AXI enumertion on bus %d\n", sih->bustype));
146 ASSERT(0);
147 return;
148 }
149 eromlim = eromptr + ER_REMAPCONTROL;
150
151 SI_MSG(("ai_scan: regs = 0x%p, erombase = 0x%08x, eromptr = 0x%08x, eromlim = 0x%08x\n",
152 regs, erombase, eromptr, eromlim));
153 while (eromptr < eromlim) {
154 uint32 cia, cib, base, cid, mfg, crev, nmw, nsw, nmp, nsp;
155 uint32 mpd, asd, addrl, addrh, sizel, sizeh;
156 uint i, j, idx;
157 bool br;
158
159 br = FALSE;
160
161 /* Grok a component */
162 cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI);
163 if (cia == (ER_END | ER_VALID)) {
164 SI_MSG(("Found END of erom after %d cores\n", sii->numcores));
165 return;
166 }
167 base = eromptr - sizeof(uint32);
168 cib = get_erom_ent(sih, &eromptr, 0, 0);
169
170 if ((cib & ER_TAG) != ER_CI) {
171 SI_ERROR(("CIA not followed by CIB\n"));
172 goto error;
173 }
174
175 cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT;
176 mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT;
177 crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
178 nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT;
179 nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT;
180 nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT;
181 nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT;
182
183 SI_MSG(("Found component 0x%04x/0x%4x rev %d at erom addr 0x%08x, with nmw = %d, "
184 "nsw = %d, nmp = %d & nsp = %d\n",
185 mfg, cid, crev, base, nmw, nsw, nmp, nsp));
186
187 if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0))
188 continue;
189 if ((nmw + nsw == 0)) {
190 /* A component which is not a core */
191 if (cid == OOB_ROUTER_CORE_ID) {
192 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE,
193 &addrl, &addrh, &sizel, &sizeh);
194 if (asd != 0) {
195 sii->common_info->oob_router = addrl;
196 }
197 }
198 continue;
199 }
200
201 idx = sii->numcores;
202/* sii->eromptr[idx] = base; */
203 sii->common_info->cia[idx] = cia;
204 sii->common_info->cib[idx] = cib;
205 sii->common_info->coreid[idx] = cid;
206
207 for (i = 0; i < nmp; i++) {
208 mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID);
209 if ((mpd & ER_TAG) != ER_MP) {
210 SI_ERROR(("Not enough MP entries for component 0x%x\n", cid));
211 goto error;
212 }
213 SI_MSG((" Master port %d, mp: %d id: %d\n", i,
214 (mpd & MPD_MP_MASK) >> MPD_MP_SHIFT,
215 (mpd & MPD_MUI_MASK) >> MPD_MUI_SHIFT));
216 }
217
218 /* First Slave Address Descriptor should be port 0:
219 * the main register space for the core
220 */
221 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, &sizel, &sizeh);
222 if (asd == 0) {
223 /* Try again to see if it is a bridge */
224 asd = get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, &addrh,
225 &sizel, &sizeh);
226 if (asd != 0)
227 br = TRUE;
228 else
229 if ((addrh != 0) || (sizeh != 0) || (sizel != SI_CORE_SIZE)) {
230 SI_ERROR(("First Slave ASD for core 0x%04x malformed "
231 "(0x%08x)\n", cid, asd));
232 goto error;
233 }
234 }
235 sii->common_info->coresba[idx] = addrl;
236 sii->common_info->coresba_size[idx] = sizel;
237 /* Get any more ASDs in port 0 */
238 j = 1;
239 do {
240 asd = get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, &addrh,
241 &sizel, &sizeh);
242 if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE))
243 sii->common_info->coresba2[idx] = addrl;
244 sii->common_info->coresba2_size[idx] = sizel;
245 j++;
246 } while (asd != 0);
247
248 /* Go through the ASDs for other slave ports */
249 for (i = 1; i < nsp; i++) {
250 j = 0;
251 do {
252 asd = get_asd(sih, &eromptr, i, j++, AD_ST_SLAVE, &addrl, &addrh,
253 &sizel, &sizeh);
254 } while (asd != 0);
255 if (j == 0) {
256 SI_ERROR((" SP %d has no address descriptors\n", i));
257 goto error;
258 }
259 }
260
261 /* Now get master wrappers */
262 for (i = 0; i < nmw; i++) {
263 asd = get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, &addrh,
264 &sizel, &sizeh);
265 if (asd == 0) {
266 SI_ERROR(("Missing descriptor for MW %d\n", i));
267 goto error;
268 }
269 if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
270 SI_ERROR(("Master wrapper %d is not 4KB\n", i));
271 goto error;
272 }
273 if (i == 0)
274 sii->common_info->wrapba[idx] = addrl;
275 }
276
277 /* And finally slave wrappers */
278 for (i = 0; i < nsw; i++) {
279 uint fwp = (nsp == 1) ? 0 : 1;
280 asd = get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, &addrl, &addrh,
281 &sizel, &sizeh);
282 if (asd == 0) {
283 SI_ERROR(("Missing descriptor for SW %d\n", i));
284 goto error;
285 }
286 if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) {
287 SI_ERROR(("Slave wrapper %d is not 4KB\n", i));
288 goto error;
289 }
290 if ((nmw == 0) && (i == 0))
291 sii->common_info->wrapba[idx] = addrl;
292 }
293
294 /* Don't record bridges */
295 if (br)
296 continue;
297
298 /* Done with core */
299 sii->numcores++;
300 }
301
302 SI_ERROR(("Reached end of erom without finding END"));
303
304error:
305 sii->numcores = 0;
306 return;
307}
308
309/* This function changes the logical "focus" to the indicated core.
310 * Return the current core's virtual address.
311 */
312void *
313ai_setcoreidx(si_t *sih, uint coreidx)
314{
315 si_info_t *sii = SI_INFO(sih);
316 uint32 addr = sii->common_info->coresba[coreidx];
317 uint32 wrap = sii->common_info->wrapba[coreidx];
318 void *regs;
319
320 if (coreidx >= sii->numcores)
321 return (NULL);
322
323 /*
324 * If the user has provided an interrupt mask enabled function,
325 * then assert interrupts are disabled before switching the core.
326 */
327 ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg));
328
329 switch (BUSTYPE(sih->bustype)) {
330 case SI_BUS:
331 /* map new one */
332 if (!sii->common_info->regs[coreidx]) {
333 sii->common_info->regs[coreidx] = REG_MAP(addr, SI_CORE_SIZE);
334 ASSERT(GOODREGS(sii->common_info->regs[coreidx]));
335 }
336 sii->curmap = regs = sii->common_info->regs[coreidx];
337 if (!sii->common_info->wrappers[coreidx]) {
338 sii->common_info->wrappers[coreidx] = REG_MAP(wrap, SI_CORE_SIZE);
339 ASSERT(GOODREGS(sii->common_info->wrappers[coreidx]));
340 }
341 sii->curwrap = sii->common_info->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/* Return the number of address spaces in current core */
365int
366ai_numaddrspaces(si_t *sih)
367{
368 return 2;
369}
370
371/* Return the address of the nth address space in the current core */
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->common_info->coresba[cidx];
383 else if (asidx == 1)
384 return sii->common_info->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/* Return the size of the nth address space in the current core */
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->common_info->coresba_size[cidx];
404 else if (asidx == 1)
405 return sii->common_info->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
430void
431ai_write_wrap_reg(si_t *sih, uint32 offset, uint32 val)
432{
433 si_info_t *sii = SI_INFO(sih);
434 aidmp_t *ai = sii->curwrap;
435 W_REG(sii->osh, (uint32 *)((uint8 *)ai+offset), val);
436 return;
437}
438
439uint
440ai_corevendor(si_t *sih)
441{
442 si_info_t *sii;
443 uint32 cia;
444
445 sii = SI_INFO(sih);
446 cia = sii->common_info->cia[sii->curidx];
447 return ((cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT);
448}
449
450uint
451ai_corerev(si_t *sih)
452{
453 si_info_t *sii;
454 uint32 cib;
455
456 sii = SI_INFO(sih);
457 cib = sii->common_info->cib[sii->curidx];
458 return ((cib & CIB_REV_MASK) >> CIB_REV_SHIFT);
459}
460
461bool
462ai_iscoreup(si_t *sih)
463{
464 si_info_t *sii;
465 aidmp_t *ai;
466
467 sii = SI_INFO(sih);
468 ai = sii->curwrap;
469
470 return (((R_REG(sii->osh, &ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == SICF_CLOCK_EN) &&
471 ((R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET) == 0));
472}
473
474/*
475 * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation,
476 * switch back to the original core, and return the new value.
477 *
478 * When using the silicon backplane, no fidleing with interrupts or core switches are needed.
479 *
480 * Also, when using pci/pcie, we can optimize away the core switching for pci registers
481 * and (on newer pci cores) chipcommon registers.
482 */
483uint
484ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
485{
486 uint origidx = 0;
487 uint32 *r = NULL;
488 uint w;
489 uint intr_val = 0;
490 bool fast = FALSE;
491 si_info_t *sii;
492
493 sii = SI_INFO(sih);
494
495 ASSERT(GOODIDX(coreidx));
496 ASSERT(regoff < SI_CORE_SIZE);
497 ASSERT((val & ~mask) == 0);
498
499 if (coreidx >= SI_MAXCORES)
500 return 0;
501
502 if (BUSTYPE(sih->bustype) == SI_BUS) {
503 /* If internal bus, we can always get at everything */
504 fast = TRUE;
505 /* map if does not exist */
506 if (!sii->common_info->wrappers[coreidx]) {
507 sii->common_info->regs[coreidx] =
508 REG_MAP(sii->common_info->coresba[coreidx], SI_CORE_SIZE);
509 ASSERT(GOODREGS(sii->common_info->regs[coreidx]));
510 }
511 r = (uint32 *)((uchar *)sii->common_info->regs[coreidx] + regoff);
512 } else if (BUSTYPE(sih->bustype) == PCI_BUS) {
513 /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
514
515 if ((sii->common_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
516 /* Chipc registers are mapped at 12KB */
517
518 fast = TRUE;
519 r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff);
520 } else if (sii->pub.buscoreidx == coreidx) {
521 /* pci registers are at either in the last 2KB of an 8KB window
522 * or, in pcie and pci rev 13 at 8KB
523 */
524 fast = TRUE;
525 if (SI_FAST(sii))
526 r = (uint32 *)((char *)sii->curmap +
527 PCI_16KB0_PCIREGS_OFFSET + regoff);
528 else
529 r = (uint32 *)((char *)sii->curmap +
530 ((regoff >= SBCONFIGOFF) ?
531 PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
532 regoff);
533 }
534 }
535
536 if (!fast) {
537 INTR_OFF(sii, intr_val);
538
539 /* save current core index */
540 origidx = si_coreidx(&sii->pub);
541
542 /* switch core */
543 r = (uint32*) ((uchar*) ai_setcoreidx(&sii->pub, coreidx) + regoff);
544 }
545 ASSERT(r != NULL);
546
547 /* mask and set */
548 if (mask || val) {
549 w = (R_REG(sii->osh, r) & ~mask) | val;
550 W_REG(sii->osh, r, w);
551 }
552
553 /* readback */
554 w = R_REG(sii->osh, r);
555
556 if (!fast) {
557 /* restore core index */
558 if (origidx != coreidx)
559 ai_setcoreidx(&sii->pub, origidx);
560
561 INTR_RESTORE(sii, intr_val);
562 }
563
564 return (w);
565}
566
567void
568ai_core_disable(si_t *sih, uint32 bits)
569{
570 si_info_t *sii;
571 volatile uint32 dummy;
572 aidmp_t *ai;
573
574 sii = SI_INFO(sih);
575
576 ASSERT(GOODREGS(sii->curwrap));
577 ai = sii->curwrap;
578
579 /* if core is already in reset, just return */
580 if (R_REG(sii->osh, &ai->resetctrl) & AIRC_RESET)
581 return;
582
583 W_REG(sii->osh, &ai->ioctrl, bits);
584 dummy = R_REG(sii->osh, &ai->ioctrl);
585 OSL_DELAY(10);
586
587 W_REG(sii->osh, &ai->resetctrl, AIRC_RESET);
588 OSL_DELAY(1);
589}
590
591/* reset and re-enable a core
592 * inputs:
593 * bits - core specific bits that are set during and after reset sequence
594 * resetbits - core specific bits that are set only during reset sequence
595 */
596void
597ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
598{
599 si_info_t *sii;
600 aidmp_t *ai;
601 volatile uint32 dummy;
602
603 sii = SI_INFO(sih);
604 ASSERT(GOODREGS(sii->curwrap));
605 ai = sii->curwrap;
606
607 /*
608 * Must do the disable sequence first to work for arbitrary current core state.
609 */
610 ai_core_disable(sih, (bits | resetbits));
611
612 /*
613 * Now do the initialization sequence.
614 */
615 W_REG(sii->osh, &ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN));
616 dummy = R_REG(sii->osh, &ai->ioctrl);
617 W_REG(sii->osh, &ai->resetctrl, 0);
618 OSL_DELAY(1);
619
620 W_REG(sii->osh, &ai->ioctrl, (bits | SICF_CLOCK_EN));
621 dummy = R_REG(sii->osh, &ai->ioctrl);
622 OSL_DELAY(1);
623}
624
625
626void
627ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
628{
629 si_info_t *sii;
630 aidmp_t *ai;
631 uint32 w;
632
633 sii = SI_INFO(sih);
634 ASSERT(GOODREGS(sii->curwrap));
635 ai = sii->curwrap;
636
637 ASSERT((val & ~mask) == 0);
638
639 if (mask || val) {
640 w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val);
641 W_REG(sii->osh, &ai->ioctrl, w);
642 }
643}
644
645uint32
646ai_core_cflags(si_t *sih, uint32 mask, uint32 val)
647{
648 si_info_t *sii;
649 aidmp_t *ai;
650 uint32 w;
651
652 sii = SI_INFO(sih);
653 ASSERT(GOODREGS(sii->curwrap));
654 ai = sii->curwrap;
655
656 ASSERT((val & ~mask) == 0);
657
658 if (mask || val) {
659 w = ((R_REG(sii->osh, &ai->ioctrl) & ~mask) | val);
660 W_REG(sii->osh, &ai->ioctrl, w);
661 }
662
663 return R_REG(sii->osh, &ai->ioctrl);
664}
665
666uint32
667ai_core_sflags(si_t *sih, uint32 mask, uint32 val)
668{
669 si_info_t *sii;
670 aidmp_t *ai;
671 uint32 w;
672
673 sii = SI_INFO(sih);
674 ASSERT(GOODREGS(sii->curwrap));
675 ai = sii->curwrap;
676
677 ASSERT((val & ~mask) == 0);
678 ASSERT((mask & ~SISF_CORE_BITS) == 0);
679
680 if (mask || val) {
681 w = ((R_REG(sii->osh, &ai->iostatus) & ~mask) | val);
682 W_REG(sii->osh, &ai->iostatus, w);
683 }
684
685 return R_REG(sii->osh, &ai->iostatus);
686}
diff --git a/drivers/net/wireless/bcm4329/bcmpcispi.c b/drivers/net/wireless/bcm4329/bcmpcispi.c
new file mode 100644
index 00000000000..1a8b6717f92
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmpcispi.c
@@ -0,0 +1,630 @@
1/*
2 * Broadcom SPI over PCI-SPI Host Controller, low-level hardware driver
3 *
4 * Copyright (C) 1999-2010, 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.c,v 1.22.2.4.4.5.6.1 2010/08/13 00:26:05 Exp $
25 */
26
27#include <typedefs.h>
28#include <bcmutils.h>
29
30#include <sdio.h> /* SDIO Specs */
31#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
32#include <sdiovar.h> /* to get msglevel bit values */
33
34#include <pcicfg.h>
35#include <bcmsdspi.h>
36#include <bcmspi.h>
37#include <bcmpcispi.h> /* BRCM PCI-SPI Host Controller Register definitions */
38
39
40/* ndis_osl.h needs to do a runtime check of the osh to map
41 * R_REG/W_REG to bus specific access similar to linux_osl.h.
42 * Until then...
43 */
44/* linux */
45
46#define SPIPCI_RREG R_REG
47#define SPIPCI_WREG W_REG
48
49
50#define SPIPCI_ANDREG(osh, r, v) SPIPCI_WREG(osh, (r), (SPIPCI_RREG(osh, r) & (v)))
51#define SPIPCI_ORREG(osh, r, v) SPIPCI_WREG(osh, (r), (SPIPCI_RREG(osh, r) | (v)))
52
53
54int bcmpcispi_dump = 0; /* Set to dump complete trace of all SPI bus transactions */
55
56typedef struct spih_info_ {
57 uint bar0; /* BAR0 of PCI Card */
58 uint bar1; /* BAR1 of PCI Card */
59 osl_t *osh; /* osh handle */
60 spih_pciregs_t *pciregs; /* PCI Core Registers */
61 spih_regs_t *regs; /* SPI Controller Registers */
62 uint8 rev; /* PCI Card Revision ID */
63} spih_info_t;
64
65
66/* Attach to PCI-SPI Host Controller Hardware */
67bool
68spi_hw_attach(sdioh_info_t *sd)
69{
70 osl_t *osh;
71 spih_info_t *si;
72
73 sd_trace(("%s: enter\n", __FUNCTION__));
74
75 osh = sd->osh;
76
77 if ((si = (spih_info_t *)MALLOC(osh, sizeof(spih_info_t))) == NULL) {
78 sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh)));
79 return FALSE;
80 }
81
82 bzero(si, sizeof(spih_info_t));
83
84 sd->controller = si;
85
86 si->osh = sd->osh;
87 si->rev = OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_REV, 4) & 0xFF;
88
89 if (si->rev < 3) {
90 sd_err(("Host controller %d not supported, please upgrade to rev >= 3\n", si->rev));
91 MFREE(osh, si, sizeof(spih_info_t));
92 return (FALSE);
93 }
94
95 sd_err(("Attaching to Generic PCI SPI Host Controller Rev %d\n", si->rev));
96
97 /* FPGA Revision < 3 not supported by driver anymore. */
98 ASSERT(si->rev >= 3);
99
100 si->bar0 = sd->bar0;
101
102 /* Rev < 10 PciSpiHost has 2 BARs:
103 * BAR0 = PCI Core Registers
104 * BAR1 = PciSpiHost Registers (all other cores on backplane)
105 *
106 * Rev 10 and up use a different PCI core which only has a single
107 * BAR0 which contains the PciSpiHost Registers.
108 */
109 if (si->rev < 10) {
110 si->pciregs = (spih_pciregs_t *)spi_reg_map(osh,
111 (uintptr)si->bar0,
112 sizeof(spih_pciregs_t));
113 sd_err(("Mapped PCI Core regs to BAR0 at %p\n", si->pciregs));
114
115 si->bar1 = OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_BAR1, 4);
116 si->regs = (spih_regs_t *)spi_reg_map(osh,
117 (uintptr)si->bar1,
118 sizeof(spih_regs_t));
119 sd_err(("Mapped SPI Controller regs to BAR1 at %p\n", si->regs));
120 } else {
121 si->regs = (spih_regs_t *)spi_reg_map(osh,
122 (uintptr)si->bar0,
123 sizeof(spih_regs_t));
124 sd_err(("Mapped SPI Controller regs to BAR0 at %p\n", si->regs));
125 si->pciregs = NULL;
126 }
127 /* Enable SPI Controller, 16.67MHz SPI Clock */
128 SPIPCI_WREG(osh, &si->regs->spih_ctrl, 0x000000d1);
129
130 /* Set extended feature register to defaults */
131 SPIPCI_WREG(osh, &si->regs->spih_ext, 0x00000000);
132
133 /* Set GPIO CS# High (de-asserted) */
134 SPIPCI_WREG(osh, &si->regs->spih_gpio_data, SPIH_CS);
135
136 /* set GPIO[0] to output for CS# */
137 /* set GPIO[1] to output for power control */
138 /* set GPIO[2] to input for card detect */
139 SPIPCI_WREG(osh, &si->regs->spih_gpio_ctrl, (SPIH_CS | SPIH_SLOT_POWER));
140
141 /* Clear out the Read FIFO in case there is any stuff left in there from a previous run. */
142 while ((SPIPCI_RREG(osh, &si->regs->spih_stat) & SPIH_RFEMPTY) == 0) {
143 SPIPCI_RREG(osh, &si->regs->spih_data);
144 }
145
146 /* Wait for power to stabilize to the SDIO Card (100msec was insufficient) */
147 OSL_DELAY(250000);
148
149 /* Check card detect on FPGA Revision >= 4 */
150 if (si->rev >= 4) {
151 if (SPIPCI_RREG(osh, &si->regs->spih_gpio_data) & SPIH_CARD_DETECT) {
152 sd_err(("%s: no card detected in SD slot\n", __FUNCTION__));
153 spi_reg_unmap(osh, (uintptr)si->regs, sizeof(spih_regs_t));
154 if (si->pciregs) {
155 spi_reg_unmap(osh, (uintptr)si->pciregs, sizeof(spih_pciregs_t));
156 }
157 MFREE(osh, si, sizeof(spih_info_t));
158 return FALSE;
159 }
160 }
161
162 /* Interrupts are level sensitive */
163 SPIPCI_WREG(osh, &si->regs->spih_int_edge, 0x80000000);
164
165 /* Interrupts are active low. */
166 SPIPCI_WREG(osh, &si->regs->spih_int_pol, 0x40000004);
167
168 /* Enable interrupts through PCI Core. */
169 if (si->pciregs) {
170 SPIPCI_WREG(osh, &si->pciregs->ICR, PCI_INT_PROP_EN);
171 }
172
173 sd_trace(("%s: exit\n", __FUNCTION__));
174 return TRUE;
175}
176
177/* Detach and return PCI-SPI Hardware to unconfigured state */
178bool
179spi_hw_detach(sdioh_info_t *sd)
180{
181 spih_info_t *si = (spih_info_t *)sd->controller;
182 osl_t *osh = si->osh;
183 spih_regs_t *regs = si->regs;
184 spih_pciregs_t *pciregs = si->pciregs;
185
186 sd_trace(("%s: enter\n", __FUNCTION__));
187
188 SPIPCI_WREG(osh, &regs->spih_ctrl, 0x00000010);
189 SPIPCI_WREG(osh, &regs->spih_gpio_ctrl, 0x00000000); /* Disable GPIO for CS# */
190 SPIPCI_WREG(osh, &regs->spih_int_mask, 0x00000000); /* Clear Intmask */
191 SPIPCI_WREG(osh, &regs->spih_hex_disp, 0x0000DEAF);
192 SPIPCI_WREG(osh, &regs->spih_int_edge, 0x00000000);
193 SPIPCI_WREG(osh, &regs->spih_int_pol, 0x00000000);
194 SPIPCI_WREG(osh, &regs->spih_hex_disp, 0x0000DEAD);
195
196 /* Disable interrupts through PCI Core. */
197 if (si->pciregs) {
198 SPIPCI_WREG(osh, &pciregs->ICR, 0x00000000);
199 spi_reg_unmap(osh, (uintptr)pciregs, sizeof(spih_pciregs_t));
200 }
201 spi_reg_unmap(osh, (uintptr)regs, sizeof(spih_regs_t));
202
203 MFREE(osh, si, sizeof(spih_info_t));
204
205 sd->controller = NULL;
206
207 sd_trace(("%s: exit\n", __FUNCTION__));
208 return TRUE;
209}
210
211/* Switch between internal (PCI) and external clock oscillator */
212static bool
213sdspi_switch_clock(sdioh_info_t *sd, bool ext_clk)
214{
215 spih_info_t *si = (spih_info_t *)sd->controller;
216 osl_t *osh = si->osh;
217 spih_regs_t *regs = si->regs;
218
219 /* Switch to desired clock, and reset the PLL. */
220 SPIPCI_WREG(osh, &regs->spih_pll_ctrl, ext_clk ? SPIH_EXT_CLK : 0);
221
222 SPINWAIT(((SPIPCI_RREG(osh, &regs->spih_pll_status) & SPIH_PLL_LOCKED)
223 != SPIH_PLL_LOCKED), 1000);
224 if ((SPIPCI_RREG(osh, &regs->spih_pll_status) & SPIH_PLL_LOCKED) != SPIH_PLL_LOCKED) {
225 sd_err(("%s: timeout waiting for PLL to lock\n", __FUNCTION__));
226 return (FALSE);
227 }
228 return (TRUE);
229
230}
231
232/* Configure PCI-SPI Host Controller's SPI Clock rate as a divisor into the
233 * base clock rate. The base clock is either the PCI Clock (33MHz) or the
234 * external clock oscillator at U17 on the PciSpiHost.
235 */
236bool
237spi_start_clock(sdioh_info_t *sd, uint16 div)
238{
239 spih_info_t *si = (spih_info_t *)sd->controller;
240 osl_t *osh = si->osh;
241 spih_regs_t *regs = si->regs;
242 uint32 t, espr, disp;
243 uint32 disp_xtal_freq;
244 bool ext_clock = FALSE;
245 char disp_string[5];
246
247 if (div > 2048) {
248 sd_err(("%s: divisor %d too large; using max of 2048\n", __FUNCTION__, div));
249 div = 2048;
250 } else if (div & (div - 1)) { /* Not a power of 2? */
251 /* Round up to a power of 2 */
252 while ((div + 1) & div)
253 div |= div >> 1;
254 div++;
255 }
256
257 /* For FPGA Rev >= 5, the use of an external clock oscillator is supported.
258 * If the oscillator is populated, use it to provide the SPI base clock,
259 * otherwise, default to the PCI clock as the SPI base clock.
260 */
261 if (si->rev >= 5) {
262 uint32 clk_tick;
263 /* Enable the External Clock Oscillator as PLL clock source. */
264 if (!sdspi_switch_clock(sd, TRUE)) {
265 sd_err(("%s: error switching to external clock\n", __FUNCTION__));
266 }
267
268 /* Check to make sure the external clock is running. If not, then it
269 * is not populated on the card, so we will default to the PCI clock.
270 */
271 clk_tick = SPIPCI_RREG(osh, &regs->spih_clk_count);
272 if (clk_tick == SPIPCI_RREG(osh, &regs->spih_clk_count)) {
273
274 /* Switch back to the PCI clock as the clock source. */
275 if (!sdspi_switch_clock(sd, FALSE)) {
276 sd_err(("%s: error switching to external clock\n", __FUNCTION__));
277 }
278 } else {
279 ext_clock = TRUE;
280 }
281 }
282
283 /* Hack to allow hot-swapping oscillators:
284 * 1. Force PCI clock as clock source, using sd_divisor of 0.
285 * 2. Swap oscillator
286 * 3. Set desired sd_divisor (will switch to external oscillator as clock source.
287 */
288 if (div == 0) {
289 ext_clock = FALSE;
290 div = 2;
291
292 /* Select PCI clock as the clock source. */
293 if (!sdspi_switch_clock(sd, FALSE)) {
294 sd_err(("%s: error switching to external clock\n", __FUNCTION__));
295 }
296
297 sd_err(("%s: Ok to hot-swap oscillators.\n", __FUNCTION__));
298 }
299
300 /* If using the external oscillator, read the clock frequency from the controller
301 * The value read is in units of 10000Hz, and it's not a nice round number because
302 * it is calculated by the FPGA. So to make up for that, we round it off.
303 */
304 if (ext_clock == TRUE) {
305 uint32 xtal_freq;
306
307 OSL_DELAY(1000);
308 xtal_freq = SPIPCI_RREG(osh, &regs->spih_xtal_freq) * 10000;
309
310 sd_info(("%s: Oscillator is %dHz\n", __FUNCTION__, xtal_freq));
311
312
313 disp_xtal_freq = xtal_freq / 10000;
314
315 /* Round it off to a nice number. */
316 if ((disp_xtal_freq % 100) > 50) {
317 disp_xtal_freq += 100;
318 }
319
320 disp_xtal_freq = (disp_xtal_freq / 100) * 100;
321 } else {
322 sd_err(("%s: no external oscillator installed, using PCI clock.\n", __FUNCTION__));
323 disp_xtal_freq = 3333;
324 }
325
326 /* Convert the SPI Clock frequency to BCD format. */
327 sprintf(disp_string, "%04d", disp_xtal_freq / div);
328
329 disp = (disp_string[0] - '0') << 12;
330 disp |= (disp_string[1] - '0') << 8;
331 disp |= (disp_string[2] - '0') << 4;
332 disp |= (disp_string[3] - '0');
333
334 /* Select the correct ESPR register value based on the divisor. */
335 switch (div) {
336 case 1: espr = 0x0; break;
337 case 2: espr = 0x1; break;
338 case 4: espr = 0x2; break;
339 case 8: espr = 0x5; break;
340 case 16: espr = 0x3; break;
341 case 32: espr = 0x4; break;
342 case 64: espr = 0x6; break;
343 case 128: espr = 0x7; break;
344 case 256: espr = 0x8; break;
345 case 512: espr = 0x9; break;
346 case 1024: espr = 0xa; break;
347 case 2048: espr = 0xb; break;
348 default: espr = 0x0; ASSERT(0); break;
349 }
350
351 t = SPIPCI_RREG(osh, &regs->spih_ctrl);
352 t &= ~3;
353 t |= espr & 3;
354 SPIPCI_WREG(osh, &regs->spih_ctrl, t);
355
356 t = SPIPCI_RREG(osh, &regs->spih_ext);
357 t &= ~3;
358 t |= (espr >> 2) & 3;
359 SPIPCI_WREG(osh, &regs->spih_ext, t);
360
361 SPIPCI_WREG(osh, &regs->spih_hex_disp, disp);
362
363 /* For Rev 8, writing to the PLL_CTRL register resets
364 * the PLL, and it can re-acquire in 200uS. For
365 * Rev 7 and older, we use a software delay to allow
366 * the PLL to re-acquire, which takes more than 2mS.
367 */
368 if (si->rev < 8) {
369 /* Wait for clock to settle. */
370 OSL_DELAY(5000);
371 }
372
373 sd_info(("%s: SPI_CTRL=0x%08x SPI_EXT=0x%08x\n",
374 __FUNCTION__,
375 SPIPCI_RREG(osh, &regs->spih_ctrl),
376 SPIPCI_RREG(osh, &regs->spih_ext)));
377
378 return TRUE;
379}
380
381/* Configure PCI-SPI Host Controller High-Speed Clocking mode setting */
382bool
383spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode)
384{
385 spih_info_t *si = (spih_info_t *)sd->controller;
386 osl_t *osh = si->osh;
387 spih_regs_t *regs = si->regs;
388
389 if (si->rev >= 10) {
390 if (hsmode) {
391 SPIPCI_ORREG(osh, &regs->spih_ext, 0x10);
392 } else {
393 SPIPCI_ANDREG(osh, &regs->spih_ext, ~0x10);
394 }
395 }
396
397 return TRUE;
398}
399
400/* Disable device interrupt */
401void
402spi_devintr_off(sdioh_info_t *sd)
403{
404 spih_info_t *si = (spih_info_t *)sd->controller;
405 osl_t *osh = si->osh;
406 spih_regs_t *regs = si->regs;
407
408 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
409 if (sd->use_client_ints) {
410 sd->intmask &= ~SPIH_DEV_INTR;
411 SPIPCI_WREG(osh, &regs->spih_int_mask, sd->intmask); /* Clear Intmask */
412 }
413}
414
415/* Enable device interrupt */
416void
417spi_devintr_on(sdioh_info_t *sd)
418{
419 spih_info_t *si = (spih_info_t *)sd->controller;
420 osl_t *osh = si->osh;
421 spih_regs_t *regs = si->regs;
422
423 ASSERT(sd->lockcount == 0);
424 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
425 if (sd->use_client_ints) {
426 if (SPIPCI_RREG(osh, &regs->spih_ctrl) & 0x02) {
427 /* Ack in case one was pending but is no longer... */
428 SPIPCI_WREG(osh, &regs->spih_int_status, SPIH_DEV_INTR);
429 }
430 sd->intmask |= SPIH_DEV_INTR;
431 /* Set device intr in Intmask */
432 SPIPCI_WREG(osh, &regs->spih_int_mask, sd->intmask);
433 }
434}
435
436/* Check to see if an interrupt belongs to the PCI-SPI Host or a SPI Device */
437bool
438spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr)
439{
440 spih_info_t *si = (spih_info_t *)sd->controller;
441 osl_t *osh = si->osh;
442 spih_regs_t *regs = si->regs;
443 bool ours = FALSE;
444
445 uint32 raw_int, cur_int;
446 ASSERT(sd);
447
448 if (is_dev_intr)
449 *is_dev_intr = FALSE;
450 raw_int = SPIPCI_RREG(osh, &regs->spih_int_status);
451 cur_int = raw_int & sd->intmask;
452 if (cur_int & SPIH_DEV_INTR) {
453 if (sd->client_intr_enabled && sd->use_client_ints) {
454 sd->intrcount++;
455 ASSERT(sd->intr_handler);
456 ASSERT(sd->intr_handler_arg);
457 (sd->intr_handler)(sd->intr_handler_arg);
458 if (is_dev_intr)
459 *is_dev_intr = TRUE;
460 } else {
461 sd_trace(("%s: Not ready for intr: enabled %d, handler 0x%p\n",
462 __FUNCTION__, sd->client_intr_enabled, sd->intr_handler));
463 }
464 SPIPCI_WREG(osh, &regs->spih_int_status, SPIH_DEV_INTR);
465 SPIPCI_RREG(osh, &regs->spih_int_status);
466 ours = TRUE;
467 } else if (cur_int & SPIH_CTLR_INTR) {
468 /* Interrupt is from SPI FIFO... just clear and ack it... */
469 sd_trace(("%s: SPI CTLR interrupt: raw_int 0x%08x cur_int 0x%08x\n",
470 __FUNCTION__, raw_int, cur_int));
471
472 /* Clear the interrupt in the SPI_STAT register */
473 SPIPCI_WREG(osh, &regs->spih_stat, 0x00000080);
474
475 /* Ack the interrupt in the interrupt controller */
476 SPIPCI_WREG(osh, &regs->spih_int_status, SPIH_CTLR_INTR);
477 SPIPCI_RREG(osh, &regs->spih_int_status);
478
479 ours = TRUE;
480 } else if (cur_int & SPIH_WFIFO_INTR) {
481 sd_trace(("%s: SPI WR FIFO Empty interrupt: raw_int 0x%08x cur_int 0x%08x\n",
482 __FUNCTION__, raw_int, cur_int));
483
484 /* Disable the FIFO Empty Interrupt */
485 sd->intmask &= ~SPIH_WFIFO_INTR;
486 SPIPCI_WREG(osh, &regs->spih_int_mask, sd->intmask);
487
488 sd->local_intrcount++;
489 sd->got_hcint = TRUE;
490 ours = TRUE;
491 } else {
492 /* Not an error: can share interrupts... */
493 sd_trace(("%s: Not my interrupt: raw_int 0x%08x cur_int 0x%08x\n",
494 __FUNCTION__, raw_int, cur_int));
495 ours = FALSE;
496 }
497
498 return ours;
499}
500
501static void
502hexdump(char *pfx, unsigned char *msg, int msglen)
503{
504 int i, col;
505 char buf[80];
506
507 ASSERT(strlen(pfx) + 49 <= sizeof(buf));
508
509 col = 0;
510
511 for (i = 0; i < msglen; i++, col++) {
512 if (col % 16 == 0)
513 strcpy(buf, pfx);
514 sprintf(buf + strlen(buf), "%02x", msg[i]);
515 if ((col + 1) % 16 == 0)
516 printf("%s\n", buf);
517 else
518 sprintf(buf + strlen(buf), " ");
519 }
520
521 if (col % 16 != 0)
522 printf("%s\n", buf);
523}
524
525/* Send/Receive an SPI Packet */
526void
527spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen)
528{
529 spih_info_t *si = (spih_info_t *)sd->controller;
530 osl_t *osh = si->osh;
531 spih_regs_t *regs = si->regs;
532 uint32 count;
533 uint32 spi_data_out;
534 uint32 spi_data_in;
535 bool yield;
536
537 sd_trace(("%s: enter\n", __FUNCTION__));
538
539 if (bcmpcispi_dump) {
540 printf("SENDRECV(len=%d)\n", msglen);
541 hexdump(" OUT: ", msg_out, msglen);
542 }
543
544#ifdef BCMSDYIELD
545 /* Only yield the CPU and wait for interrupt on Rev 8 and newer FPGA images. */
546 yield = ((msglen > 500) && (si->rev >= 8));
547#else
548 yield = FALSE;
549#endif /* BCMSDYIELD */
550
551 ASSERT(msglen % 4 == 0);
552
553
554 SPIPCI_ANDREG(osh, &regs->spih_gpio_data, ~SPIH_CS); /* Set GPIO CS# Low (asserted) */
555
556 for (count = 0; count < (uint32)msglen/4; count++) {
557 spi_data_out = ((uint32)((uint32 *)msg_out)[count]);
558 SPIPCI_WREG(osh, &regs->spih_data, spi_data_out);
559 }
560
561#ifdef BCMSDYIELD
562 if (yield) {
563 /* Ack the interrupt in the interrupt controller */
564 SPIPCI_WREG(osh, &regs->spih_int_status, SPIH_WFIFO_INTR);
565 SPIPCI_RREG(osh, &regs->spih_int_status);
566
567 /* Enable the FIFO Empty Interrupt */
568 sd->intmask |= SPIH_WFIFO_INTR;
569 sd->got_hcint = FALSE;
570 SPIPCI_WREG(osh, &regs->spih_int_mask, sd->intmask);
571
572 }
573#endif /* BCMSDYIELD */
574
575 /* Wait for write fifo to empty... */
576 SPIPCI_ANDREG(osh, &regs->spih_gpio_data, ~0x00000020); /* Set GPIO 5 Low */
577
578 if (yield) {
579 ASSERT((SPIPCI_RREG(sd->osh, &regs->spih_stat) & SPIH_WFEMPTY) == 0);
580 }
581
582 spi_waitbits(sd, yield);
583 SPIPCI_ORREG(osh, &regs->spih_gpio_data, 0x00000020); /* Set GPIO 5 High (de-asserted) */
584
585 for (count = 0; count < (uint32)msglen/4; count++) {
586 spi_data_in = SPIPCI_RREG(osh, &regs->spih_data);
587 ((uint32 *)msg_in)[count] = spi_data_in;
588 }
589
590 /* Set GPIO CS# High (de-asserted) */
591 SPIPCI_ORREG(osh, &regs->spih_gpio_data, SPIH_CS);
592
593 if (bcmpcispi_dump) {
594 hexdump(" IN : ", msg_in, msglen);
595 }
596}
597
598void
599spi_spinbits(sdioh_info_t *sd)
600{
601 spih_info_t *si = (spih_info_t *)sd->controller;
602 osl_t *osh = si->osh;
603 spih_regs_t *regs = si->regs;
604 uint spin_count; /* Spin loop bound check */
605
606 spin_count = 0;
607 while ((SPIPCI_RREG(sd->osh, &regs->spih_stat) & SPIH_WFEMPTY) == 0) {
608 if (spin_count > SPI_SPIN_BOUND) {
609 sd_err(("%s: SPIH_WFEMPTY spin bits out of bound %u times \n",
610 __FUNCTION__, spin_count));
611 ASSERT(FALSE);
612 }
613 spin_count++;
614 }
615
616 /* Wait for SPI Transfer state machine to return to IDLE state.
617 * The state bits are only implemented in Rev >= 5 FPGA. These
618 * bits are hardwired to 00 for Rev < 5, so this check doesn't cause
619 * any problems.
620 */
621 spin_count = 0;
622 while ((SPIPCI_RREG(osh, &regs->spih_stat) & SPIH_STATE_MASK) != 0) {
623 if (spin_count > SPI_SPIN_BOUND) {
624 sd_err(("%s: SPIH_STATE_MASK spin bits out of bound %u times \n",
625 __FUNCTION__, spin_count));
626 ASSERT(FALSE);
627 }
628 spin_count++;
629 }
630}
diff --git a/drivers/net/wireless/bcm4329/bcmsdh.c b/drivers/net/wireless/bcm4329/bcmsdh.c
new file mode 100644
index 00000000000..4bf5889e5a6
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmsdh.c
@@ -0,0 +1,652 @@
1/*
2 * BCMSDH interface glue
3 * implement bcmsdh API for SDIOH driver
4 *
5 * Copyright (C) 1999-2010, 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,v 1.35.2.1.4.8.6.13 2010/04/06 03:26:57 Exp $
26 */
27/* ****************** BCMSDH Interface Functions *************************** */
28
29#include <typedefs.h>
30#include <bcmdevs.h>
31#include <bcmendian.h>
32#include <bcmutils.h>
33#include <hndsoc.h>
34#include <siutils.h>
35#include <osl.h>
36
37#include <bcmsdh.h> /* BRCM API for SDIO clients (such as wl, dhd) */
38#include <bcmsdbus.h> /* common SDIO/controller interface */
39#include <sbsdio.h> /* BRCM sdio device core */
40
41#include <sdio.h> /* sdio spec */
42
43#define SDIOH_API_ACCESS_RETRY_LIMIT 2
44const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL;
45
46
47struct bcmsdh_info
48{
49 bool init_success; /* underlying driver successfully attached */
50 void *sdioh; /* handler for sdioh */
51 uint32 vendevid; /* Target Vendor and Device ID on SD bus */
52 osl_t *osh;
53 bool regfail; /* Save status of last reg_read/reg_write call */
54 uint32 sbwad; /* Save backplane window address */
55};
56/* local copy of bcm sd handler */
57bcmsdh_info_t * l_bcmsdh = NULL;
58
59#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
60extern int
61sdioh_enable_hw_oob_intr(void *sdioh, bool enable);
62
63void
64bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable)
65{
66 sdioh_enable_hw_oob_intr(sdh->sdioh, enable);
67}
68#endif
69
70bcmsdh_info_t *
71bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq)
72{
73 bcmsdh_info_t *bcmsdh;
74
75 if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) {
76 BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
77 return NULL;
78 }
79 bzero((char *)bcmsdh, sizeof(bcmsdh_info_t));
80
81 /* save the handler locally */
82 l_bcmsdh = bcmsdh;
83
84 if (!(bcmsdh->sdioh = sdioh_attach(osh, cfghdl, irq))) {
85 bcmsdh_detach(osh, bcmsdh);
86 return NULL;
87 }
88
89 bcmsdh->osh = osh;
90 bcmsdh->init_success = TRUE;
91
92 *regsva = (uint32 *)SI_ENUM_BASE;
93
94 /* Report the BAR, to fix if needed */
95 bcmsdh->sbwad = SI_ENUM_BASE;
96 return bcmsdh;
97}
98
99int
100bcmsdh_detach(osl_t *osh, void *sdh)
101{
102 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
103
104 if (bcmsdh != NULL) {
105 if (bcmsdh->sdioh) {
106 sdioh_detach(osh, bcmsdh->sdioh);
107 bcmsdh->sdioh = NULL;
108 }
109 MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t));
110 }
111
112 l_bcmsdh = NULL;
113 return 0;
114}
115
116int
117bcmsdh_iovar_op(void *sdh, const char *name,
118 void *params, int plen, void *arg, int len, bool set)
119{
120 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
121 return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set);
122}
123
124bool
125bcmsdh_intr_query(void *sdh)
126{
127 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
128 SDIOH_API_RC status;
129 bool on;
130
131 ASSERT(bcmsdh);
132 status = sdioh_interrupt_query(bcmsdh->sdioh, &on);
133 if (SDIOH_API_SUCCESS(status))
134 return FALSE;
135 else
136 return on;
137}
138
139int
140bcmsdh_intr_enable(void *sdh)
141{
142 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
143 SDIOH_API_RC status;
144 ASSERT(bcmsdh);
145
146 status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE);
147 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
148}
149
150int
151bcmsdh_intr_disable(void *sdh)
152{
153 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
154 SDIOH_API_RC status;
155 ASSERT(bcmsdh);
156
157 status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE);
158 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
159}
160
161int
162bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
163{
164 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
165 SDIOH_API_RC status;
166 ASSERT(bcmsdh);
167
168 status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh);
169 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
170}
171
172int
173bcmsdh_intr_dereg(void *sdh)
174{
175 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
176 SDIOH_API_RC status;
177 ASSERT(bcmsdh);
178
179 status = sdioh_interrupt_deregister(bcmsdh->sdioh);
180 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
181}
182
183#if defined(DHD_DEBUG)
184bool
185bcmsdh_intr_pending(void *sdh)
186{
187 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
188
189 ASSERT(sdh);
190 return sdioh_interrupt_pending(bcmsdh->sdioh);
191}
192#endif
193
194
195int
196bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
197{
198 ASSERT(sdh);
199
200 /* don't support yet */
201 return BCME_UNSUPPORTED;
202}
203
204uint8
205bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err)
206{
207 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
208 SDIOH_API_RC status;
209#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
210 int32 retry = 0;
211#endif
212 uint8 data = 0;
213
214 if (!bcmsdh)
215 bcmsdh = l_bcmsdh;
216
217 ASSERT(bcmsdh->init_success);
218
219#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
220 do {
221 if (retry) /* wait for 1 ms till bus get settled down */
222 OSL_DELAY(1000);
223#endif
224 status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data);
225#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
226 } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
227#endif
228 if (err)
229 *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
230
231 BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__,
232 fnc_num, addr, data));
233
234 return data;
235}
236
237void
238bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err)
239{
240 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
241 SDIOH_API_RC status;
242#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
243 int32 retry = 0;
244#endif
245
246 if (!bcmsdh)
247 bcmsdh = l_bcmsdh;
248
249 ASSERT(bcmsdh->init_success);
250
251#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
252 do {
253 if (retry) /* wait for 1 ms till bus get settled down */
254 OSL_DELAY(1000);
255#endif
256 status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data);
257#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
258 } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
259#endif
260 if (err)
261 *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR;
262
263 BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__,
264 fnc_num, addr, data));
265}
266
267uint32
268bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err)
269{
270 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
271 SDIOH_API_RC status;
272 uint32 data = 0;
273
274 if (!bcmsdh)
275 bcmsdh = l_bcmsdh;
276
277 ASSERT(bcmsdh->init_success);
278
279 status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num,
280 addr, &data, 4);
281
282 if (err)
283 *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
284
285 BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__,
286 fnc_num, addr, data));
287
288 return data;
289}
290
291void
292bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err)
293{
294 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
295 SDIOH_API_RC status;
296
297 if (!bcmsdh)
298 bcmsdh = l_bcmsdh;
299
300 ASSERT(bcmsdh->init_success);
301
302 status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num,
303 addr, &data, 4);
304
305 if (err)
306 *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
307
308 BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num,
309 addr, data));
310}
311
312
313int
314bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length)
315{
316 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
317 SDIOH_API_RC status;
318
319 uint8 *tmp_buf, *tmp_ptr;
320 uint8 *ptr;
321 bool ascii = func & ~0xf;
322 func &= 0x7;
323
324 if (!bcmsdh)
325 bcmsdh = l_bcmsdh;
326
327 ASSERT(bcmsdh->init_success);
328 ASSERT(cis);
329 ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT);
330
331 status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length);
332
333 if (ascii) {
334 /* Move binary bits to tmp and format them into the provided buffer. */
335 if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) {
336 BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__));
337 return BCME_NOMEM;
338 }
339 bcopy(cis, tmp_buf, length);
340 for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) {
341 ptr += sprintf((char*)ptr, "%.2x ", *tmp_ptr & 0xff);
342 if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0)
343 ptr += sprintf((char *)ptr, "\n");
344 }
345 MFREE(bcmsdh->osh, tmp_buf, length);
346 }
347
348 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
349}
350
351
352static int
353bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address)
354{
355 int err = 0;
356 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
357 bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
358 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
359 if (!err)
360 bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
361 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
362 if (!err)
363 bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
364 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
365
366
367 return err;
368}
369
370uint32
371bcmsdh_reg_read(void *sdh, uint32 addr, uint size)
372{
373 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
374 SDIOH_API_RC status;
375 uint32 word = 0;
376 uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
377
378 BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __FUNCTION__, addr));
379
380 if (!bcmsdh)
381 bcmsdh = l_bcmsdh;
382
383 ASSERT(bcmsdh->init_success);
384
385 if (bar0 != bcmsdh->sbwad) {
386 if (bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0))
387 return 0xFFFFFFFF;
388
389 bcmsdh->sbwad = bar0;
390 }
391
392 addr &= SBSDIO_SB_OFT_ADDR_MASK;
393 if (size == 4)
394 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
395
396 status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL,
397 SDIOH_READ, SDIO_FUNC_1, addr, &word, size);
398
399 bcmsdh->regfail = !(SDIOH_API_SUCCESS(status));
400
401 BCMSDH_INFO(("uint32data = 0x%x\n", word));
402
403 /* if ok, return appropriately masked word */
404 if (SDIOH_API_SUCCESS(status)) {
405 switch (size) {
406 case sizeof(uint8):
407 return (word & 0xff);
408 case sizeof(uint16):
409 return (word & 0xffff);
410 case sizeof(uint32):
411 return word;
412 default:
413 bcmsdh->regfail = TRUE;
414
415 }
416 }
417
418 /* otherwise, bad sdio access or invalid size */
419 BCMSDH_ERROR(("%s: error reading addr 0x%04x size %d\n", __FUNCTION__, addr, size));
420 return 0xFFFFFFFF;
421}
422
423uint32
424bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data)
425{
426 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
427 SDIOH_API_RC status;
428 uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
429 int err = 0;
430
431 BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
432 __FUNCTION__, addr, size*8, data));
433
434 if (!bcmsdh)
435 bcmsdh = l_bcmsdh;
436
437 ASSERT(bcmsdh->init_success);
438
439 if (bar0 != bcmsdh->sbwad) {
440 if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0)))
441 return err;
442
443 bcmsdh->sbwad = bar0;
444 }
445
446 addr &= SBSDIO_SB_OFT_ADDR_MASK;
447 if (size == 4)
448 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
449 status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1,
450 addr, &data, size);
451 bcmsdh->regfail = !(SDIOH_API_SUCCESS(status));
452
453 if (SDIOH_API_SUCCESS(status))
454 return 0;
455
456 BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n",
457 __FUNCTION__, data, addr, size));
458 return 0xFFFFFFFF;
459}
460
461bool
462bcmsdh_regfail(void *sdh)
463{
464 return ((bcmsdh_info_t *)sdh)->regfail;
465}
466
467int
468bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags,
469 uint8 *buf, uint nbytes, void *pkt,
470 bcmsdh_cmplt_fn_t complete, void *handle)
471{
472 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
473 SDIOH_API_RC status;
474 uint incr_fix;
475 uint width;
476 uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
477 int err = 0;
478
479 ASSERT(bcmsdh);
480 ASSERT(bcmsdh->init_success);
481
482 BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
483 __FUNCTION__, fn, addr, nbytes));
484
485 /* Async not implemented yet */
486 ASSERT(!(flags & SDIO_REQ_ASYNC));
487 if (flags & SDIO_REQ_ASYNC)
488 return BCME_UNSUPPORTED;
489
490 if (bar0 != bcmsdh->sbwad) {
491 if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0)))
492 return err;
493
494 bcmsdh->sbwad = bar0;
495 }
496
497 addr &= SBSDIO_SB_OFT_ADDR_MASK;
498
499 incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
500 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
501 if (width == 4)
502 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
503
504 status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
505 SDIOH_READ, fn, addr, width, nbytes, buf, pkt);
506
507 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
508}
509
510int
511bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags,
512 uint8 *buf, uint nbytes, void *pkt,
513 bcmsdh_cmplt_fn_t complete, void *handle)
514{
515 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
516 SDIOH_API_RC status;
517 uint incr_fix;
518 uint width;
519 uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
520 int err = 0;
521
522 ASSERT(bcmsdh);
523 ASSERT(bcmsdh->init_success);
524
525 BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
526 __FUNCTION__, fn, addr, nbytes));
527
528 /* Async not implemented yet */
529 ASSERT(!(flags & SDIO_REQ_ASYNC));
530 if (flags & SDIO_REQ_ASYNC)
531 return BCME_UNSUPPORTED;
532
533 if (bar0 != bcmsdh->sbwad) {
534 if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0)))
535 return err;
536
537 bcmsdh->sbwad = bar0;
538 }
539
540 addr &= SBSDIO_SB_OFT_ADDR_MASK;
541
542 incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
543 width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
544 if (width == 4)
545 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
546
547 status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
548 SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt);
549
550 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
551}
552
553int
554bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes)
555{
556 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
557 SDIOH_API_RC status;
558
559 ASSERT(bcmsdh);
560 ASSERT(bcmsdh->init_success);
561 ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0);
562
563 addr &= SBSDIO_SB_OFT_ADDR_MASK;
564 addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
565
566 status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC,
567 (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1,
568 addr, 4, nbytes, buf, NULL);
569
570 return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
571}
572
573int
574bcmsdh_abort(void *sdh, uint fn)
575{
576 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
577
578 return sdioh_abort(bcmsdh->sdioh, fn);
579}
580
581int
582bcmsdh_start(void *sdh, int stage)
583{
584 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
585
586 return sdioh_start(bcmsdh->sdioh, stage);
587}
588
589int
590bcmsdh_stop(void *sdh)
591{
592 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
593
594 return sdioh_stop(bcmsdh->sdioh);
595}
596
597
598int
599bcmsdh_query_device(void *sdh)
600{
601 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
602 bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0;
603 return (bcmsdh->vendevid);
604}
605
606uint
607bcmsdh_query_iofnum(void *sdh)
608{
609 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
610
611 if (!bcmsdh)
612 bcmsdh = l_bcmsdh;
613
614 return (sdioh_query_iofnum(bcmsdh->sdioh));
615}
616
617int
618bcmsdh_reset(bcmsdh_info_t *sdh)
619{
620 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
621
622 return sdioh_sdio_reset(bcmsdh->sdioh);
623}
624
625void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh)
626{
627 ASSERT(sdh);
628 return sdh->sdioh;
629}
630
631/* Function to pass device-status bits to DHD. */
632uint32
633bcmsdh_get_dstatus(void *sdh)
634{
635 return 0;
636}
637uint32
638bcmsdh_cur_sbwad(void *sdh)
639{
640 bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
641
642 if (!bcmsdh)
643 bcmsdh = l_bcmsdh;
644
645 return (bcmsdh->sbwad);
646}
647
648void
649bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev)
650{
651 return;
652}
diff --git a/drivers/net/wireless/bcm4329/bcmsdh_linux.c b/drivers/net/wireless/bcm4329/bcmsdh_linux.c
new file mode 100644
index 00000000000..22e1e9c7997
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmsdh_linux.c
@@ -0,0 +1,735 @@
1/*
2 * SDIO access interface for drivers - linux specific (pci only)
3 *
4 * Copyright (C) 1999-2010, 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.42.10.10.2.14.4.2 2010/09/15 00:30:11 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
39#include <osl.h>
40#include <pcicfg.h>
41#include <bcmdefs.h>
42#include <bcmdevs.h>
43
44#if defined(OOB_INTR_ONLY)
45#include <linux/irq.h>
46extern void dhdsdio_isr(void * args);
47#include <bcmutils.h>
48#include <dngl_stats.h>
49#include <dhd.h>
50#endif /* defined(OOB_INTR_ONLY) */
51#if defined(CONFIG_MACH_SANDGATE2G) || defined(CONFIG_MACH_LOGICPD_PXA270)
52#if !defined(BCMPLATFORM_BUS)
53#define BCMPLATFORM_BUS
54#endif /* !defined(BCMPLATFORM_BUS) */
55
56#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19))
57#include <linux/platform_device.h>
58#endif /* KERNEL_VERSION(2, 6, 19) */
59#endif /* CONFIG_MACH_SANDGATE2G || CONFIG_MACH_LOGICPD_PXA270 */
60
61/**
62 * SDIO Host Controller info
63 */
64typedef struct bcmsdh_hc bcmsdh_hc_t;
65
66struct bcmsdh_hc {
67 bcmsdh_hc_t *next;
68#ifdef BCMPLATFORM_BUS
69 struct device *dev; /* platform device handle */
70#else
71 struct pci_dev *dev; /* pci device handle */
72#endif /* BCMPLATFORM_BUS */
73 osl_t *osh;
74 void *regs; /* SDIO Host Controller address */
75 bcmsdh_info_t *sdh; /* SDIO Host Controller handle */
76 void *ch;
77 unsigned int oob_irq;
78 unsigned long oob_flags; /* OOB Host specifiction as edge and etc */
79 bool oob_irq_registered;
80#if defined(OOB_INTR_ONLY)
81 spinlock_t irq_lock;
82#endif
83};
84static bcmsdh_hc_t *sdhcinfo = NULL;
85
86/* driver info, initialized when bcmsdh_register is called */
87static bcmsdh_driver_t drvinfo = {NULL, NULL};
88
89/* debugging macros */
90#define SDLX_MSG(x)
91
92/**
93 * Checks to see if vendor and device IDs match a supported SDIO Host Controller.
94 */
95bool
96bcmsdh_chipmatch(uint16 vendor, uint16 device)
97{
98 /* Add other vendors and devices as required */
99
100#ifdef BCMSDIOH_STD
101 /* Check for Arasan host controller */
102 if (vendor == VENDOR_SI_IMAGE) {
103 return (TRUE);
104 }
105 /* Check for BRCM 27XX Standard host controller */
106 if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM) {
107 return (TRUE);
108 }
109 /* Check for BRCM Standard host controller */
110 if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM) {
111 return (TRUE);
112 }
113 /* Check for TI PCIxx21 Standard host controller */
114 if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI) {
115 return (TRUE);
116 }
117 if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI) {
118 return (TRUE);
119 }
120 /* Ricoh R5C822 Standard SDIO Host */
121 if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH) {
122 return (TRUE);
123 }
124 /* JMicron Standard SDIO Host */
125 if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON) {
126 return (TRUE);
127 }
128
129#endif /* BCMSDIOH_STD */
130#ifdef BCMSDIOH_SPI
131 /* This is the PciSpiHost. */
132 if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
133 printf("Found PCI SPI Host Controller\n");
134 return (TRUE);
135 }
136
137#endif /* BCMSDIOH_SPI */
138
139 return (FALSE);
140}
141
142#if defined(BCMPLATFORM_BUS)
143#if defined(BCMLXSDMMC)
144/* forward declarations */
145int bcmsdh_probe(struct device *dev);
146int bcmsdh_remove(struct device *dev);
147
148EXPORT_SYMBOL(bcmsdh_probe);
149EXPORT_SYMBOL(bcmsdh_remove);
150
151#else
152/* forward declarations */
153static int __devinit bcmsdh_probe(struct device *dev);
154static int __devexit bcmsdh_remove(struct device *dev);
155#endif /* BCMLXSDMMC */
156
157#ifndef BCMLXSDMMC
158static struct device_driver bcmsdh_driver = {
159 .name = "pxa2xx-mci",
160 .bus = &platform_bus_type,
161 .probe = bcmsdh_probe,
162 .remove = bcmsdh_remove,
163 .suspend = NULL,
164 .resume = NULL,
165 };
166#endif /* BCMLXSDMMC */
167
168#ifndef BCMLXSDMMC
169static
170#endif /* BCMLXSDMMC */
171int bcmsdh_probe(struct device *dev)
172{
173 osl_t *osh = NULL;
174 bcmsdh_hc_t *sdhc = NULL;
175 ulong regs = 0;
176 bcmsdh_info_t *sdh = NULL;
177#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
178 struct platform_device *pdev;
179 struct resource *r;
180#endif /* BCMLXSDMMC */
181 int irq = 0;
182 uint32 vendevid;
183 unsigned long irq_flags = 0;
184
185#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
186 pdev = to_platform_device(dev);
187 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
188 irq = platform_get_irq(pdev, 0);
189 if (!r || irq == NO_IRQ)
190 return -ENXIO;
191#endif /* BCMLXSDMMC */
192
193#if defined(OOB_INTR_ONLY)
194#ifdef HW_OOB
195 irq_flags = \
196 IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE;
197#else
198 irq_flags = IRQF_TRIGGER_FALLING;
199#endif /* HW_OOB */
200 irq = dhd_customer_oob_irq_map(&irq_flags);
201 if (irq < 0) {
202 SDLX_MSG(("%s: Host irq is not defined\n", __FUNCTION__));
203 return 1;
204 }
205#endif /* defined(OOB_INTR_ONLY) */
206 /* allocate SDIO Host Controller state info */
207 if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) {
208 SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
209 goto err;
210 }
211 if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
212 SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
213 __FUNCTION__,
214 MALLOCED(osh)));
215 goto err;
216 }
217 bzero(sdhc, sizeof(bcmsdh_hc_t));
218 sdhc->osh = osh;
219
220 sdhc->dev = (void *)dev;
221
222#ifdef BCMLXSDMMC
223 if (!(sdh = bcmsdh_attach(osh, (void *)0,
224 (void **)&regs, irq))) {
225 SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
226 goto err;
227 }
228#else
229 if (!(sdh = bcmsdh_attach(osh, (void *)r->start,
230 (void **)&regs, irq))) {
231 SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
232 goto err;
233 }
234#endif /* BCMLXSDMMC */
235 sdhc->sdh = sdh;
236 sdhc->oob_irq = irq;
237 sdhc->oob_flags = irq_flags;
238 sdhc->oob_irq_registered = FALSE; /* to make sure.. */
239#if defined(OOB_INTR_ONLY)
240 spin_lock_init(&sdhc->irq_lock);
241#endif
242
243 /* chain SDIO Host Controller info together */
244 sdhc->next = sdhcinfo;
245 sdhcinfo = sdhc;
246 /* Read the vendor/device ID from the CIS */
247 vendevid = bcmsdh_query_device(sdh);
248
249 /* try to attach to the target device */
250 if (!(sdhc->ch = drvinfo.attach((vendevid >> 16),
251 (vendevid & 0xFFFF), 0, 0, 0, 0,
252 (void *)regs, NULL, sdh, dev))) {
253 SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
254 goto err;
255 }
256
257 return 0;
258
259 /* error handling */
260err:
261 if (sdhc) {
262 if (sdhc->sdh)
263 bcmsdh_detach(sdhc->osh, sdhc->sdh);
264 MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
265 }
266 if (osh)
267 osl_detach(osh);
268 return -ENODEV;
269}
270
271#ifndef BCMLXSDMMC
272static
273#endif /* BCMLXSDMMC */
274int bcmsdh_remove(struct device *dev)
275{
276 bcmsdh_hc_t *sdhc, *prev;
277 osl_t *osh;
278
279 sdhc = sdhcinfo;
280 drvinfo.detach(sdhc->ch);
281 bcmsdh_detach(sdhc->osh, sdhc->sdh);
282 /* find the SDIO Host Controller state for this pdev and take it out from the list */
283 for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
284 if (sdhc->dev == (void *)dev) {
285 if (prev)
286 prev->next = sdhc->next;
287 else
288 sdhcinfo = NULL;
289 break;
290 }
291 prev = sdhc;
292 }
293 if (!sdhc) {
294 SDLX_MSG(("%s: failed\n", __FUNCTION__));
295 return 0;
296 }
297
298
299 /* release SDIO Host Controller info */
300 osh = sdhc->osh;
301 MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
302 osl_detach(osh);
303
304#if !defined(BCMLXSDMMC) || defined(OOB_INTR_ONLY)
305 dev_set_drvdata(dev, NULL);
306#endif /* !defined(BCMLXSDMMC) */
307
308 return 0;
309}
310
311#else /* BCMPLATFORM_BUS */
312
313#if !defined(BCMLXSDMMC)
314/* forward declarations for PCI probe and remove functions. */
315static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
316static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev);
317
318/**
319 * pci id table
320 */
321static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = {
322 { vendor: PCI_ANY_ID,
323 device: PCI_ANY_ID,
324 subvendor: PCI_ANY_ID,
325 subdevice: PCI_ANY_ID,
326 class: 0,
327 class_mask: 0,
328 driver_data: 0,
329 },
330 { 0, }
331};
332MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid);
333
334/**
335 * SDIO Host Controller pci driver info
336 */
337static struct pci_driver bcmsdh_pci_driver = {
338 node: {},
339 name: "bcmsdh",
340 id_table: bcmsdh_pci_devid,
341 probe: bcmsdh_pci_probe,
342 remove: bcmsdh_pci_remove,
343#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
344 save_state: NULL,
345#endif
346 suspend: NULL,
347 resume: NULL,
348};
349
350
351extern uint sd_pci_slot; /* Force detection to a particular PCI */
352 /* slot only . Allows for having multiple */
353 /* WL devices at once in a PC */
354 /* Only one instance of dhd will be */
355 /* usable at a time */
356 /* Upper word is bus number, */
357 /* lower word is slot number */
358 /* Default value of 0xFFFFffff turns this */
359 /* off */
360module_param(sd_pci_slot, uint, 0);
361
362
363/**
364 * Detect supported SDIO Host Controller and attach if found.
365 *
366 * Determine if the device described by pdev is a supported SDIO Host
367 * Controller. If so, attach to it and attach to the target device.
368 */
369static int __devinit
370bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
371{
372 osl_t *osh = NULL;
373 bcmsdh_hc_t *sdhc = NULL;
374 ulong regs;
375 bcmsdh_info_t *sdh = NULL;
376 int rc;
377
378 if (sd_pci_slot != 0xFFFFffff) {
379 if (pdev->bus->number != (sd_pci_slot>>16) ||
380 PCI_SLOT(pdev->devfn) != (sd_pci_slot&0xffff)) {
381 SDLX_MSG(("%s: %s: bus %X, slot %X, vend %X, dev %X\n",
382 __FUNCTION__,
383 bcmsdh_chipmatch(pdev->vendor, pdev->device) ?
384 "Found compatible SDIOHC" :
385 "Probing unknown device",
386 pdev->bus->number, PCI_SLOT(pdev->devfn),
387 pdev->vendor, pdev->device));
388 return -ENODEV;
389 }
390 SDLX_MSG(("%s: %s: bus %X, slot %X, vendor %X, device %X (good PCI location)\n",
391 __FUNCTION__,
392 bcmsdh_chipmatch(pdev->vendor, pdev->device) ?
393 "Using compatible SDIOHC" :
394 "WARNING, forced use of unkown device",
395 pdev->bus->number, PCI_SLOT(pdev->devfn),
396 pdev->vendor, pdev->device));
397 }
398
399 if ((pdev->vendor == VENDOR_TI) && ((pdev->device == PCIXX21_FLASHMEDIA_ID) ||
400 (pdev->device == PCIXX21_FLASHMEDIA0_ID))) {
401 uint32 config_reg;
402
403 SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n", __FUNCTION__));
404 if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
405 SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
406 goto err;
407 }
408
409 config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4);
410
411 /*
412 * Set MMC_SD_DIS bit in FlashMedia Controller.
413 * Disbling the SD/MMC Controller in the FlashMedia Controller
414 * allows the Standard SD Host Controller to take over control
415 * of the SD Slot.
416 */
417 config_reg |= 0x02;
418 OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg);
419 osl_detach(osh);
420 }
421 /* match this pci device with what we support */
422 /* we can't solely rely on this to believe it is our SDIO Host Controller! */
423 if (!bcmsdh_chipmatch(pdev->vendor, pdev->device)) {
424 return -ENODEV;
425 }
426
427 /* this is a pci device we might support */
428 SDLX_MSG(("%s: Found possible SDIO Host Controller: bus %d slot %d func %d irq %d\n",
429 __FUNCTION__,
430 pdev->bus->number, PCI_SLOT(pdev->devfn),
431 PCI_FUNC(pdev->devfn), pdev->irq));
432
433 /* use bcmsdh_query_device() to get the vendor ID of the target device so
434 * it will eventually appear in the Broadcom string on the console
435 */
436
437 /* allocate SDIO Host Controller state info */
438 if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
439 SDLX_MSG(("%s: osl_attach failed\n", __FUNCTION__));
440 goto err;
441 }
442 if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
443 SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
444 __FUNCTION__,
445 MALLOCED(osh)));
446 goto err;
447 }
448 bzero(sdhc, sizeof(bcmsdh_hc_t));
449 sdhc->osh = osh;
450
451 sdhc->dev = pdev;
452
453 /* map to address where host can access */
454 pci_set_master(pdev);
455 rc = pci_enable_device(pdev);
456 if (rc) {
457 SDLX_MSG(("%s: Cannot enable PCI device\n", __FUNCTION__));
458 goto err;
459 }
460 if (!(sdh = bcmsdh_attach(osh, (void *)(uintptr)pci_resource_start(pdev, 0),
461 (void **)&regs, pdev->irq))) {
462 SDLX_MSG(("%s: bcmsdh_attach failed\n", __FUNCTION__));
463 goto err;
464 }
465
466 sdhc->sdh = sdh;
467
468 /* try to attach to the target device */
469 if (!(sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */
470 bcmsdh_query_device(sdh) & 0xFFFF, 0, 0, 0, 0,
471 (void *)regs, NULL, sdh, pdev->dev))) {
472 SDLX_MSG(("%s: device attach failed\n", __FUNCTION__));
473 goto err;
474 }
475
476 /* chain SDIO Host Controller info together */
477 sdhc->next = sdhcinfo;
478 sdhcinfo = sdhc;
479
480 return 0;
481
482 /* error handling */
483err:
484 if (sdhc->sdh)
485 bcmsdh_detach(sdhc->osh, sdhc->sdh);
486 if (sdhc)
487 MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
488 if (osh)
489 osl_detach(osh);
490 return -ENODEV;
491}
492
493
494/**
495 * Detach from target devices and SDIO Host Controller
496 */
497static void __devexit
498bcmsdh_pci_remove(struct pci_dev *pdev)
499{
500 bcmsdh_hc_t *sdhc, *prev;
501 osl_t *osh;
502
503 /* find the SDIO Host Controller state for this pdev and take it out from the list */
504 for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
505 if (sdhc->dev == pdev) {
506 if (prev)
507 prev->next = sdhc->next;
508 else
509 sdhcinfo = NULL;
510 break;
511 }
512 prev = sdhc;
513 }
514 if (!sdhc)
515 return;
516
517 drvinfo.detach(sdhc->ch);
518
519 bcmsdh_detach(sdhc->osh, sdhc->sdh);
520
521 /* release SDIO Host Controller info */
522 osh = sdhc->osh;
523 MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
524 osl_detach(osh);
525}
526#endif /* BCMLXSDMMC */
527#endif /* BCMPLATFORM_BUS */
528
529extern int sdio_function_init(void);
530
531int
532bcmsdh_register(bcmsdh_driver_t *driver)
533{
534 int error = 0;
535
536 drvinfo = *driver;
537
538#if defined(BCMPLATFORM_BUS)
539#if defined(BCMLXSDMMC)
540 SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
541 error = sdio_function_init();
542#else
543 SDLX_MSG(("Intel PXA270 SDIO Driver\n"));
544 error = driver_register(&bcmsdh_driver);
545#endif /* defined(BCMLXSDMMC) */
546 return error;
547#endif /* defined(BCMPLATFORM_BUS) */
548
549#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
550#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
551 if (!(error = pci_module_init(&bcmsdh_pci_driver)))
552 return 0;
553#else
554 if (!(error = pci_register_driver(&bcmsdh_pci_driver)))
555 return 0;
556#endif
557
558 SDLX_MSG(("%s: pci_module_init failed 0x%x\n", __FUNCTION__, error));
559#endif /* BCMPLATFORM_BUS */
560
561 return error;
562}
563
564extern void sdio_function_cleanup(void);
565
566void
567bcmsdh_unregister(void)
568{
569#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
570 if (bcmsdh_pci_driver.node.next)
571#endif
572
573#if defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
574 driver_unregister(&bcmsdh_driver);
575#endif
576#if defined(BCMLXSDMMC)
577 sdio_function_cleanup();
578#endif /* BCMLXSDMMC */
579#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
580 pci_unregister_driver(&bcmsdh_pci_driver);
581#endif /* BCMPLATFORM_BUS */
582}
583
584#if defined(OOB_INTR_ONLY)
585void bcmsdh_oob_intr_set(bool enable)
586{
587 static bool curstate = 1;
588 unsigned long flags;
589
590 spin_lock_irqsave(&sdhcinfo->irq_lock, flags);
591 if (curstate != enable) {
592 if (enable)
593 enable_irq(sdhcinfo->oob_irq);
594 else
595 disable_irq_nosync(sdhcinfo->oob_irq);
596 curstate = enable;
597 }
598 spin_unlock_irqrestore(&sdhcinfo->irq_lock, flags);
599}
600
601static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
602{
603 dhd_pub_t *dhdp;
604
605 dhdp = (dhd_pub_t *)dev_get_drvdata(sdhcinfo->dev);
606
607 bcmsdh_oob_intr_set(0);
608
609 if (dhdp == NULL) {
610 SDLX_MSG(("Out of band GPIO interrupt fired way too early\n"));
611 return IRQ_HANDLED;
612 }
613
614 dhdsdio_isr((void *)dhdp->bus);
615
616 return IRQ_HANDLED;
617}
618
619int bcmsdh_register_oob_intr(void * dhdp)
620{
621 int error = 0;
622
623 SDLX_MSG(("%s Enter\n", __FUNCTION__));
624
625/* Example of HW_OOB for HW2: please refer to your host specifiction */
626/* sdhcinfo->oob_flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE; */
627
628 dev_set_drvdata(sdhcinfo->dev, dhdp);
629
630 if (!sdhcinfo->oob_irq_registered) {
631 SDLX_MSG(("%s IRQ=%d Type=%X \n", __FUNCTION__, \
632 (int)sdhcinfo->oob_irq, (int)sdhcinfo->oob_flags));
633 /* Refer to customer Host IRQ docs about proper irqflags definition */
634 error = request_irq(sdhcinfo->oob_irq, wlan_oob_irq, sdhcinfo->oob_flags,
635 "bcmsdh_sdmmc", NULL);
636 if (error)
637 return -ENODEV;
638
639 enable_irq_wake(sdhcinfo->oob_irq);
640 sdhcinfo->oob_irq_registered = TRUE;
641 }
642
643 return 0;
644}
645
646void bcmsdh_set_irq(int flag)
647{
648 if (sdhcinfo->oob_irq_registered) {
649 SDLX_MSG(("%s Flag = %d", __FUNCTION__, flag));
650 if (flag) {
651 enable_irq(sdhcinfo->oob_irq);
652 enable_irq_wake(sdhcinfo->oob_irq);
653 } else {
654 disable_irq_wake(sdhcinfo->oob_irq);
655 disable_irq(sdhcinfo->oob_irq);
656 }
657 }
658}
659
660void bcmsdh_unregister_oob_intr(void)
661{
662 SDLX_MSG(("%s: Enter\n", __FUNCTION__));
663
664 if (sdhcinfo->oob_irq_registered) {
665 disable_irq_wake(sdhcinfo->oob_irq);
666 disable_irq(sdhcinfo->oob_irq); /* just in case.. */
667 free_irq(sdhcinfo->oob_irq, NULL);
668 sdhcinfo->oob_irq_registered = FALSE;
669 }
670}
671#endif /* defined(OOB_INTR_ONLY) */
672/* Module parameters specific to each host-controller driver */
673
674extern uint sd_msglevel; /* Debug message level */
675module_param(sd_msglevel, uint, 0);
676
677extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */
678module_param(sd_power, uint, 0);
679
680extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */
681module_param(sd_clock, uint, 0);
682
683extern uint sd_divisor; /* Divisor (-1 means external clock) */
684module_param(sd_divisor, uint, 0);
685
686extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */
687module_param(sd_sdmode, uint, 0);
688
689extern uint sd_hiok; /* Ok to use hi-speed mode */
690module_param(sd_hiok, uint, 0);
691
692extern uint sd_f2_blocksize;
693module_param(sd_f2_blocksize, int, 0);
694
695
696#ifdef BCMSDH_MODULE
697EXPORT_SYMBOL(bcmsdh_attach);
698EXPORT_SYMBOL(bcmsdh_detach);
699EXPORT_SYMBOL(bcmsdh_intr_query);
700EXPORT_SYMBOL(bcmsdh_intr_enable);
701EXPORT_SYMBOL(bcmsdh_intr_disable);
702EXPORT_SYMBOL(bcmsdh_intr_reg);
703EXPORT_SYMBOL(bcmsdh_intr_dereg);
704
705#if defined(DHD_DEBUG)
706EXPORT_SYMBOL(bcmsdh_intr_pending);
707#endif
708
709EXPORT_SYMBOL(bcmsdh_devremove_reg);
710EXPORT_SYMBOL(bcmsdh_cfg_read);
711EXPORT_SYMBOL(bcmsdh_cfg_write);
712EXPORT_SYMBOL(bcmsdh_cis_read);
713EXPORT_SYMBOL(bcmsdh_reg_read);
714EXPORT_SYMBOL(bcmsdh_reg_write);
715EXPORT_SYMBOL(bcmsdh_regfail);
716EXPORT_SYMBOL(bcmsdh_send_buf);
717EXPORT_SYMBOL(bcmsdh_recv_buf);
718
719EXPORT_SYMBOL(bcmsdh_rwdata);
720EXPORT_SYMBOL(bcmsdh_abort);
721EXPORT_SYMBOL(bcmsdh_query_device);
722EXPORT_SYMBOL(bcmsdh_query_iofnum);
723EXPORT_SYMBOL(bcmsdh_iovar_op);
724EXPORT_SYMBOL(bcmsdh_register);
725EXPORT_SYMBOL(bcmsdh_unregister);
726EXPORT_SYMBOL(bcmsdh_chipmatch);
727EXPORT_SYMBOL(bcmsdh_reset);
728
729EXPORT_SYMBOL(bcmsdh_get_dstatus);
730EXPORT_SYMBOL(bcmsdh_cfg_read_word);
731EXPORT_SYMBOL(bcmsdh_cfg_write_word);
732EXPORT_SYMBOL(bcmsdh_cur_sbwad);
733EXPORT_SYMBOL(bcmsdh_chipinfo);
734
735#endif /* BCMSDH_MODULE */
diff --git a/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c
new file mode 100644
index 00000000000..031367b8f18
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc.c
@@ -0,0 +1,1304 @@
1/*
2 * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
3 *
4 * Copyright (C) 1999-2010, 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,v 1.1.2.5.6.30.4.1 2010/09/02 23:12:21 Exp $
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> /* 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 sdio_claim_host(gInstance->func[1]);
202 sdio_disable_func(gInstance->func[1]);
203 sdio_release_host(gInstance->func[1]);
204
205 /* deregister irq */
206 sdioh_sdmmc_osfree(sd);
207
208 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
209 }
210 return SDIOH_API_RC_SUCCESS;
211}
212
213#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
214
215extern SDIOH_API_RC
216sdioh_enable_func_intr(void)
217{
218 uint8 reg;
219 int err;
220
221 if (gInstance->func[0]) {
222 sdio_claim_host(gInstance->func[0]);
223
224 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
225 if (err) {
226 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
227 sdio_release_host(gInstance->func[0]);
228 return SDIOH_API_RC_FAIL;
229 }
230
231 /* Enable F1 and F2 interrupts, set master enable */
232 reg |= (INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN | INTR_CTL_MASTER_EN);
233
234 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
235 sdio_release_host(gInstance->func[0]);
236
237 if (err) {
238 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
239 return SDIOH_API_RC_FAIL;
240 }
241 }
242
243 return SDIOH_API_RC_SUCCESS;
244}
245
246extern SDIOH_API_RC
247sdioh_disable_func_intr(void)
248{
249 uint8 reg;
250 int err;
251
252 if (gInstance->func[0]) {
253 sdio_claim_host(gInstance->func[0]);
254 reg = sdio_readb(gInstance->func[0], SDIOD_CCCR_INTEN, &err);
255 if (err) {
256 sd_err(("%s: error for read SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
257 sdio_release_host(gInstance->func[0]);
258 return SDIOH_API_RC_FAIL;
259 }
260
261 reg &= ~(INTR_CTL_FUNC1_EN | INTR_CTL_FUNC2_EN);
262 /* Disable master interrupt with the last function interrupt */
263 if (!(reg & 0xFE))
264 reg = 0;
265 sdio_writeb(gInstance->func[0], reg, SDIOD_CCCR_INTEN, &err);
266
267 sdio_release_host(gInstance->func[0]);
268 if (err) {
269 sd_err(("%s: error for write SDIO_CCCR_IENx : 0x%x\n", __FUNCTION__, err));
270 return SDIOH_API_RC_FAIL;
271 }
272 }
273 return SDIOH_API_RC_SUCCESS;
274}
275#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
276
277/* Configure callback to client when we recieve client interrupt */
278extern SDIOH_API_RC
279sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
280{
281 sd_trace(("%s: Entering\n", __FUNCTION__));
282 if (fn == NULL) {
283 sd_err(("%s: interrupt handler is NULL, not registering\n", __FUNCTION__));
284 return SDIOH_API_RC_FAIL;
285 }
286#if !defined(OOB_INTR_ONLY)
287 sd->intr_handler = fn;
288 sd->intr_handler_arg = argh;
289 sd->intr_handler_valid = TRUE;
290
291 /* register and unmask irq */
292 if (gInstance->func[2]) {
293 sdio_claim_host(gInstance->func[2]);
294 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
295 sdio_release_host(gInstance->func[2]);
296 }
297
298 if (gInstance->func[1]) {
299 sdio_claim_host(gInstance->func[1]);
300 sdio_claim_irq(gInstance->func[1], IRQHandler);
301 sdio_release_host(gInstance->func[1]);
302 }
303#elif defined(HW_OOB)
304 sdioh_enable_func_intr();
305#endif /* defined(OOB_INTR_ONLY) */
306 return SDIOH_API_RC_SUCCESS;
307}
308
309extern SDIOH_API_RC
310sdioh_interrupt_deregister(sdioh_info_t *sd)
311{
312 sd_trace(("%s: Entering\n", __FUNCTION__));
313
314#if !defined(OOB_INTR_ONLY)
315 if (gInstance->func[1]) {
316 /* register and unmask irq */
317 sdio_claim_host(gInstance->func[1]);
318 sdio_release_irq(gInstance->func[1]);
319 sdio_release_host(gInstance->func[1]);
320 }
321
322 if (gInstance->func[2]) {
323 /* Claim host controller F2 */
324 sdio_claim_host(gInstance->func[2]);
325 sdio_release_irq(gInstance->func[2]);
326 /* Release host controller F2 */
327 sdio_release_host(gInstance->func[2]);
328 }
329
330 sd->intr_handler_valid = FALSE;
331 sd->intr_handler = NULL;
332 sd->intr_handler_arg = NULL;
333#elif defined(HW_OOB)
334 sdioh_disable_func_intr();
335#endif /* !defined(OOB_INTR_ONLY) */
336 return SDIOH_API_RC_SUCCESS;
337}
338
339extern SDIOH_API_RC
340sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
341{
342 sd_trace(("%s: Entering\n", __FUNCTION__));
343 *onoff = sd->client_intr_enabled;
344 return SDIOH_API_RC_SUCCESS;
345}
346
347#if defined(DHD_DEBUG)
348extern bool
349sdioh_interrupt_pending(sdioh_info_t *sd)
350{
351 return (0);
352}
353#endif
354
355uint
356sdioh_query_iofnum(sdioh_info_t *sd)
357{
358 return sd->num_funcs;
359}
360
361/* IOVar table */
362enum {
363 IOV_MSGLEVEL = 1,
364 IOV_BLOCKMODE,
365 IOV_BLOCKSIZE,
366 IOV_DMA,
367 IOV_USEINTS,
368 IOV_NUMINTS,
369 IOV_NUMLOCALINTS,
370 IOV_HOSTREG,
371 IOV_DEVREG,
372 IOV_DIVISOR,
373 IOV_SDMODE,
374 IOV_HISPEED,
375 IOV_HCIREGS,
376 IOV_POWER,
377 IOV_CLOCK,
378 IOV_RXCHAIN
379};
380
381const bcm_iovar_t sdioh_iovars[] = {
382 {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
383 {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 },
384 {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */
385 {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 },
386 {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 },
387 {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 },
388 {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 },
389 {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
390 {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
391 {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 },
392 {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 },
393 {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 },
394 {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100},
395 {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0 },
396 {"sd_rxchain", IOV_RXCHAIN, 0, IOVT_BOOL, 0 },
397 {NULL, 0, 0, 0, 0 }
398};
399
400int
401sdioh_iovar_op(sdioh_info_t *si, const char *name,
402 void *params, int plen, void *arg, int len, bool set)
403{
404 const bcm_iovar_t *vi = NULL;
405 int bcmerror = 0;
406 int val_size;
407 int32 int_val = 0;
408 bool bool_val;
409 uint32 actionid;
410
411 ASSERT(name);
412 ASSERT(len >= 0);
413
414 /* Get must have return space; Set does not take qualifiers */
415 ASSERT(set || (arg && len));
416 ASSERT(!set || (!params && !plen));
417
418 sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
419
420 if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
421 bcmerror = BCME_UNSUPPORTED;
422 goto exit;
423 }
424
425 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
426 goto exit;
427
428 /* Set up params so get and set can share the convenience variables */
429 if (params == NULL) {
430 params = arg;
431 plen = len;
432 }
433
434 if (vi->type == IOVT_VOID)
435 val_size = 0;
436 else if (vi->type == IOVT_BUFFER)
437 val_size = len;
438 else
439 val_size = sizeof(int);
440
441 if (plen >= (int)sizeof(int_val))
442 bcopy(params, &int_val, sizeof(int_val));
443
444 bool_val = (int_val != 0) ? TRUE : FALSE;
445
446 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
447 switch (actionid) {
448 case IOV_GVAL(IOV_MSGLEVEL):
449 int_val = (int32)sd_msglevel;
450 bcopy(&int_val, arg, val_size);
451 break;
452
453 case IOV_SVAL(IOV_MSGLEVEL):
454 sd_msglevel = int_val;
455 break;
456
457 case IOV_GVAL(IOV_BLOCKMODE):
458 int_val = (int32)si->sd_blockmode;
459 bcopy(&int_val, arg, val_size);
460 break;
461
462 case IOV_SVAL(IOV_BLOCKMODE):
463 si->sd_blockmode = (bool)int_val;
464 /* Haven't figured out how to make non-block mode with DMA */
465 break;
466
467 case IOV_GVAL(IOV_BLOCKSIZE):
468 if ((uint32)int_val > si->num_funcs) {
469 bcmerror = BCME_BADARG;
470 break;
471 }
472 int_val = (int32)si->client_block_size[int_val];
473 bcopy(&int_val, arg, val_size);
474 break;
475
476 case IOV_SVAL(IOV_BLOCKSIZE):
477 {
478 uint func = ((uint32)int_val >> 16);
479 uint blksize = (uint16)int_val;
480 uint maxsize;
481
482 if (func > si->num_funcs) {
483 bcmerror = BCME_BADARG;
484 break;
485 }
486
487 switch (func) {
488 case 0: maxsize = 32; break;
489 case 1: maxsize = BLOCK_SIZE_4318; break;
490 case 2: maxsize = BLOCK_SIZE_4328; break;
491 default: maxsize = 0;
492 }
493 if (blksize > maxsize) {
494 bcmerror = BCME_BADARG;
495 break;
496 }
497 if (!blksize) {
498 blksize = maxsize;
499 }
500
501 /* Now set it */
502 si->client_block_size[func] = blksize;
503
504 break;
505 }
506
507 case IOV_GVAL(IOV_RXCHAIN):
508 int_val = FALSE;
509 bcopy(&int_val, arg, val_size);
510 break;
511
512 case IOV_GVAL(IOV_DMA):
513 int_val = (int32)si->sd_use_dma;
514 bcopy(&int_val, arg, val_size);
515 break;
516
517 case IOV_SVAL(IOV_DMA):
518 si->sd_use_dma = (bool)int_val;
519 break;
520
521 case IOV_GVAL(IOV_USEINTS):
522 int_val = (int32)si->use_client_ints;
523 bcopy(&int_val, arg, val_size);
524 break;
525
526 case IOV_SVAL(IOV_USEINTS):
527 si->use_client_ints = (bool)int_val;
528 if (si->use_client_ints)
529 si->intmask |= CLIENT_INTR;
530 else
531 si->intmask &= ~CLIENT_INTR;
532
533 break;
534
535 case IOV_GVAL(IOV_DIVISOR):
536 int_val = (uint32)sd_divisor;
537 bcopy(&int_val, arg, val_size);
538 break;
539
540 case IOV_SVAL(IOV_DIVISOR):
541 sd_divisor = int_val;
542 break;
543
544 case IOV_GVAL(IOV_POWER):
545 int_val = (uint32)sd_power;
546 bcopy(&int_val, arg, val_size);
547 break;
548
549 case IOV_SVAL(IOV_POWER):
550 sd_power = int_val;
551 break;
552
553 case IOV_GVAL(IOV_CLOCK):
554 int_val = (uint32)sd_clock;
555 bcopy(&int_val, arg, val_size);
556 break;
557
558 case IOV_SVAL(IOV_CLOCK):
559 sd_clock = int_val;
560 break;
561
562 case IOV_GVAL(IOV_SDMODE):
563 int_val = (uint32)sd_sdmode;
564 bcopy(&int_val, arg, val_size);
565 break;
566
567 case IOV_SVAL(IOV_SDMODE):
568 sd_sdmode = int_val;
569 break;
570
571 case IOV_GVAL(IOV_HISPEED):
572 int_val = (uint32)sd_hiok;
573 bcopy(&int_val, arg, val_size);
574 break;
575
576 case IOV_SVAL(IOV_HISPEED):
577 sd_hiok = int_val;
578 break;
579
580 case IOV_GVAL(IOV_NUMINTS):
581 int_val = (int32)si->intrcount;
582 bcopy(&int_val, arg, val_size);
583 break;
584
585 case IOV_GVAL(IOV_NUMLOCALINTS):
586 int_val = (int32)0;
587 bcopy(&int_val, arg, val_size);
588 break;
589
590 case IOV_GVAL(IOV_HOSTREG):
591 {
592 sdreg_t *sd_ptr = (sdreg_t *)params;
593
594 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
595 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
596 bcmerror = BCME_BADARG;
597 break;
598 }
599
600 sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__,
601 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
602 sd_ptr->offset));
603 if (sd_ptr->offset & 1)
604 int_val = 8; /* sdioh_sdmmc_rreg8(si, sd_ptr->offset); */
605 else if (sd_ptr->offset & 2)
606 int_val = 16; /* sdioh_sdmmc_rreg16(si, sd_ptr->offset); */
607 else
608 int_val = 32; /* sdioh_sdmmc_rreg(si, sd_ptr->offset); */
609
610 bcopy(&int_val, arg, sizeof(int_val));
611 break;
612 }
613
614 case IOV_SVAL(IOV_HOSTREG):
615 {
616 sdreg_t *sd_ptr = (sdreg_t *)params;
617
618 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
619 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
620 bcmerror = BCME_BADARG;
621 break;
622 }
623
624 sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value,
625 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
626 sd_ptr->offset));
627 break;
628 }
629
630 case IOV_GVAL(IOV_DEVREG):
631 {
632 sdreg_t *sd_ptr = (sdreg_t *)params;
633 uint8 data = 0;
634
635 if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
636 bcmerror = BCME_SDIO_ERROR;
637 break;
638 }
639
640 int_val = (int)data;
641 bcopy(&int_val, arg, sizeof(int_val));
642 break;
643 }
644
645 case IOV_SVAL(IOV_DEVREG):
646 {
647 sdreg_t *sd_ptr = (sdreg_t *)params;
648 uint8 data = (uint8)sd_ptr->value;
649
650 if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
651 bcmerror = BCME_SDIO_ERROR;
652 break;
653 }
654 break;
655 }
656
657 default:
658 bcmerror = BCME_UNSUPPORTED;
659 break;
660 }
661exit:
662
663 return bcmerror;
664}
665
666#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
667
668SDIOH_API_RC
669sdioh_enable_hw_oob_intr(sdioh_info_t *sd, bool enable)
670{
671 SDIOH_API_RC status;
672 uint8 data;
673
674 if (enable)
675 data = 3; /* enable hw oob interrupt */
676 else
677 data = 4; /* disable hw oob interrupt */
678 data |= 4; /* Active HIGH */
679
680 status = sdioh_request_byte(sd, SDIOH_WRITE, 0, 0xf2, &data);
681 return status;
682}
683#endif /* defined(OOB_INTR_ONLY) && defined(HW_OOB) */
684
685extern SDIOH_API_RC
686sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
687{
688 SDIOH_API_RC status;
689 /* No lock needed since sdioh_request_byte does locking */
690 status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
691 return status;
692}
693
694extern SDIOH_API_RC
695sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
696{
697 /* No lock needed since sdioh_request_byte does locking */
698 SDIOH_API_RC status;
699 status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
700 return status;
701}
702
703static int
704sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr)
705{
706 /* read 24 bits and return valid 17 bit addr */
707 int i;
708 uint32 scratch, regdata;
709 uint8 *ptr = (uint8 *)&scratch;
710 for (i = 0; i < 3; i++) {
711 if ((sdioh_sdmmc_card_regread (sd, 0, regaddr, 1, &regdata)) != SUCCESS)
712 sd_err(("%s: Can't read!\n", __FUNCTION__));
713
714 *ptr++ = (uint8) regdata;
715 regaddr++;
716 }
717
718 /* Only the lower 17-bits are valid */
719 scratch = ltoh32(scratch);
720 scratch &= 0x0001FFFF;
721 return (scratch);
722}
723
724extern SDIOH_API_RC
725sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
726{
727 uint32 count;
728 int offset;
729 uint32 foo;
730 uint8 *cis = cisd;
731
732 sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
733
734 if (!sd->func_cis_ptr[func]) {
735 bzero(cis, length);
736 sd_err(("%s: no func_cis_ptr[%d]\n", __FUNCTION__, func));
737 return SDIOH_API_RC_FAIL;
738 }
739
740 sd_err(("%s: func_cis_ptr[%d]=0x%04x\n", __FUNCTION__, func, sd->func_cis_ptr[func]));
741
742 for (count = 0; count < length; count++) {
743 offset = sd->func_cis_ptr[func] + count;
744 if (sdioh_sdmmc_card_regread (sd, 0, offset, 1, &foo) < 0) {
745 sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
746 return SDIOH_API_RC_FAIL;
747 }
748
749 *cis = (uint8)(foo & 0xff);
750 cis++;
751 }
752
753 return SDIOH_API_RC_SUCCESS;
754}
755
756extern SDIOH_API_RC
757sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
758{
759 int err_ret;
760
761 sd_info(("%s: rw=%d, func=%d, addr=0x%05x\n", __FUNCTION__, rw, func, regaddr));
762
763 DHD_PM_RESUME_WAIT(sdioh_request_byte_wait);
764 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
765 if(rw) { /* CMD52 Write */
766 if (func == 0) {
767 /* Can only directly write to some F0 registers. Handle F2 enable
768 * as a special case.
769 */
770 if (regaddr == SDIOD_CCCR_IOEN) {
771 if (gInstance->func[2]) {
772 sdio_claim_host(gInstance->func[2]);
773 if (*byte & SDIO_FUNC_ENABLE_2) {
774 /* Enable Function 2 */
775 err_ret = sdio_enable_func(gInstance->func[2]);
776 if (err_ret) {
777 sd_err(("bcmsdh_sdmmc: enable F2 failed:%d",
778 err_ret));
779 }
780 } else {
781 /* Disable Function 2 */
782 err_ret = sdio_disable_func(gInstance->func[2]);
783 if (err_ret) {
784 sd_err(("bcmsdh_sdmmc: Disab F2 failed:%d",
785 err_ret));
786 }
787 }
788 sdio_release_host(gInstance->func[2]);
789 }
790 }
791#if defined(MMC_SDIO_ABORT)
792 /* to allow abort command through F1 */
793 else if (regaddr == SDIOD_CCCR_IOABORT) {
794 sdio_claim_host(gInstance->func[func]);
795 /*
796 * this sdio_f0_writeb() can be replaced with another api
797 * depending upon MMC driver change.
798 * As of this time, this is temporaray one
799 */
800 sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
801 sdio_release_host(gInstance->func[func]);
802 }
803#endif /* MMC_SDIO_ABORT */
804 else if (regaddr < 0xF0) {
805 sd_err(("bcmsdh_sdmmc: F0 Wr:0x%02x: write disallowed\n", regaddr));
806 } else {
807 /* Claim host controller, perform F0 write, and release */
808 sdio_claim_host(gInstance->func[func]);
809 sdio_f0_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
810 sdio_release_host(gInstance->func[func]);
811 }
812 } else {
813 /* Claim host controller, perform Fn write, and release */
814 sdio_claim_host(gInstance->func[func]);
815 sdio_writeb(gInstance->func[func], *byte, regaddr, &err_ret);
816 sdio_release_host(gInstance->func[func]);
817 }
818 } else { /* CMD52 Read */
819 /* Claim host controller, perform Fn read, and release */
820 sdio_claim_host(gInstance->func[func]);
821
822 if (func == 0) {
823 *byte = sdio_f0_readb(gInstance->func[func], regaddr, &err_ret);
824 } else {
825 *byte = sdio_readb(gInstance->func[func], regaddr, &err_ret);
826 }
827
828 sdio_release_host(gInstance->func[func]);
829 }
830
831 if (err_ret) {
832 sd_err(("bcmsdh_sdmmc: Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
833 rw ? "Write" : "Read", func, regaddr, *byte, err_ret));
834 }
835
836 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
837}
838
839extern SDIOH_API_RC
840sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
841 uint32 *word, uint nbytes)
842{
843 int err_ret = SDIOH_API_RC_FAIL;
844
845 if (func == 0) {
846 sd_err(("%s: Only CMD52 allowed to F0.\n", __FUNCTION__));
847 return SDIOH_API_RC_FAIL;
848 }
849
850 sd_info(("%s: cmd_type=%d, rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
851 __FUNCTION__, cmd_type, rw, func, addr, nbytes));
852
853 DHD_PM_RESUME_WAIT(sdioh_request_word_wait);
854 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
855 /* Claim host controller */
856 sdio_claim_host(gInstance->func[func]);
857
858 if(rw) { /* CMD52 Write */
859 if (nbytes == 4) {
860 sdio_writel(gInstance->func[func], *word, addr, &err_ret);
861 } else if (nbytes == 2) {
862 sdio_writew(gInstance->func[func], (*word & 0xFFFF), addr, &err_ret);
863 } else {
864 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
865 }
866 } else { /* CMD52 Read */
867 if (nbytes == 4) {
868 *word = sdio_readl(gInstance->func[func], addr, &err_ret);
869 } else if (nbytes == 2) {
870 *word = sdio_readw(gInstance->func[func], addr, &err_ret) & 0xFFFF;
871 } else {
872 sd_err(("%s: Invalid nbytes: %d\n", __FUNCTION__, nbytes));
873 }
874 }
875
876 /* Release host controller */
877 sdio_release_host(gInstance->func[func]);
878
879 if (err_ret) {
880 sd_err(("bcmsdh_sdmmc: Failed to %s word, Err: 0x%08x",
881 rw ? "Write" : "Read", err_ret));
882 }
883
884 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
885}
886
887static SDIOH_API_RC
888sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func,
889 uint addr, void *pkt)
890{
891 bool fifo = (fix_inc == SDIOH_DATA_FIX);
892 uint32 SGCount = 0;
893 int err_ret = 0;
894
895 void *pnext;
896
897 sd_trace(("%s: Enter\n", __FUNCTION__));
898
899 ASSERT(pkt);
900 DHD_PM_RESUME_WAIT(sdioh_request_packet_wait);
901 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
902
903 /* Claim host controller */
904 sdio_claim_host(gInstance->func[func]);
905 for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) {
906 uint pkt_len = PKTLEN(sd->osh, pnext);
907 pkt_len += 3;
908 pkt_len &= 0xFFFFFFFC;
909
910#ifdef CONFIG_MMC_MSM7X00A
911 if ((pkt_len % 64) == 32) {
912 sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__));
913 pkt_len += 32;
914 }
915#endif /* CONFIG_MMC_MSM7X00A */
916 /* Make sure the packet is aligned properly. If it isn't, then this
917 * is the fault of sdioh_request_buffer() which is supposed to give
918 * us something we can work with.
919 */
920 ASSERT(((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) == 0);
921
922 if ((write) && (!fifo)) {
923 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
924 ((uint8*)PKTDATA(sd->osh, pnext)),
925 pkt_len);
926 } else if (write) {
927 err_ret = sdio_memcpy_toio(gInstance->func[func], addr,
928 ((uint8*)PKTDATA(sd->osh, pnext)),
929 pkt_len);
930 } else if (fifo) {
931 err_ret = sdio_readsb(gInstance->func[func],
932 ((uint8*)PKTDATA(sd->osh, pnext)),
933 addr,
934 pkt_len);
935 } else {
936 err_ret = sdio_memcpy_fromio(gInstance->func[func],
937 ((uint8*)PKTDATA(sd->osh, pnext)),
938 addr,
939 pkt_len);
940 }
941
942 if (err_ret) {
943 sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n",
944 __FUNCTION__,
945 (write) ? "TX" : "RX",
946 pnext, SGCount, addr, pkt_len, err_ret));
947 } else {
948 sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n",
949 __FUNCTION__,
950 (write) ? "TX" : "RX",
951 pnext, SGCount, addr, pkt_len));
952 }
953
954 if (!fifo) {
955 addr += pkt_len;
956 }
957 SGCount ++;
958
959 }
960
961 /* Release host controller */
962 sdio_release_host(gInstance->func[func]);
963
964 sd_trace(("%s: Exit\n", __FUNCTION__));
965 return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
966}
967
968
969/*
970 * This function takes a buffer or packet, and fixes everything up so that in the
971 * end, a DMA-able packet is created.
972 *
973 * A buffer does not have an associated packet pointer, and may or may not be aligned.
974 * A packet may consist of a single packet, or a packet chain. If it is a packet chain,
975 * then all the packets in the chain must be properly aligned. If the packet data is not
976 * aligned, then there may only be one packet, and in this case, it is copied to a new
977 * aligned packet.
978 *
979 */
980extern SDIOH_API_RC
981sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, uint func,
982 uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
983{
984 SDIOH_API_RC Status;
985 void *mypkt = NULL;
986
987 sd_trace(("%s: Enter\n", __FUNCTION__));
988
989 DHD_PM_RESUME_WAIT(sdioh_request_buffer_wait);
990 DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL);
991 /* Case 1: we don't have a packet. */
992 if (pkt == NULL) {
993 sd_data(("%s: Creating new %s Packet, len=%d\n",
994 __FUNCTION__, write ? "TX" : "RX", buflen_u));
995#ifdef DHD_USE_STATIC_BUF
996 if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) {
997#else
998 if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) {
999#endif /* DHD_USE_STATIC_BUF */
1000 sd_err(("%s: PKTGET failed: len %d\n",
1001 __FUNCTION__, buflen_u));
1002 return SDIOH_API_RC_FAIL;
1003 }
1004
1005 /* For a write, copy the buffer data into the packet. */
1006 if (write) {
1007 bcopy(buffer, PKTDATA(sd->osh, mypkt), buflen_u);
1008 }
1009
1010 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1011
1012 /* For a read, copy the packet data back to the buffer. */
1013 if (!write) {
1014 bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u);
1015 }
1016#ifdef DHD_USE_STATIC_BUF
1017 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
1018#else
1019 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
1020#endif /* DHD_USE_STATIC_BUF */
1021 } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) {
1022 /* Case 2: We have a packet, but it is unaligned. */
1023
1024 /* In this case, we cannot have a chain. */
1025 ASSERT(PKTNEXT(sd->osh, pkt) == NULL);
1026
1027 sd_data(("%s: Creating aligned %s Packet, len=%d\n",
1028 __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt)));
1029#ifdef DHD_USE_STATIC_BUF
1030 if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
1031#else
1032 if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) {
1033#endif /* DHD_USE_STATIC_BUF */
1034 sd_err(("%s: PKTGET failed: len %d\n",
1035 __FUNCTION__, PKTLEN(sd->osh, pkt)));
1036 return SDIOH_API_RC_FAIL;
1037 }
1038
1039 /* For a write, copy the buffer data into the packet. */
1040 if (write) {
1041 bcopy(PKTDATA(sd->osh, pkt),
1042 PKTDATA(sd->osh, mypkt),
1043 PKTLEN(sd->osh, pkt));
1044 }
1045
1046 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, mypkt);
1047
1048 /* For a read, copy the packet data back to the buffer. */
1049 if (!write) {
1050 bcopy(PKTDATA(sd->osh, mypkt),
1051 PKTDATA(sd->osh, pkt),
1052 PKTLEN(sd->osh, mypkt));
1053 }
1054#ifdef DHD_USE_STATIC_BUF
1055 PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE);
1056#else
1057 PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE);
1058#endif /* DHD_USE_STATIC_BUF */
1059 } else { /* case 3: We have a packet and it is aligned. */
1060 sd_data(("%s: Aligned %s Packet, direct DMA\n",
1061 __FUNCTION__, write ? "Tx" : "Rx"));
1062 Status = sdioh_request_packet(sd, fix_inc, write, func, addr, pkt);
1063 }
1064
1065 return (Status);
1066}
1067
1068/* this function performs "abort" for both of host & device */
1069extern int
1070sdioh_abort(sdioh_info_t *sd, uint func)
1071{
1072#if defined(MMC_SDIO_ABORT)
1073 char t_func = (char) func;
1074#endif /* defined(MMC_SDIO_ABORT) */
1075 sd_trace(("%s: Enter\n", __FUNCTION__));
1076
1077#if defined(MMC_SDIO_ABORT)
1078 /* issue abort cmd52 command through F1 */
1079 sdioh_request_byte(sd, SD_IO_OP_WRITE, SDIO_FUNC_0, SDIOD_CCCR_IOABORT, &t_func);
1080#endif /* defined(MMC_SDIO_ABORT) */
1081
1082 sd_trace(("%s: Exit\n", __FUNCTION__));
1083 return SDIOH_API_RC_SUCCESS;
1084}
1085
1086/* Reset and re-initialize the device */
1087int sdioh_sdio_reset(sdioh_info_t *si)
1088{
1089 sd_trace(("%s: Enter\n", __FUNCTION__));
1090 sd_trace(("%s: Exit\n", __FUNCTION__));
1091 return SDIOH_API_RC_SUCCESS;
1092}
1093
1094/* Disable device interrupt */
1095void
1096sdioh_sdmmc_devintr_off(sdioh_info_t *sd)
1097{
1098 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1099 sd->intmask &= ~CLIENT_INTR;
1100}
1101
1102/* Enable device interrupt */
1103void
1104sdioh_sdmmc_devintr_on(sdioh_info_t *sd)
1105{
1106 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1107 sd->intmask |= CLIENT_INTR;
1108}
1109
1110/* Read client card reg */
1111int
1112sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
1113{
1114
1115 if ((func == 0) || (regsize == 1)) {
1116 uint8 temp = 0;
1117
1118 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1119 *data = temp;
1120 *data &= 0xff;
1121 sd_data(("%s: byte read data=0x%02x\n",
1122 __FUNCTION__, *data));
1123 } else {
1124 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, data, regsize);
1125 if (regsize == 2)
1126 *data &= 0xffff;
1127
1128 sd_data(("%s: word read data=0x%08x\n",
1129 __FUNCTION__, *data));
1130 }
1131
1132 return SUCCESS;
1133}
1134
1135#if !defined(OOB_INTR_ONLY)
1136/* bcmsdh_sdmmc interrupt handler */
1137static void IRQHandler(struct sdio_func *func)
1138{
1139 sdioh_info_t *sd;
1140
1141 sd_trace(("bcmsdh_sdmmc: ***IRQHandler\n"));
1142 sd = gInstance->sd;
1143
1144 ASSERT(sd != NULL);
1145 sdio_release_host(gInstance->func[0]);
1146
1147 if (sd->use_client_ints) {
1148 sd->intrcount++;
1149 ASSERT(sd->intr_handler);
1150 ASSERT(sd->intr_handler_arg);
1151 (sd->intr_handler)(sd->intr_handler_arg);
1152 } else {
1153 sd_err(("bcmsdh_sdmmc: ***IRQHandler\n"));
1154
1155 sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
1156 __FUNCTION__, sd->client_intr_enabled, sd->intr_handler));
1157 }
1158
1159 sdio_claim_host(gInstance->func[0]);
1160}
1161
1162/* bcmsdh_sdmmc interrupt handler for F2 (dummy handler) */
1163static void IRQHandlerF2(struct sdio_func *func)
1164{
1165 sdioh_info_t *sd;
1166
1167 sd_trace(("bcmsdh_sdmmc: ***IRQHandlerF2\n"));
1168
1169 sd = gInstance->sd;
1170
1171 ASSERT(sd != NULL);
1172}
1173#endif /* !defined(OOB_INTR_ONLY) */
1174
1175#ifdef NOTUSED
1176/* Write client card reg */
1177static int
1178sdioh_sdmmc_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data)
1179{
1180
1181 if ((func == 0) || (regsize == 1)) {
1182 uint8 temp;
1183
1184 temp = data & 0xff;
1185 sdioh_request_byte(sd, SDIOH_READ, func, regaddr, &temp);
1186 sd_data(("%s: byte write data=0x%02x\n",
1187 __FUNCTION__, data));
1188 } else {
1189 if (regsize == 2)
1190 data &= 0xffff;
1191
1192 sdioh_request_word(sd, 0, SDIOH_READ, func, regaddr, &data, regsize);
1193
1194 sd_data(("%s: word write data=0x%08x\n",
1195 __FUNCTION__, data));
1196 }
1197
1198 return SUCCESS;
1199}
1200#endif /* NOTUSED */
1201
1202int
1203sdioh_start(sdioh_info_t *si, int stage)
1204{
1205 int ret;
1206 sdioh_info_t *sd = gInstance->sd;
1207
1208 /* Need to do this stages as we can't enable the interrupt till
1209 downloading of the firmware is complete, other wise polling
1210 sdio access will come in way
1211 */
1212 if (gInstance->func[0]) {
1213 if (stage == 0) {
1214 /* Since the power to the chip is killed, we will have
1215 re enumerate the device again. Set the block size
1216 and enable the fucntion 1 for in preparation for
1217 downloading the code
1218 */
1219 /* sdio_reset_comm() - has been fixed in latest kernel/msm.git for Linux
1220 2.6.27. The implementation prior to that is buggy, and needs broadcom's
1221 patch for it
1222 */
1223 if ((ret = sdio_reset_comm(gInstance->func[0]->card)))
1224 sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret));
1225 else {
1226 sd->num_funcs = 2;
1227 sd->sd_blockmode = TRUE;
1228 sd->use_client_ints = TRUE;
1229 sd->client_block_size[0] = 64;
1230
1231 /* Claim host controller */
1232 sdio_claim_host(gInstance->func[1]);
1233
1234 sd->client_block_size[1] = 64;
1235 if (sdio_set_block_size(gInstance->func[1], 64)) {
1236 sd_err(("bcmsdh_sdmmc: Failed to set F1 blocksize\n"));
1237 }
1238
1239 /* Release host controller F1 */
1240 sdio_release_host(gInstance->func[1]);
1241
1242 if (gInstance->func[2]) {
1243 /* Claim host controller F2 */
1244 sdio_claim_host(gInstance->func[2]);
1245
1246 sd->client_block_size[2] = sd_f2_blocksize;
1247 if (sdio_set_block_size(gInstance->func[2],
1248 sd_f2_blocksize)) {
1249 sd_err(("bcmsdh_sdmmc: Failed to set F2 "
1250 "blocksize to %d\n", sd_f2_blocksize));
1251 }
1252
1253 /* Release host controller F2 */
1254 sdio_release_host(gInstance->func[2]);
1255 }
1256
1257 sdioh_sdmmc_card_enablefuncs(sd);
1258 }
1259 } else {
1260#if !defined(OOB_INTR_ONLY)
1261 sdio_claim_host(gInstance->func[0]);
1262 sdio_claim_irq(gInstance->func[2], IRQHandlerF2);
1263 sdio_claim_irq(gInstance->func[1], IRQHandler);
1264 sdio_release_host(gInstance->func[0]);
1265#else /* defined(OOB_INTR_ONLY) */
1266#if defined(HW_OOB)
1267 sdioh_enable_func_intr();
1268#endif
1269 bcmsdh_oob_intr_set(TRUE);
1270#endif /* !defined(OOB_INTR_ONLY) */
1271 }
1272 }
1273 else
1274 sd_err(("%s Failed\n", __FUNCTION__));
1275
1276 return (0);
1277}
1278
1279int
1280sdioh_stop(sdioh_info_t *si)
1281{
1282 /* MSM7201A Android sdio stack has bug with interrupt
1283 So internaly within SDIO stack they are polling
1284 which cause issue when device is turned off. So
1285 unregister interrupt with SDIO stack to stop the
1286 polling
1287 */
1288 if (gInstance->func[0]) {
1289#if !defined(OOB_INTR_ONLY)
1290 sdio_claim_host(gInstance->func[0]);
1291 sdio_release_irq(gInstance->func[1]);
1292 sdio_release_irq(gInstance->func[2]);
1293 sdio_release_host(gInstance->func[0]);
1294#else /* defined(OOB_INTR_ONLY) */
1295#if defined(HW_OOB)
1296 sdioh_disable_func_intr();
1297#endif
1298 bcmsdh_oob_intr_set(FALSE);
1299#endif /* !defined(OOB_INTR_ONLY) */
1300 }
1301 else
1302 sd_err(("%s Failed\n", __FUNCTION__));
1303 return (0);
1304}
diff --git a/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c
new file mode 100644
index 00000000000..b1fc35b7783
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmsdh_sdmmc_linux.c
@@ -0,0 +1,316 @@
1/*
2 * BCMSDH Function Driver for the native SDIO/MMC driver in the Linux Kernel
3 *
4 * Copyright (C) 1999-2010, 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.1.2.5.6.17 2010/08/13 00:36:19 Exp $
25 */
26
27#include <typedefs.h>
28#include <bcmutils.h>
29#include <sdio.h> /* SDIO 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_4329)
53#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329
54#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */
55#if !defined(SDIO_DEVICE_ID_BROADCOM_4319)
56#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319
57#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */
58
59#include <bcmsdh_sdmmc.h>
60
61#include <dhd_dbg.h>
62
63extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd);
64extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd);
65
66int sdio_function_init(void);
67void sdio_function_cleanup(void);
68
69#define DESCRIPTION "bcmsdh_sdmmc Driver"
70#define AUTHOR "Broadcom Corporation"
71
72/* module param defaults */
73static int clockoverride = 0;
74
75module_param(clockoverride, int, 0644);
76MODULE_PARM_DESC(clockoverride, "SDIO card clock override");
77
78PBCMSDH_SDMMC_INSTANCE gInstance;
79
80/* Maximum number of bcmsdh_sdmmc devices supported by driver */
81#define BCMSDH_SDMMC_MAX_DEVICES 1
82
83extern int bcmsdh_probe(struct device *dev);
84extern int bcmsdh_remove(struct device *dev);
85
86static int bcmsdh_sdmmc_probe(struct sdio_func *func,
87 const struct sdio_device_id *id)
88{
89 int ret = 0;
90 static struct sdio_func sdio_func_0;
91 sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__));
92 sd_trace(("sdio_bcmsdh: func->class=%x\n", func->class));
93 sd_trace(("sdio_vendor: 0x%04x\n", func->vendor));
94 sd_trace(("sdio_device: 0x%04x\n", func->device));
95 sd_trace(("Function#: 0x%04x\n", func->num));
96
97 if (func->num == 1) {
98 sdio_func_0.num = 0;
99 sdio_func_0.card = func->card;
100 gInstance->func[0] = &sdio_func_0;
101 if(func->device == 0x4) { /* 4318 */
102 gInstance->func[2] = NULL;
103 sd_trace(("NIC found, calling bcmsdh_probe...\n"));
104 ret = bcmsdh_probe(&func->dev);
105 }
106 }
107
108 gInstance->func[func->num] = func;
109
110 if (func->num == 2) {
111 sd_trace(("F2 found, calling bcmsdh_probe...\n"));
112 ret = bcmsdh_probe(&func->dev);
113 }
114
115 return ret;
116}
117
118static void bcmsdh_sdmmc_remove(struct sdio_func *func)
119{
120 sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__));
121 sd_info(("sdio_bcmsdh: func->class=%x\n", func->class));
122 sd_info(("sdio_vendor: 0x%04x\n", func->vendor));
123 sd_info(("sdio_device: 0x%04x\n", func->device));
124 sd_info(("Function#: 0x%04x\n", func->num));
125
126 if (func->num == 2) {
127 sd_trace(("F2 found, calling bcmsdh_remove...\n"));
128 bcmsdh_remove(&func->dev);
129 }
130}
131
132/* devices we support, null terminated */
133static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
134 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT) },
135 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) },
136 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) },
137 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) },
138 { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) },
139 { /* end: all zeroes */ },
140};
141
142MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
143
144#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
145static int bcmsdh_sdmmc_suspend(struct device *pdev)
146{
147 struct sdio_func *func = dev_to_sdio_func(pdev);
148 mmc_pm_flag_t sdio_flags;
149 int ret = 0;
150
151 if (func->num != 2)
152 return 0;
153
154 sdio_flags = sdio_get_host_pm_caps(func);
155
156 if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
157 sd_err(("can't keep power while host "
158 "is suspended\n", __FUNCTION__));
159 ret = -EINVAL;
160 goto out;
161 }
162
163 /* keep power while host suspended */
164 ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
165 if (ret) {
166 sd_err(("error while trying to keep power\n", __FUNCTION__));
167 goto out;
168 }
169
170out:
171 return ret;
172}
173
174static int bcmsdh_sdmmc_resume(struct device *pdev)
175{
176 /* nothing to do since MMC_PM_KEEP_POWER is cleared by MMC stack */
177 return 0;
178}
179
180static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = {
181 .suspend = bcmsdh_sdmmc_suspend,
182 .resume = bcmsdh_sdmmc_resume,
183};
184#endif
185
186static struct sdio_driver bcmsdh_sdmmc_driver = {
187 .probe = bcmsdh_sdmmc_probe,
188 .remove = bcmsdh_sdmmc_remove,
189 .name = "bcmsdh_sdmmc",
190 .id_table = bcmsdh_sdmmc_ids,
191#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM)
192 .drv = {
193 .pm = &bcmsdh_sdmmc_pm_ops,
194 },
195#endif
196 };
197
198struct sdos_info {
199 sdioh_info_t *sd;
200 spinlock_t lock;
201};
202
203
204int
205sdioh_sdmmc_osinit(sdioh_info_t *sd)
206{
207 struct sdos_info *sdos;
208
209 sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info));
210 sd->sdos_info = (void*)sdos;
211 if (sdos == NULL)
212 return BCME_NOMEM;
213
214 sdos->sd = sd;
215 spin_lock_init(&sdos->lock);
216 return BCME_OK;
217}
218
219void
220sdioh_sdmmc_osfree(sdioh_info_t *sd)
221{
222 struct sdos_info *sdos;
223 ASSERT(sd && sd->sdos_info);
224
225 sdos = (struct sdos_info *)sd->sdos_info;
226 MFREE(sd->osh, sdos, sizeof(struct sdos_info));
227}
228
229/* Interrupt enable/disable */
230SDIOH_API_RC
231sdioh_interrupt_set(sdioh_info_t *sd, bool enable)
232{
233 ulong flags;
234 struct sdos_info *sdos;
235
236 sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling"));
237
238 sdos = (struct sdos_info *)sd->sdos_info;
239 ASSERT(sdos);
240
241#if !defined(OOB_INTR_ONLY)
242 if (enable && !(sd->intr_handler && sd->intr_handler_arg)) {
243 sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__));
244 return SDIOH_API_RC_FAIL;
245 }
246#endif /* !defined(OOB_INTR_ONLY) */
247
248 /* Ensure atomicity for enable/disable calls */
249 spin_lock_irqsave(&sdos->lock, flags);
250
251 sd->client_intr_enabled = enable;
252 if (enable) {
253 sdioh_sdmmc_devintr_on(sd);
254 } else {
255 sdioh_sdmmc_devintr_off(sd);
256 }
257
258 spin_unlock_irqrestore(&sdos->lock, flags);
259
260 return SDIOH_API_RC_SUCCESS;
261}
262
263
264#ifdef BCMSDH_MODULE
265static int __init
266bcmsdh_module_init(void)
267{
268 int error = 0;
269 sdio_function_init();
270 return error;
271}
272
273static void __exit
274bcmsdh_module_cleanup(void)
275{
276 sdio_function_cleanup();
277}
278
279module_init(bcmsdh_module_init);
280module_exit(bcmsdh_module_cleanup);
281
282MODULE_LICENSE("GPL v2");
283MODULE_DESCRIPTION(DESCRIPTION);
284MODULE_AUTHOR(AUTHOR);
285
286#endif /* BCMSDH_MODULE */
287/*
288 * module init
289*/
290int sdio_function_init(void)
291{
292 int error = 0;
293 sd_trace(("bcmsdh_sdmmc: %s Enter\n", __FUNCTION__));
294
295 gInstance = kzalloc(sizeof(BCMSDH_SDMMC_INSTANCE), GFP_KERNEL);
296 if (!gInstance)
297 return -ENOMEM;
298
299 error = sdio_register_driver(&bcmsdh_sdmmc_driver);
300
301 return error;
302}
303
304/*
305 * module cleanup
306*/
307extern int bcmsdh_remove(struct device *dev);
308void sdio_function_cleanup(void)
309{
310 sd_trace(("%s Enter\n", __FUNCTION__));
311
312 sdio_unregister_driver(&bcmsdh_sdmmc_driver);
313
314 if (gInstance)
315 kfree(gInstance);
316}
diff --git a/drivers/net/wireless/bcm4329/bcmsdspi.c b/drivers/net/wireless/bcm4329/bcmsdspi.c
new file mode 100644
index 00000000000..636539be5ea
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmsdspi.c
@@ -0,0 +1,1596 @@
1/*
2 * Broadcom BCMSDH to SPI Protocol Conversion Layer
3 *
4 * Copyright (C) 1999-2010, 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.c,v 1.14.4.2.4.4.6.5 2010/03/10 03:09:48 Exp $
25 */
26
27#include <typedefs.h>
28
29#include <bcmdevs.h>
30#include <bcmendian.h>
31#include <bcmutils.h>
32#include <osl.h>
33#include <siutils.h>
34#include <sdio.h> /* SDIO Device and Protocol Specs */
35#include <sdioh.h> /* SDIO Host Controller Specification */
36#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
37#include <sdiovar.h> /* ioctl/iovars */
38
39#include <pcicfg.h>
40
41
42#include <bcmsdspi.h>
43#include <bcmspi.h>
44
45#include <proto/sdspi.h>
46
47#define SD_PAGE 4096
48
49/* Globals */
50
51uint sd_msglevel = SDH_ERROR_VAL;
52uint sd_hiok = FALSE; /* Use hi-speed mode if available? */
53uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */
54uint sd_f2_blocksize = 512; /* Default blocksize */
55
56uint sd_divisor = 2; /* Default 33MHz/2 = 16MHz for dongle */
57uint sd_power = 1; /* Default to SD Slot powered ON */
58uint sd_clock = 1; /* Default to SD Clock turned ON */
59uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */
60uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */
61
62uint sd_toctl = 7;
63
64/* Prototypes */
65static bool sdspi_start_power(sdioh_info_t *sd);
66static int sdspi_set_highspeed_mode(sdioh_info_t *sd, bool HSMode);
67static int sdspi_card_enablefuncs(sdioh_info_t *sd);
68static void sdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count);
69static int sdspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg,
70 uint32 *data, uint32 datalen);
71static int sdspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr,
72 int regsize, uint32 *data);
73static int sdspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr,
74 int regsize, uint32 data);
75static int sdspi_driver_init(sdioh_info_t *sd);
76static bool sdspi_reset(sdioh_info_t *sd, bool host_reset, bool client_reset);
77static int sdspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo,
78 uint32 addr, int nbytes, uint32 *data);
79static int sdspi_abort(sdioh_info_t *sd, uint func);
80
81static int set_client_block_size(sdioh_info_t *sd, int func, int blocksize);
82
83static uint8 sdspi_crc7(unsigned char* p, uint32 len);
84static uint16 sdspi_crc16(unsigned char* p, uint32 len);
85static int sdspi_crc_onoff(sdioh_info_t *sd, bool use_crc);
86
87/*
88 * Public entry points & extern's
89 */
90extern sdioh_info_t *
91sdioh_attach(osl_t *osh, void *bar0, uint irq)
92{
93 sdioh_info_t *sd;
94
95 sd_trace(("%s\n", __FUNCTION__));
96 if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
97 sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
98 return NULL;
99 }
100 bzero((char *)sd, sizeof(sdioh_info_t));
101 sd->osh = osh;
102
103 if (spi_osinit(sd) != 0) {
104 sd_err(("%s: spi_osinit() failed\n", __FUNCTION__));
105 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
106 return NULL;
107 }
108
109 sd->bar0 = (uintptr)bar0;
110 sd->irq = irq;
111 sd->intr_handler = NULL;
112 sd->intr_handler_arg = NULL;
113 sd->intr_handler_valid = FALSE;
114
115 /* Set defaults */
116 sd->sd_blockmode = FALSE;
117 sd->use_client_ints = TRUE;
118 sd->sd_use_dma = FALSE; /* DMA Not supported */
119
120 /* Haven't figured out how to make bytemode work with dma */
121 if (!sd->sd_blockmode)
122 sd->sd_use_dma = 0;
123
124 if (!spi_hw_attach(sd)) {
125 sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__));
126 spi_osfree(sd);
127 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
128 return NULL;
129 }
130
131 if (sdspi_driver_init(sd) != SUCCESS) {
132 if (sdspi_driver_init(sd) != SUCCESS) {
133 sd_err(("%s:sdspi_driver_init() failed()\n", __FUNCTION__));
134 spi_hw_detach(sd);
135 spi_osfree(sd);
136 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
137 return (NULL);
138 }
139 }
140
141 if (spi_register_irq(sd, irq) != SUCCESS) {
142 sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq));
143 spi_hw_detach(sd);
144 spi_osfree(sd);
145 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
146 return (NULL);
147 }
148
149 sd_trace(("%s: Done\n", __FUNCTION__));
150 return sd;
151}
152
153extern SDIOH_API_RC
154sdioh_detach(osl_t *osh, sdioh_info_t *sd)
155{
156 sd_trace(("%s\n", __FUNCTION__));
157
158 if (sd) {
159 if (sd->card_init_done)
160 sdspi_reset(sd, 1, 1);
161
162 sd_info(("%s: detaching from hardware\n", __FUNCTION__));
163 spi_free_irq(sd->irq, sd);
164 spi_hw_detach(sd);
165 spi_osfree(sd);
166 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
167 }
168
169 return SDIOH_API_RC_SUCCESS;
170}
171
172/* Configure callback to client when we recieve client interrupt */
173extern SDIOH_API_RC
174sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
175{
176 sd_trace(("%s: Entering\n", __FUNCTION__));
177
178 sd->intr_handler = fn;
179 sd->intr_handler_arg = argh;
180 sd->intr_handler_valid = TRUE;
181
182 return SDIOH_API_RC_SUCCESS;
183}
184
185extern SDIOH_API_RC
186sdioh_interrupt_deregister(sdioh_info_t *sd)
187{
188 sd_trace(("%s: Entering\n", __FUNCTION__));
189
190 sd->intr_handler_valid = FALSE;
191 sd->intr_handler = NULL;
192 sd->intr_handler_arg = NULL;
193
194 return SDIOH_API_RC_SUCCESS;
195}
196
197extern SDIOH_API_RC
198sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
199{
200 sd_trace(("%s: Entering\n", __FUNCTION__));
201
202 *onoff = sd->client_intr_enabled;
203
204 return SDIOH_API_RC_SUCCESS;
205}
206
207#if defined(DHD_DEBUG)
208extern bool
209sdioh_interrupt_pending(sdioh_info_t *sd)
210{
211 return 0;
212}
213#endif
214
215uint
216sdioh_query_iofnum(sdioh_info_t *sd)
217{
218 return sd->num_funcs;
219}
220
221/* IOVar table */
222enum {
223 IOV_MSGLEVEL = 1,
224 IOV_BLOCKMODE,
225 IOV_BLOCKSIZE,
226 IOV_DMA,
227 IOV_USEINTS,
228 IOV_NUMINTS,
229 IOV_NUMLOCALINTS,
230 IOV_HOSTREG,
231 IOV_DEVREG,
232 IOV_DIVISOR,
233 IOV_SDMODE,
234 IOV_HISPEED,
235 IOV_HCIREGS,
236 IOV_POWER,
237 IOV_CLOCK,
238 IOV_CRC
239};
240
241const bcm_iovar_t sdioh_iovars[] = {
242 {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
243 {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 },
244 {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */
245 {"sd_dma", IOV_DMA, 0, IOVT_BOOL, 0 },
246 {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 },
247 {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 },
248 {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 },
249 {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
250 {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
251 {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 },
252 {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 },
253 {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 },
254 {"sd_crc", IOV_CRC, 0, IOVT_UINT32, 0 },
255 {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100},
256 {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0},
257 {NULL, 0, 0, 0, 0 }
258};
259
260int
261sdioh_iovar_op(sdioh_info_t *si, const char *name,
262 void *params, int plen, void *arg, int len, bool set)
263{
264 const bcm_iovar_t *vi = NULL;
265 int bcmerror = 0;
266 int val_size;
267 int32 int_val = 0;
268 bool bool_val;
269 uint32 actionid;
270
271 ASSERT(name);
272 ASSERT(len >= 0);
273
274 /* Get must have return space; Set does not take qualifiers */
275 ASSERT(set || (arg && len));
276 ASSERT(!set || (!params && !plen));
277
278 sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
279
280 if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
281 bcmerror = BCME_UNSUPPORTED;
282 goto exit;
283 }
284
285 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
286 goto exit;
287
288 /* Set up params so get and set can share the convenience variables */
289 if (params == NULL) {
290 params = arg;
291 plen = len;
292 }
293
294 if (vi->type == IOVT_VOID)
295 val_size = 0;
296 else if (vi->type == IOVT_BUFFER)
297 val_size = len;
298 else
299 val_size = sizeof(int);
300
301 if (plen >= (int)sizeof(int_val))
302 bcopy(params, &int_val, sizeof(int_val));
303
304 bool_val = (int_val != 0) ? TRUE : FALSE;
305
306 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
307 switch (actionid) {
308 case IOV_GVAL(IOV_MSGLEVEL):
309 int_val = (int32)sd_msglevel;
310 bcopy(&int_val, arg, val_size);
311 break;
312
313 case IOV_SVAL(IOV_MSGLEVEL):
314 sd_msglevel = int_val;
315 break;
316
317 case IOV_GVAL(IOV_BLOCKMODE):
318 int_val = (int32)si->sd_blockmode;
319 bcopy(&int_val, arg, val_size);
320 break;
321
322 case IOV_SVAL(IOV_BLOCKMODE):
323 si->sd_blockmode = (bool)int_val;
324 /* Haven't figured out how to make non-block mode with DMA */
325 if (!si->sd_blockmode)
326 si->sd_use_dma = 0;
327 break;
328
329 case IOV_GVAL(IOV_BLOCKSIZE):
330 if ((uint32)int_val > si->num_funcs) {
331 bcmerror = BCME_BADARG;
332 break;
333 }
334 int_val = (int32)si->client_block_size[int_val];
335 bcopy(&int_val, arg, val_size);
336 break;
337
338 case IOV_SVAL(IOV_BLOCKSIZE):
339 {
340 uint func = ((uint32)int_val >> 16);
341 uint blksize = (uint16)int_val;
342 uint maxsize;
343
344 if (func > si->num_funcs) {
345 bcmerror = BCME_BADARG;
346 break;
347 }
348
349 switch (func) {
350 case 0: maxsize = 32; break;
351 case 1: maxsize = BLOCK_SIZE_4318; break;
352 case 2: maxsize = BLOCK_SIZE_4328; break;
353 default: maxsize = 0;
354 }
355 if (blksize > maxsize) {
356 bcmerror = BCME_BADARG;
357 break;
358 }
359 if (!blksize) {
360 blksize = maxsize;
361 }
362
363 /* Now set it */
364 spi_lock(si);
365 bcmerror = set_client_block_size(si, func, blksize);
366 spi_unlock(si);
367 break;
368 }
369
370 case IOV_GVAL(IOV_DMA):
371 int_val = (int32)si->sd_use_dma;
372 bcopy(&int_val, arg, val_size);
373 break;
374
375 case IOV_SVAL(IOV_DMA):
376 si->sd_use_dma = (bool)int_val;
377 break;
378
379 case IOV_GVAL(IOV_USEINTS):
380 int_val = (int32)si->use_client_ints;
381 bcopy(&int_val, arg, val_size);
382 break;
383
384 case IOV_SVAL(IOV_USEINTS):
385 break;
386
387 case IOV_GVAL(IOV_DIVISOR):
388 int_val = (uint32)sd_divisor;
389 bcopy(&int_val, arg, val_size);
390 break;
391
392 case IOV_SVAL(IOV_DIVISOR):
393 sd_divisor = int_val;
394 if (!spi_start_clock(si, (uint16)sd_divisor)) {
395 sd_err(("set clock failed!\n"));
396 bcmerror = BCME_ERROR;
397 }
398 break;
399
400 case IOV_GVAL(IOV_POWER):
401 int_val = (uint32)sd_power;
402 bcopy(&int_val, arg, val_size);
403 break;
404
405 case IOV_SVAL(IOV_POWER):
406 sd_power = int_val;
407 break;
408
409 case IOV_GVAL(IOV_CLOCK):
410 int_val = (uint32)sd_clock;
411 bcopy(&int_val, arg, val_size);
412 break;
413
414 case IOV_SVAL(IOV_CLOCK):
415 sd_clock = int_val;
416 break;
417
418 case IOV_GVAL(IOV_CRC):
419 int_val = (uint32)sd_crc;
420 bcopy(&int_val, arg, val_size);
421 break;
422
423 case IOV_SVAL(IOV_CRC):
424 /* Apply new setting, but don't change sd_crc until
425 * after the CRC-mode is selected in the device. This
426 * is required because the software must generate a
427 * correct CRC for the CMD59 in order to be able to
428 * turn OFF the CRC.
429 */
430 sdspi_crc_onoff(si, int_val ? 1 : 0);
431 sd_crc = int_val;
432 break;
433
434 case IOV_GVAL(IOV_SDMODE):
435 int_val = (uint32)sd_sdmode;
436 bcopy(&int_val, arg, val_size);
437 break;
438
439 case IOV_SVAL(IOV_SDMODE):
440 sd_sdmode = int_val;
441 break;
442
443 case IOV_GVAL(IOV_HISPEED):
444 int_val = (uint32)sd_hiok;
445 bcopy(&int_val, arg, val_size);
446 break;
447
448 case IOV_SVAL(IOV_HISPEED):
449 sd_hiok = int_val;
450
451 if (!sdspi_set_highspeed_mode(si, (bool)sd_hiok)) {
452 sd_err(("Failed changing highspeed mode to %d.\n", sd_hiok));
453 bcmerror = BCME_ERROR;
454 return ERROR;
455 }
456 break;
457
458 case IOV_GVAL(IOV_NUMINTS):
459 int_val = (int32)si->intrcount;
460 bcopy(&int_val, arg, val_size);
461 break;
462
463 case IOV_GVAL(IOV_NUMLOCALINTS):
464 int_val = (int32)si->local_intrcount;
465 bcopy(&int_val, arg, val_size);
466 break;
467
468 case IOV_GVAL(IOV_HOSTREG):
469 {
470 break;
471 }
472
473 case IOV_SVAL(IOV_HOSTREG):
474 {
475 sd_err(("IOV_HOSTREG unsupported\n"));
476 break;
477 }
478
479 case IOV_GVAL(IOV_DEVREG):
480 {
481 sdreg_t *sd_ptr = (sdreg_t *)params;
482 uint8 data;
483
484 if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
485 bcmerror = BCME_SDIO_ERROR;
486 break;
487 }
488
489 int_val = (int)data;
490 bcopy(&int_val, arg, sizeof(int_val));
491 break;
492 }
493
494 case IOV_SVAL(IOV_DEVREG):
495 {
496 sdreg_t *sd_ptr = (sdreg_t *)params;
497 uint8 data = (uint8)sd_ptr->value;
498
499 if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
500 bcmerror = BCME_SDIO_ERROR;
501 break;
502 }
503 break;
504 }
505
506
507 default:
508 bcmerror = BCME_UNSUPPORTED;
509 break;
510 }
511exit:
512
513 return bcmerror;
514}
515
516extern SDIOH_API_RC
517sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
518{
519 SDIOH_API_RC status;
520 /* No lock needed since sdioh_request_byte does locking */
521 status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
522 return status;
523}
524
525extern SDIOH_API_RC
526sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
527{
528 /* No lock needed since sdioh_request_byte does locking */
529 SDIOH_API_RC status;
530 status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
531 return status;
532}
533
534extern SDIOH_API_RC
535sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
536{
537 uint32 count;
538 int offset;
539 uint32 foo;
540 uint8 *cis = cisd;
541
542 sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
543
544 if (!sd->func_cis_ptr[func]) {
545 bzero(cis, length);
546 return SDIOH_API_RC_FAIL;
547 }
548
549 spi_lock(sd);
550 *cis = 0;
551 for (count = 0; count < length; count++) {
552 offset = sd->func_cis_ptr[func] + count;
553 if (sdspi_card_regread (sd, 0, offset, 1, &foo) < 0) {
554 sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
555 spi_unlock(sd);
556 return SDIOH_API_RC_FAIL;
557 }
558 *cis = (uint8)(foo & 0xff);
559 cis++;
560 }
561 spi_unlock(sd);
562 return SDIOH_API_RC_SUCCESS;
563}
564
565extern SDIOH_API_RC
566sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
567{
568 int status;
569 uint32 cmd_arg;
570 uint32 rsp5;
571
572 spi_lock(sd);
573
574 cmd_arg = 0;
575 cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
576 cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
577 cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, rw == SDIOH_READ ? 0 : 1);
578 cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
579 cmd_arg = SFIELD(cmd_arg, CMD52_DATA, rw == SDIOH_READ ? 0 : *byte);
580
581 sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x\n", __FUNCTION__, rw, func, regaddr));
582
583 if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma,
584 SDIOH_CMD_52, cmd_arg, NULL, 0)) != SUCCESS) {
585 spi_unlock(sd);
586 return status;
587 }
588
589 sdspi_cmd_getrsp(sd, &rsp5, 1);
590 if (rsp5 != 0x00) {
591 sd_err(("%s: rsp5 flags is 0x%x func=%d\n",
592 __FUNCTION__, rsp5, func));
593 /* ASSERT(0); */
594 spi_unlock(sd);
595 return SDIOH_API_RC_FAIL;
596 }
597
598 if (rw == SDIOH_READ)
599 *byte = sd->card_rsp_data >> 24;
600
601 spi_unlock(sd);
602 return SDIOH_API_RC_SUCCESS;
603}
604
605extern SDIOH_API_RC
606sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
607 uint32 *word, uint nbytes)
608{
609 int status;
610
611 spi_lock(sd);
612
613 if (rw == SDIOH_READ)
614 status = sdspi_card_regread(sd, func, addr, nbytes, word);
615 else
616 status = sdspi_card_regwrite(sd, func, addr, nbytes, *word);
617
618 spi_unlock(sd);
619 return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
620}
621
622extern SDIOH_API_RC
623sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func,
624 uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
625{
626 int len;
627 int buflen = (int)buflen_u;
628 bool fifo = (fix_inc == SDIOH_DATA_FIX);
629
630 spi_lock(sd);
631
632 ASSERT(reg_width == 4);
633 ASSERT(buflen_u < (1 << 30));
634 ASSERT(sd->client_block_size[func]);
635
636 sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n",
637 __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W',
638 buflen_u, sd->r_cnt, sd->t_cnt, pkt));
639
640 /* Break buffer down into blocksize chunks:
641 * Bytemode: 1 block at a time.
642 */
643 while (buflen > 0) {
644 if (sd->sd_blockmode) {
645 /* Max xfer is Page size */
646 len = MIN(SD_PAGE, buflen);
647
648 /* Round down to a block boundry */
649 if (buflen > sd->client_block_size[func])
650 len = (len/sd->client_block_size[func]) *
651 sd->client_block_size[func];
652 } else {
653 /* Byte mode: One block at a time */
654 len = MIN(sd->client_block_size[func], buflen);
655 }
656
657 if (sdspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) {
658 spi_unlock(sd);
659 return SDIOH_API_RC_FAIL;
660 }
661 buffer += len;
662 buflen -= len;
663 if (!fifo)
664 addr += len;
665 }
666 spi_unlock(sd);
667 return SDIOH_API_RC_SUCCESS;
668}
669
670static int
671sdspi_abort(sdioh_info_t *sd, uint func)
672{
673 uint8 spi_databuf[] = { 0x74, 0x80, 0x00, 0x0C, 0xFF, 0x95, 0xFF, 0xFF,
674 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
675 uint8 spi_rspbuf[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
676 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
677 int err = 0;
678
679 sd_err(("Sending SPI Abort to F%d\n", func));
680 spi_databuf[4] = func & 0x7;
681 /* write to function 0, addr 6 (IOABORT) func # in 3 LSBs. */
682 spi_sendrecv(sd, spi_databuf, spi_rspbuf, sizeof(spi_databuf));
683
684 return err;
685}
686
687extern int
688sdioh_abort(sdioh_info_t *sd, uint fnum)
689{
690 int ret;
691
692 spi_lock(sd);
693 ret = sdspi_abort(sd, fnum);
694 spi_unlock(sd);
695
696 return ret;
697}
698
699int
700sdioh_start(sdioh_info_t *sd, int stage)
701{
702 return SUCCESS;
703}
704
705int
706sdioh_stop(sdioh_info_t *sd)
707{
708 return SUCCESS;
709}
710
711
712/*
713 * Private/Static work routines
714 */
715static bool
716sdspi_reset(sdioh_info_t *sd, bool host_reset, bool client_reset)
717{
718 if (!sd)
719 return TRUE;
720
721 spi_lock(sd);
722 /* Reset client card */
723 if (client_reset && (sd->adapter_slot != -1)) {
724 if (sdspi_card_regwrite(sd, 0, SDIOD_CCCR_IOABORT, 1, 0x8) != SUCCESS)
725 sd_err(("%s: Cannot write to card reg 0x%x\n",
726 __FUNCTION__, SDIOD_CCCR_IOABORT));
727 else
728 sd->card_rca = 0;
729 }
730
731 /* The host reset is a NOP in the sd-spi case. */
732 if (host_reset) {
733 sd->sd_mode = SDIOH_MODE_SPI;
734 }
735 spi_unlock(sd);
736 return TRUE;
737}
738
739static int
740sdspi_host_init(sdioh_info_t *sd)
741{
742 sdspi_reset(sd, 1, 0);
743
744 /* Default power on mode is SD1 */
745 sd->sd_mode = SDIOH_MODE_SPI;
746 sd->polled_mode = TRUE;
747 sd->host_init_done = TRUE;
748 sd->card_init_done = FALSE;
749 sd->adapter_slot = 1;
750
751 return (SUCCESS);
752}
753
754#define CMD0_RETRIES 3
755#define CMD5_RETRIES 10
756
757static int
758get_ocr(sdioh_info_t *sd, uint32 *cmd_arg, uint32 *cmd_rsp)
759{
760 uint32 rsp5;
761 int retries, status;
762
763 /* First issue a CMD0 to get the card into SPI mode. */
764 for (retries = 0; retries <= CMD0_RETRIES; retries++) {
765 if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma,
766 SDIOH_CMD_0, *cmd_arg, NULL, 0)) != SUCCESS) {
767 sd_err(("%s: No response to CMD0\n", __FUNCTION__));
768 continue;
769 }
770
771 sdspi_cmd_getrsp(sd, &rsp5, 1);
772
773 if (GFIELD(rsp5, SPI_RSP_ILL_CMD)) {
774 printf("%s: Card already initialized (continuing)\n", __FUNCTION__);
775 break;
776 }
777
778 if (GFIELD(rsp5, SPI_RSP_IDLE)) {
779 printf("%s: Card in SPI mode\n", __FUNCTION__);
780 break;
781 }
782 }
783
784 if (retries > CMD0_RETRIES) {
785 sd_err(("%s: Too many retries for CMD0\n", __FUNCTION__));
786 return ERROR;
787 }
788
789 /* Get the Card's Operation Condition. */
790 /* Occasionally the board takes a while to become ready. */
791 for (retries = 0; retries <= CMD5_RETRIES; retries++) {
792 if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma,
793 SDIOH_CMD_5, *cmd_arg, NULL, 0)) != SUCCESS) {
794 sd_err(("%s: No response to CMD5\n", __FUNCTION__));
795 continue;
796 }
797
798 printf("CMD5 response data was: 0x%08x\n", sd->card_rsp_data);
799
800 if (GFIELD(sd->card_rsp_data, RSP4_CARD_READY)) {
801 printf("%s: Card ready\n", __FUNCTION__);
802 break;
803 }
804 }
805
806 if (retries > CMD5_RETRIES) {
807 sd_err(("%s: Too many retries for CMD5\n", __FUNCTION__));
808 return ERROR;
809 }
810
811 *cmd_rsp = sd->card_rsp_data;
812
813 sdspi_crc_onoff(sd, sd_crc ? 1 : 0);
814
815 return (SUCCESS);
816}
817
818static int
819sdspi_crc_onoff(sdioh_info_t *sd, bool use_crc)
820{
821 uint32 args;
822 int status;
823
824 args = use_crc ? 1 : 0;
825 if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma,
826 SDIOH_CMD_59, args, NULL, 0)) != SUCCESS) {
827 sd_err(("%s: No response to CMD59\n", __FUNCTION__));
828 }
829
830 sd_info(("CMD59 response data was: 0x%08x\n", sd->card_rsp_data));
831
832 sd_err(("SD-SPI CRC turned %s\n", use_crc ? "ON" : "OFF"));
833 return (SUCCESS);
834}
835
836static int
837sdspi_client_init(sdioh_info_t *sd)
838{
839 uint8 fn_ints;
840
841 sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot));
842
843 /* Start at ~400KHz clock rate for initialization */
844 if (!spi_start_clock(sd, 128)) {
845 sd_err(("spi_start_clock failed\n"));
846 return ERROR;
847 }
848
849 if (!sdspi_start_power(sd)) {
850 sd_err(("sdspi_start_power failed\n"));
851 return ERROR;
852 }
853
854 if (sd->num_funcs == 0) {
855 sd_err(("%s: No IO funcs!\n", __FUNCTION__));
856 return ERROR;
857 }
858
859 sdspi_card_enablefuncs(sd);
860
861 set_client_block_size(sd, 1, BLOCK_SIZE_4318);
862 fn_ints = INTR_CTL_FUNC1_EN;
863
864 if (sd->num_funcs >= 2) {
865 set_client_block_size(sd, 2, sd_f2_blocksize /* BLOCK_SIZE_4328 */);
866 fn_ints |= INTR_CTL_FUNC2_EN;
867 }
868
869 /* Enable/Disable Client interrupts */
870 /* Turn on here but disable at host controller */
871 if (sdspi_card_regwrite(sd, 0, SDIOD_CCCR_INTEN, 1,
872 (fn_ints | INTR_CTL_MASTER_EN)) != SUCCESS) {
873 sd_err(("%s: Could not enable ints in CCCR\n", __FUNCTION__));
874 return ERROR;
875 }
876
877 /* Switch to High-speed clocking mode if both host and device support it */
878 sdspi_set_highspeed_mode(sd, (bool)sd_hiok);
879
880 /* After configuring for High-Speed mode, set the desired clock rate. */
881 if (!spi_start_clock(sd, (uint16)sd_divisor)) {
882 sd_err(("spi_start_clock failed\n"));
883 return ERROR;
884 }
885
886 sd->card_init_done = TRUE;
887
888 return SUCCESS;
889}
890
891static int
892sdspi_set_highspeed_mode(sdioh_info_t *sd, bool HSMode)
893{
894 uint32 regdata;
895 int status;
896 bool hsmode;
897
898 if (HSMode == TRUE) {
899
900 sd_err(("Attempting to enable High-Speed mode.\n"));
901
902 if ((status = sdspi_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
903 1, &regdata)) != SUCCESS) {
904 return status;
905 }
906 if (regdata & SDIO_SPEED_SHS) {
907 sd_err(("Device supports High-Speed mode.\n"));
908
909 regdata |= SDIO_SPEED_EHS;
910
911 sd_err(("Writing %08x to Card at %08x\n",
912 regdata, SDIOD_CCCR_SPEED_CONTROL));
913 if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
914 1, regdata)) != BCME_OK) {
915 return status;
916 }
917
918 hsmode = 1;
919
920 sd_err(("High-speed clocking mode enabled.\n"));
921 }
922 else {
923 sd_err(("Device does not support High-Speed Mode.\n"));
924 hsmode = 0;
925 }
926 } else {
927 if ((status = sdspi_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
928 1, &regdata)) != SUCCESS) {
929 return status;
930 }
931
932 regdata = ~SDIO_SPEED_EHS;
933
934 sd_err(("Writing %08x to Card at %08x\n",
935 regdata, SDIOD_CCCR_SPEED_CONTROL));
936 if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
937 1, regdata)) != BCME_OK) {
938 return status;
939 }
940
941 sd_err(("Low-speed clocking mode enabled.\n"));
942 hsmode = 0;
943 }
944
945 spi_controller_highspeed_mode(sd, hsmode);
946
947 return TRUE;
948}
949
950bool
951sdspi_start_power(sdioh_info_t *sd)
952{
953 uint32 cmd_arg;
954 uint32 cmd_rsp;
955
956 sd_trace(("%s\n", __FUNCTION__));
957
958 /* Get the Card's Operation Condition. Occasionally the board
959 * takes a while to become ready
960 */
961
962 cmd_arg = 0;
963 if (get_ocr(sd, &cmd_arg, &cmd_rsp) != SUCCESS) {
964 sd_err(("%s: Failed to get OCR; bailing\n", __FUNCTION__));
965 return FALSE;
966 }
967
968 sd_err(("mem_present = %d\n", GFIELD(cmd_rsp, RSP4_MEM_PRESENT)));
969 sd_err(("num_funcs = %d\n", GFIELD(cmd_rsp, RSP4_NUM_FUNCS)));
970 sd_err(("card_ready = %d\n", GFIELD(cmd_rsp, RSP4_CARD_READY)));
971 sd_err(("OCR = 0x%x\n", GFIELD(cmd_rsp, RSP4_IO_OCR)));
972
973 /* Verify that the card supports I/O mode */
974 if (GFIELD(cmd_rsp, RSP4_NUM_FUNCS) == 0) {
975 sd_err(("%s: Card does not support I/O\n", __FUNCTION__));
976 return ERROR;
977 }
978
979 sd->num_funcs = GFIELD(cmd_rsp, RSP4_NUM_FUNCS);
980
981 /* Examine voltage: Arasan only supports 3.3 volts,
982 * so look for 3.2-3.3 Volts and also 3.3-3.4 volts.
983 */
984
985 if ((GFIELD(cmd_rsp, RSP4_IO_OCR) & (0x3 << 20)) == 0) {
986 sd_err(("This client does not support 3.3 volts!\n"));
987 return ERROR;
988 }
989
990
991 return TRUE;
992}
993
994static int
995sdspi_driver_init(sdioh_info_t *sd)
996{
997 sd_trace(("%s\n", __FUNCTION__));
998
999 if ((sdspi_host_init(sd)) != SUCCESS) {
1000 return ERROR;
1001 }
1002
1003 if (sdspi_client_init(sd) != SUCCESS) {
1004 return ERROR;
1005 }
1006
1007 return SUCCESS;
1008}
1009
1010static int
1011sdspi_card_enablefuncs(sdioh_info_t *sd)
1012{
1013 int status;
1014 uint32 regdata;
1015 uint32 regaddr, fbraddr;
1016 uint8 func;
1017 uint8 *ptr;
1018
1019 sd_trace(("%s\n", __FUNCTION__));
1020 /* Get the Card's common CIS address */
1021 ptr = (uint8 *) &sd->com_cis_ptr;
1022 for (regaddr = SDIOD_CCCR_CISPTR_0; regaddr <= SDIOD_CCCR_CISPTR_2; regaddr++) {
1023 if ((status = sdspi_card_regread (sd, 0, regaddr, 1, &regdata)) != SUCCESS)
1024 return status;
1025
1026 *ptr++ = (uint8) regdata;
1027 }
1028
1029 /* Only the lower 17-bits are valid */
1030 sd->com_cis_ptr &= 0x0001FFFF;
1031 sd->func_cis_ptr[0] = sd->com_cis_ptr;
1032 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
1033
1034 /* Get the Card's function CIS (for each function) */
1035 for (fbraddr = SDIOD_FBR_STARTADDR, func = 1;
1036 func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
1037 ptr = (uint8 *) &sd->func_cis_ptr[func];
1038 for (regaddr = SDIOD_FBR_CISPTR_0; regaddr <= SDIOD_FBR_CISPTR_2; regaddr++) {
1039 if ((status = sdspi_card_regread (sd, 0, regaddr + fbraddr, 1, &regdata))
1040 != SUCCESS)
1041 return status;
1042
1043 *ptr++ = (uint8) regdata;
1044 }
1045
1046 /* Only the lower 17-bits are valid */
1047 sd->func_cis_ptr[func] &= 0x0001FFFF;
1048 sd_info(("%s: Function %d CIS Ptr = 0x%x\n",
1049 __FUNCTION__, func, sd->func_cis_ptr[func]));
1050 }
1051
1052 sd_info(("%s: write ESCI bit\n", __FUNCTION__));
1053 /* Enable continuous SPI interrupt (ESCI bit) */
1054 sdspi_card_regwrite(sd, 0, SDIOD_CCCR_BICTRL, 1, 0x60);
1055
1056 sd_info(("%s: enable f1\n", __FUNCTION__));
1057 /* Enable function 1 on the card */
1058 regdata = SDIO_FUNC_ENABLE_1;
1059 if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_IOEN, 1, regdata)) != SUCCESS)
1060 return status;
1061
1062 sd_info(("%s: done\n", __FUNCTION__));
1063 return SUCCESS;
1064}
1065
1066/* Read client card reg */
1067static int
1068sdspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
1069{
1070 int status;
1071 uint32 cmd_arg;
1072 uint32 rsp5;
1073
1074 cmd_arg = 0;
1075
1076 if ((func == 0) || (regsize == 1)) {
1077 cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
1078 cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
1079 cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_READ);
1080 cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
1081 cmd_arg = SFIELD(cmd_arg, CMD52_DATA, 0);
1082
1083 if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg, NULL, 0))
1084 != SUCCESS)
1085 return status;
1086
1087 sdspi_cmd_getrsp(sd, &rsp5, 1);
1088
1089 if (rsp5 != 0x00)
1090 sd_err(("%s: rsp5 flags is 0x%x\t %d\n",
1091 __FUNCTION__, rsp5, func));
1092
1093 *data = sd->card_rsp_data >> 24;
1094 } else {
1095 cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize);
1096 cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1);
1097 cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0);
1098 cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func);
1099 cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, regaddr);
1100 cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_READ);
1101
1102 sd->data_xfer_count = regsize;
1103
1104 /* sdspi_cmd_issue() returns with the command complete bit
1105 * in the ISR already cleared
1106 */
1107 if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_53, cmd_arg, NULL, 0))
1108 != SUCCESS)
1109 return status;
1110
1111 sdspi_cmd_getrsp(sd, &rsp5, 1);
1112
1113 if (rsp5 != 0x00)
1114 sd_err(("%s: rsp5 flags is 0x%x\t %d\n",
1115 __FUNCTION__, rsp5, func));
1116
1117 *data = sd->card_rsp_data;
1118 if (regsize == 2) {
1119 *data &= 0xffff;
1120 }
1121
1122 sd_info(("%s: CMD53 func %d, addr 0x%x, size %d, data 0x%08x\n",
1123 __FUNCTION__, func, regaddr, regsize, *data));
1124
1125
1126 }
1127
1128 return SUCCESS;
1129}
1130
1131/* write a client register */
1132static int
1133sdspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data)
1134{
1135 int status;
1136 uint32 cmd_arg, rsp5, flags;
1137
1138 cmd_arg = 0;
1139
1140 if ((func == 0) || (regsize == 1)) {
1141 cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
1142 cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
1143 cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_WRITE);
1144 cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
1145 cmd_arg = SFIELD(cmd_arg, CMD52_DATA, data & 0xff);
1146 if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg, NULL, 0))
1147 != SUCCESS)
1148 return status;
1149
1150 sdspi_cmd_getrsp(sd, &rsp5, 1);
1151 flags = GFIELD(rsp5, RSP5_FLAGS);
1152 if (flags && (flags != 0x10))
1153 sd_err(("%s: rsp5.rsp5.flags = 0x%x, expecting 0x10\n",
1154 __FUNCTION__, flags));
1155 }
1156 else {
1157 cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize);
1158 cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1);
1159 cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0);
1160 cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func);
1161 cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, regaddr);
1162 cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_WRITE);
1163
1164 sd->data_xfer_count = regsize;
1165 sd->cmd53_wr_data = data;
1166
1167 sd_info(("%s: CMD53 func %d, addr 0x%x, size %d, data 0x%08x\n",
1168 __FUNCTION__, func, regaddr, regsize, data));
1169
1170 /* sdspi_cmd_issue() returns with the command complete bit
1171 * in the ISR already cleared
1172 */
1173 if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_53, cmd_arg, NULL, 0))
1174 != SUCCESS)
1175 return status;
1176
1177 sdspi_cmd_getrsp(sd, &rsp5, 1);
1178
1179 if (rsp5 != 0x00)
1180 sd_err(("%s: rsp5 flags = 0x%x, expecting 0x00\n",
1181 __FUNCTION__, rsp5));
1182
1183 }
1184 return SUCCESS;
1185}
1186
1187void
1188sdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count /* num 32 bit words */)
1189{
1190 *rsp_buffer = sd->card_response;
1191}
1192
1193int max_errors = 0;
1194
1195#define SPI_MAX_PKT_LEN 768
1196uint8 spi_databuf[SPI_MAX_PKT_LEN];
1197uint8 spi_rspbuf[SPI_MAX_PKT_LEN];
1198
1199/* datalen is used for CMD53 length only (0 for sd->data_xfer_count) */
1200static int
1201sdspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg,
1202 uint32 *data, uint32 datalen)
1203{
1204 uint32 cmd_reg;
1205 uint32 cmd_arg = arg;
1206 uint8 cmd_crc = 0x95; /* correct CRC for CMD0 and don't care for others. */
1207 uint16 dat_crc;
1208 uint8 cmd52data = 0;
1209 uint32 i, j;
1210 uint32 spi_datalen = 0;
1211 uint32 spi_pre_cmd_pad = 0;
1212 uint32 spi_max_response_pad = 128;
1213
1214 cmd_reg = 0;
1215 cmd_reg = SFIELD(cmd_reg, SPI_DIR, 1);
1216 cmd_reg = SFIELD(cmd_reg, SPI_CMD_INDEX, cmd);
1217
1218 if (GFIELD(cmd_arg, CMD52_RW_FLAG) == 1) { /* Same for CMD52 and CMD53 */
1219 cmd_reg = SFIELD(cmd_reg, SPI_RW, 1);
1220 }
1221
1222 switch (cmd) {
1223 case SDIOH_CMD_59: /* CRC_ON_OFF (SPI Mode Only) - Response R1 */
1224 cmd52data = arg & 0x1;
1225 case SDIOH_CMD_0: /* Set Card to Idle State - No Response */
1226 case SDIOH_CMD_5: /* Send Operation condition - Response R4 */
1227 sd_trace(("%s: CMD%d\n", __FUNCTION__, cmd));
1228 spi_datalen = 44;
1229 spi_pre_cmd_pad = 12;
1230 spi_max_response_pad = 28;
1231 break;
1232
1233 case SDIOH_CMD_3: /* Ask card to send RCA - Response R6 */
1234 case SDIOH_CMD_7: /* Select card - Response R1 */
1235 case SDIOH_CMD_15: /* Set card to inactive state - Response None */
1236 sd_err(("%s: CMD%d is invalid for SPI Mode.\n", __FUNCTION__, cmd));
1237 return ERROR;
1238 break;
1239
1240 case SDIOH_CMD_52: /* IO R/W Direct (single byte) - Response R5 */
1241 cmd52data = GFIELD(cmd_arg, CMD52_DATA);
1242 cmd_arg = arg;
1243 cmd_reg = SFIELD(cmd_reg, SPI_FUNC, GFIELD(cmd_arg, CMD52_FUNCTION));
1244 cmd_reg = SFIELD(cmd_reg, SPI_ADDR, GFIELD(cmd_arg, CMD52_REG_ADDR));
1245 /* Display trace for byte write */
1246 if (GFIELD(cmd_arg, CMD52_RW_FLAG) == 1) {
1247 sd_trace(("%s: CMD52: Wr F:%d @0x%04x=%02x\n",
1248 __FUNCTION__,
1249 GFIELD(cmd_arg, CMD52_FUNCTION),
1250 GFIELD(cmd_arg, CMD52_REG_ADDR),
1251 cmd52data));
1252 }
1253
1254 spi_datalen = 32;
1255 spi_max_response_pad = 28;
1256
1257 break;
1258 case SDIOH_CMD_53: /* IO R/W Extended (multiple bytes/blocks) */
1259 cmd_arg = arg;
1260 cmd_reg = SFIELD(cmd_reg, SPI_FUNC, GFIELD(cmd_arg, CMD53_FUNCTION));
1261 cmd_reg = SFIELD(cmd_reg, SPI_ADDR, GFIELD(cmd_arg, CMD53_REG_ADDR));
1262 cmd_reg = SFIELD(cmd_reg, SPI_BLKMODE, 0);
1263 cmd_reg = SFIELD(cmd_reg, SPI_OPCODE, GFIELD(cmd_arg, CMD53_OP_CODE));
1264 cmd_reg = SFIELD(cmd_reg, SPI_STUFF0, (sd->data_xfer_count>>8));
1265 cmd52data = (uint8)sd->data_xfer_count;
1266
1267 /* Set upper bit in byte count if necessary, but don't set it for 512 bytes. */
1268 if ((sd->data_xfer_count > 255) && (sd->data_xfer_count < 512)) {
1269 cmd_reg |= 1;
1270 }
1271
1272 if (GFIELD(cmd_reg, SPI_RW) == 1) { /* Write */
1273 spi_max_response_pad = 32;
1274 spi_datalen = (sd->data_xfer_count + spi_max_response_pad) & 0xFFFC;
1275 } else { /* Read */
1276
1277 spi_max_response_pad = 32;
1278 spi_datalen = (sd->data_xfer_count + spi_max_response_pad) & 0xFFFC;
1279 }
1280 sd_trace(("%s: CMD53: %s F:%d @0x%04x len=0x%02x\n",
1281 __FUNCTION__,
1282 (GFIELD(cmd_reg, SPI_RW) == 1 ? "Wr" : "Rd"),
1283 GFIELD(cmd_arg, CMD53_FUNCTION),
1284 GFIELD(cmd_arg, CMD53_REG_ADDR),
1285 cmd52data));
1286 break;
1287
1288 default:
1289 sd_err(("%s: Unknown command %d\n", __FUNCTION__, cmd));
1290 return ERROR;
1291 }
1292
1293 /* Set up and issue the SDIO command */
1294 memset(spi_databuf, SDSPI_IDLE_PAD, spi_datalen);
1295 spi_databuf[spi_pre_cmd_pad + 0] = (cmd_reg & 0xFF000000) >> 24;
1296 spi_databuf[spi_pre_cmd_pad + 1] = (cmd_reg & 0x00FF0000) >> 16;
1297 spi_databuf[spi_pre_cmd_pad + 2] = (cmd_reg & 0x0000FF00) >> 8;
1298 spi_databuf[spi_pre_cmd_pad + 3] = (cmd_reg & 0x000000FF);
1299 spi_databuf[spi_pre_cmd_pad + 4] = cmd52data;
1300
1301 /* Generate CRC7 for command, if CRC is enabled, otherwise, a
1302 * default CRC7 of 0x95, which is correct for CMD0, is used.
1303 */
1304 if (sd_crc) {
1305 cmd_crc = sdspi_crc7(&spi_databuf[spi_pre_cmd_pad], 5);
1306 }
1307 spi_databuf[spi_pre_cmd_pad + 5] = cmd_crc;
1308#define SPI_STOP_TRAN 0xFD
1309
1310 /* for CMD53 Write, put the data into the output buffer */
1311 if ((cmd == SDIOH_CMD_53) && (GFIELD(cmd_arg, CMD53_RW_FLAG) == 1)) {
1312 if (datalen != 0) {
1313 spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD;
1314 spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK;
1315
1316 for (i = 0; i < sd->data_xfer_count; i++) {
1317 spi_databuf[i + 11 + spi_pre_cmd_pad] = ((uint8 *)data)[i];
1318 }
1319 if (sd_crc) {
1320 dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], i);
1321 } else {
1322 dat_crc = 0xAAAA;
1323 }
1324 spi_databuf[i + 11 + spi_pre_cmd_pad] = (dat_crc >> 8) & 0xFF;
1325 spi_databuf[i + 12 + spi_pre_cmd_pad] = dat_crc & 0xFF;
1326 } else if (sd->data_xfer_count == 2) {
1327 spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD;
1328 spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK;
1329 spi_databuf[spi_pre_cmd_pad + 11] = sd->cmd53_wr_data & 0xFF;
1330 spi_databuf[spi_pre_cmd_pad + 12] = (sd->cmd53_wr_data & 0x0000FF00) >> 8;
1331 if (sd_crc) {
1332 dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], 2);
1333 } else {
1334 dat_crc = 0x22AA;
1335 }
1336 spi_databuf[spi_pre_cmd_pad + 13] = (dat_crc >> 8) & 0xFF;
1337 spi_databuf[spi_pre_cmd_pad + 14] = (dat_crc & 0xFF);
1338 } else if (sd->data_xfer_count == 4) {
1339 spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD;
1340 spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK;
1341 spi_databuf[spi_pre_cmd_pad + 11] = sd->cmd53_wr_data & 0xFF;
1342 spi_databuf[spi_pre_cmd_pad + 12] = (sd->cmd53_wr_data & 0x0000FF00) >> 8;
1343 spi_databuf[spi_pre_cmd_pad + 13] = (sd->cmd53_wr_data & 0x00FF0000) >> 16;
1344 spi_databuf[spi_pre_cmd_pad + 14] = (sd->cmd53_wr_data & 0xFF000000) >> 24;
1345 if (sd_crc) {
1346 dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], 4);
1347 } else {
1348 dat_crc = 0x44AA;
1349 }
1350 spi_databuf[spi_pre_cmd_pad + 15] = (dat_crc >> 8) & 0xFF;
1351 spi_databuf[spi_pre_cmd_pad + 16] = (dat_crc & 0xFF);
1352 } else {
1353 printf("CMD53 Write: size %d unsupported\n", sd->data_xfer_count);
1354 }
1355 }
1356
1357 spi_sendrecv(sd, spi_databuf, spi_rspbuf, spi_datalen);
1358
1359 for (i = spi_pre_cmd_pad + SDSPI_COMMAND_LEN; i < spi_max_response_pad; i++) {
1360 if ((spi_rspbuf[i] & SDSPI_START_BIT_MASK) == 0) {
1361 break;
1362 }
1363 }
1364
1365 if (i == spi_max_response_pad) {
1366 sd_err(("%s: Did not get a response for CMD%d\n", __FUNCTION__, cmd));
1367 return ERROR;
1368 }
1369
1370 /* Extract the response. */
1371 sd->card_response = spi_rspbuf[i];
1372
1373 /* for CMD53 Read, find the start of the response data... */
1374 if ((cmd == SDIOH_CMD_53) && (GFIELD(cmd_arg, CMD52_RW_FLAG) == 0)) {
1375 for (; i < spi_max_response_pad; i++) {
1376 if (spi_rspbuf[i] == SDSPI_START_BLOCK) {
1377 break;
1378 }
1379 }
1380
1381 if (i == spi_max_response_pad) {
1382 printf("Did not get a start of data phase for CMD%d\n", cmd);
1383 max_errors++;
1384 sdspi_abort(sd, GFIELD(cmd_arg, CMD53_FUNCTION));
1385 }
1386 sd->card_rsp_data = spi_rspbuf[i+1];
1387 sd->card_rsp_data |= spi_rspbuf[i+2] << 8;
1388 sd->card_rsp_data |= spi_rspbuf[i+3] << 16;
1389 sd->card_rsp_data |= spi_rspbuf[i+4] << 24;
1390
1391 if (datalen != 0) {
1392 i++;
1393 for (j = 0; j < sd->data_xfer_count; j++) {
1394 ((uint8 *)data)[j] = spi_rspbuf[i+j];
1395 }
1396 if (sd_crc) {
1397 uint16 recv_crc;
1398
1399 recv_crc = spi_rspbuf[i+j] << 8 | spi_rspbuf[i+j+1];
1400 dat_crc = sdspi_crc16((uint8 *)data, datalen);
1401 if (dat_crc != recv_crc) {
1402 sd_err(("%s: Incorrect data CRC: expected 0x%04x, "
1403 "received 0x%04x\n",
1404 __FUNCTION__, dat_crc, recv_crc));
1405 }
1406 }
1407 }
1408 return SUCCESS;
1409 }
1410
1411 sd->card_rsp_data = spi_rspbuf[i+4];
1412 sd->card_rsp_data |= spi_rspbuf[i+3] << 8;
1413 sd->card_rsp_data |= spi_rspbuf[i+2] << 16;
1414 sd->card_rsp_data |= spi_rspbuf[i+1] << 24;
1415
1416 /* Display trace for byte read */
1417 if ((cmd == SDIOH_CMD_52) && (GFIELD(cmd_arg, CMD52_RW_FLAG) == 0)) {
1418 sd_trace(("%s: CMD52: Rd F:%d @0x%04x=%02x\n",
1419 __FUNCTION__,
1420 GFIELD(cmd_arg, CMD53_FUNCTION),
1421 GFIELD(cmd_arg, CMD53_REG_ADDR),
1422 sd->card_rsp_data >> 24));
1423 }
1424
1425 return SUCCESS;
1426}
1427
1428/*
1429 * On entry: if single-block or non-block, buffer size <= block size.
1430 * If multi-block, buffer size is unlimited.
1431 * Question is how to handle the left-overs in either single- or multi-block.
1432 * I think the caller should break the buffer up so this routine will always
1433 * use block size == buffer size to handle the end piece of the buffer
1434 */
1435
1436static int
1437sdspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int nbytes, uint32 *data)
1438{
1439 int status;
1440 uint32 cmd_arg;
1441 uint32 rsp5;
1442 int num_blocks, blocksize;
1443 bool local_blockmode, local_dma;
1444 bool read = rw == SDIOH_READ ? 1 : 0;
1445
1446 ASSERT(nbytes);
1447
1448 cmd_arg = 0;
1449 sd_data(("%s: %s 53 func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n",
1450 __FUNCTION__, read ? "Rd" : "Wr", func, fifo ? "FIXED" : "INCR",
1451 addr, nbytes, sd->r_cnt, sd->t_cnt));
1452
1453 if (read) sd->r_cnt++; else sd->t_cnt++;
1454
1455 local_blockmode = sd->sd_blockmode;
1456 local_dma = sd->sd_use_dma;
1457
1458 /* Don't bother with block mode on small xfers */
1459 if (nbytes < sd->client_block_size[func]) {
1460 sd_info(("setting local blockmode to false: nbytes (%d) != block_size (%d)\n",
1461 nbytes, sd->client_block_size[func]));
1462 local_blockmode = FALSE;
1463 local_dma = FALSE;
1464 }
1465
1466 if (local_blockmode) {
1467 blocksize = MIN(sd->client_block_size[func], nbytes);
1468 num_blocks = nbytes/blocksize;
1469 cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, num_blocks);
1470 cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 1);
1471 } else {
1472 num_blocks = 1;
1473 blocksize = nbytes;
1474 cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, nbytes);
1475 cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0);
1476 }
1477
1478 if (fifo)
1479 cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 0);
1480 else
1481 cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1);
1482
1483 cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func);
1484 cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, addr);
1485 if (read)
1486 cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_READ);
1487 else
1488 cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_WRITE);
1489
1490 sd->data_xfer_count = nbytes;
1491 if ((func == 2) && (fifo == 1)) {
1492 sd_data(("%s: %s 53 func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n",
1493 __FUNCTION__, read ? "Rd" : "Wr", func, fifo ? "FIXED" : "INCR",
1494 addr, nbytes, sd->r_cnt, sd->t_cnt));
1495 }
1496
1497 /* sdspi_cmd_issue() returns with the command complete bit
1498 * in the ISR already cleared
1499 */
1500 if ((status = sdspi_cmd_issue(sd, local_dma,
1501 SDIOH_CMD_53, cmd_arg,
1502 data, nbytes)) != SUCCESS) {
1503 sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, (read ? "read" : "write")));
1504 return status;
1505 }
1506
1507 sdspi_cmd_getrsp(sd, &rsp5, 1);
1508
1509 if (rsp5 != 0x00) {
1510 sd_err(("%s: rsp5 flags = 0x%x, expecting 0x00\n",
1511 __FUNCTION__, rsp5));
1512 return ERROR;
1513 }
1514
1515 return SUCCESS;
1516}
1517
1518static int
1519set_client_block_size(sdioh_info_t *sd, int func, int block_size)
1520{
1521 int base;
1522 int err = 0;
1523
1524 sd_err(("%s: Setting block size %d, func %d\n", __FUNCTION__, block_size, func));
1525 sd->client_block_size[func] = block_size;
1526
1527 /* Set the block size in the SDIO Card register */
1528 base = func * SDIOD_FBR_SIZE;
1529 err = sdspi_card_regwrite(sd, 0, base + SDIOD_CCCR_BLKSIZE_0, 1, block_size & 0xff);
1530 if (!err) {
1531 err = sdspi_card_regwrite(sd, 0, base + SDIOD_CCCR_BLKSIZE_1, 1,
1532 (block_size >> 8) & 0xff);
1533 }
1534
1535 /*
1536 * Do not set the block size in the SDIO Host register; that
1537 * is func dependent and will get done on an individual
1538 * transaction basis.
1539 */
1540
1541 return (err ? BCME_SDIO_ERROR : 0);
1542}
1543
1544/* Reset and re-initialize the device */
1545int
1546sdioh_sdio_reset(sdioh_info_t *si)
1547{
1548 si->card_init_done = FALSE;
1549 return sdspi_client_init(si);
1550}
1551
1552#define CRC7_POLYNOM 0x09
1553#define CRC7_CRCHIGHBIT 0x40
1554
1555static uint8 sdspi_crc7(unsigned char* p, uint32 len)
1556{
1557 uint8 c, j, bit, crc = 0;
1558 uint32 i;
1559
1560 for (i = 0; i < len; i++) {
1561 c = *p++;
1562 for (j = 0x80; j; j >>= 1) {
1563 bit = crc & CRC7_CRCHIGHBIT;
1564 crc <<= 1;
1565 if (c & j) bit ^= CRC7_CRCHIGHBIT;
1566 if (bit) crc ^= CRC7_POLYNOM;
1567 }
1568 }
1569
1570 /* Convert the CRC7 to an 8-bit SD CRC */
1571 crc = (crc << 1) | 1;
1572
1573 return (crc);
1574}
1575
1576#define CRC16_POLYNOM 0x1021
1577#define CRC16_CRCHIGHBIT 0x8000
1578
1579static uint16 sdspi_crc16(unsigned char* p, uint32 len)
1580{
1581 uint32 i;
1582 uint16 j, c, bit;
1583 uint16 crc = 0;
1584
1585 for (i = 0; i < len; i++) {
1586 c = *p++;
1587 for (j = 0x80; j; j >>= 1) {
1588 bit = crc & CRC16_CRCHIGHBIT;
1589 crc <<= 1;
1590 if (c & j) bit ^= CRC16_CRCHIGHBIT;
1591 if (bit) crc ^= CRC16_POLYNOM;
1592 }
1593 }
1594
1595 return (crc);
1596}
diff --git a/drivers/net/wireless/bcm4329/bcmsdspi_linux.c b/drivers/net/wireless/bcm4329/bcmsdspi_linux.c
new file mode 100644
index 00000000000..e2e0ca6abe4
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmsdspi_linux.c
@@ -0,0 +1,252 @@
1/*
2 * Broadcom SPI Host Controller Driver - Linux Per-port
3 *
4 * Copyright (C) 1999-2010, 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_linux.c,v 1.7.2.1.4.3 2008/06/30 21:09:36 Exp $
25 */
26
27#include <typedefs.h>
28#include <pcicfg.h>
29#include <bcmutils.h>
30
31#include <sdio.h> /* SDIO Specs */
32#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
33#include <sdiovar.h> /* to get msglevel bit values */
34
35#include <linux/sched.h> /* request_irq(), free_irq() */
36
37#include <bcmsdspi.h>
38#include <bcmspi.h>
39
40extern uint sd_crc;
41module_param(sd_crc, uint, 0);
42
43#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
44#define KERNEL26
45#endif
46
47struct sdos_info {
48 sdioh_info_t *sd;
49 spinlock_t lock;
50 wait_queue_head_t intr_wait_queue;
51};
52
53#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
54#define BLOCKABLE() (!in_atomic())
55#else
56#define BLOCKABLE() (!in_interrupt())
57#endif
58
59/* Interrupt handler */
60static irqreturn_t
61sdspi_isr(int irq, void *dev_id
62#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
63, struct pt_regs *ptregs
64#endif
65)
66{
67 sdioh_info_t *sd;
68 struct sdos_info *sdos;
69 bool ours;
70
71 sd = (sdioh_info_t *)dev_id;
72 sd->local_intrcount++;
73
74 if (!sd->card_init_done) {
75 sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq));
76 return IRQ_RETVAL(FALSE);
77 } else {
78 ours = spi_check_client_intr(sd, NULL);
79
80 /* For local interrupts, wake the waiting process */
81 if (ours && sd->got_hcint) {
82 sdos = (struct sdos_info *)sd->sdos_info;
83 wake_up_interruptible(&sdos->intr_wait_queue);
84 }
85
86 return IRQ_RETVAL(ours);
87 }
88}
89
90/* Register with Linux for interrupts */
91int
92spi_register_irq(sdioh_info_t *sd, uint irq)
93{
94 sd_trace(("Entering %s: irq == %d\n", __FUNCTION__, irq));
95 if (request_irq(irq, sdspi_isr, IRQF_SHARED, "bcmsdspi", sd) < 0) {
96 sd_err(("%s: request_irq() failed\n", __FUNCTION__));
97 return ERROR;
98 }
99 return SUCCESS;
100}
101
102/* Free Linux irq */
103void
104spi_free_irq(uint irq, sdioh_info_t *sd)
105{
106 free_irq(irq, sd);
107}
108
109/* Map Host controller registers */
110
111uint32 *
112spi_reg_map(osl_t *osh, uintptr addr, int size)
113{
114 return (uint32 *)REG_MAP(addr, size);
115}
116
117void
118spi_reg_unmap(osl_t *osh, uintptr addr, int size)
119{
120 REG_UNMAP((void*)(uintptr)addr);
121}
122
123int
124spi_osinit(sdioh_info_t *sd)
125{
126 struct sdos_info *sdos;
127
128 sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info));
129 sd->sdos_info = (void*)sdos;
130 if (sdos == NULL)
131 return BCME_NOMEM;
132
133 sdos->sd = sd;
134 spin_lock_init(&sdos->lock);
135 init_waitqueue_head(&sdos->intr_wait_queue);
136 return BCME_OK;
137}
138
139void
140spi_osfree(sdioh_info_t *sd)
141{
142 struct sdos_info *sdos;
143 ASSERT(sd && sd->sdos_info);
144
145 sdos = (struct sdos_info *)sd->sdos_info;
146 MFREE(sd->osh, sdos, sizeof(struct sdos_info));
147}
148
149/* Interrupt enable/disable */
150SDIOH_API_RC
151sdioh_interrupt_set(sdioh_info_t *sd, bool enable)
152{
153 ulong flags;
154 struct sdos_info *sdos;
155
156 sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling"));
157
158 sdos = (struct sdos_info *)sd->sdos_info;
159 ASSERT(sdos);
160
161 if (!(sd->host_init_done && sd->card_init_done)) {
162 sd_err(("%s: Card & Host are not initted - bailing\n", __FUNCTION__));
163 return SDIOH_API_RC_FAIL;
164 }
165
166 if (enable && !(sd->intr_handler && sd->intr_handler_arg)) {
167 sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__));
168 return SDIOH_API_RC_FAIL;
169 }
170
171 /* Ensure atomicity for enable/disable calls */
172 spin_lock_irqsave(&sdos->lock, flags);
173
174 sd->client_intr_enabled = enable;
175 if (enable && !sd->lockcount)
176 spi_devintr_on(sd);
177 else
178 spi_devintr_off(sd);
179
180 spin_unlock_irqrestore(&sdos->lock, flags);
181
182 return SDIOH_API_RC_SUCCESS;
183}
184
185/* Protect against reentrancy (disable device interrupts while executing) */
186void
187spi_lock(sdioh_info_t *sd)
188{
189 ulong flags;
190 struct sdos_info *sdos;
191
192 sdos = (struct sdos_info *)sd->sdos_info;
193 ASSERT(sdos);
194
195 sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount));
196
197 spin_lock_irqsave(&sdos->lock, flags);
198 if (sd->lockcount) {
199 sd_err(("%s: Already locked!\n", __FUNCTION__));
200 ASSERT(sd->lockcount == 0);
201 }
202 spi_devintr_off(sd);
203 sd->lockcount++;
204 spin_unlock_irqrestore(&sdos->lock, flags);
205}
206
207/* Enable client interrupt */
208void
209spi_unlock(sdioh_info_t *sd)
210{
211 ulong flags;
212 struct sdos_info *sdos;
213
214 sd_trace(("%s: %d, %d\n", __FUNCTION__, sd->lockcount, sd->client_intr_enabled));
215 ASSERT(sd->lockcount > 0);
216
217 sdos = (struct sdos_info *)sd->sdos_info;
218 ASSERT(sdos);
219
220 spin_lock_irqsave(&sdos->lock, flags);
221 if (--sd->lockcount == 0 && sd->client_intr_enabled) {
222 spi_devintr_on(sd);
223 }
224 spin_unlock_irqrestore(&sdos->lock, flags);
225}
226
227void spi_waitbits(sdioh_info_t *sd, bool yield)
228{
229 struct sdos_info *sdos;
230
231 sdos = (struct sdos_info *)sd->sdos_info;
232
233#ifndef BCMSDYIELD
234 ASSERT(!yield);
235#endif
236 sd_trace(("%s: yield %d canblock %d\n",
237 __FUNCTION__, yield, BLOCKABLE()));
238
239 /* Clear the "interrupt happened" flag and last intrstatus */
240 sd->got_hcint = FALSE;
241
242#ifdef BCMSDYIELD
243 if (yield && BLOCKABLE()) {
244 /* Wait for the indication, the interrupt will be masked when the ISR fires. */
245 wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint));
246 } else
247#endif /* BCMSDYIELD */
248 {
249 spi_spinbits(sd);
250 }
251
252}
diff --git a/drivers/net/wireless/bcm4329/bcmsdstd.c b/drivers/net/wireless/bcm4329/bcmsdstd.c
new file mode 100644
index 00000000000..0ca1f8ff8a2
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmsdstd.c
@@ -0,0 +1,3127 @@
1/*
2 * 'Standard' SDIO HOST CONTROLLER driver
3 *
4 * Copyright (C) 1999-2010, 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.c,v 1.64.4.1.4.4.2.18 2010/08/17 17:00:48 Exp $
25 */
26
27#include <typedefs.h>
28
29#include <bcmdevs.h>
30#include <bcmendian.h>
31#include <bcmutils.h>
32#include <osl.h>
33#include <siutils.h>
34#include <sdio.h> /* SDIO Device and Protocol Specs */
35#include <sdioh.h> /* SDIO Host Controller Specification */
36#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
37#include <sdiovar.h> /* ioctl/iovars */
38#include <pcicfg.h>
39
40
41#define SD_PAGE_BITS 12
42#define SD_PAGE (1 << SD_PAGE_BITS)
43
44#include <bcmsdstd.h>
45
46/* Globals */
47uint sd_msglevel = SDH_ERROR_VAL;
48uint sd_hiok = TRUE; /* Use hi-speed mode if available? */
49uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */
50uint sd_f2_blocksize = 64; /* Default blocksize */
51
52#ifdef BCMSDYIELD
53bool sd_yieldcpu = TRUE; /* Allow CPU yielding for buffer requests */
54uint sd_minyield = 0; /* Minimum xfer size to allow CPU yield */
55bool sd_forcerb = FALSE; /* Force sync readback in intrs_on/off */
56#endif
57
58uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */
59
60uint sd_power = 1; /* Default to SD Slot powered ON */
61uint sd_clock = 1; /* Default to SD Clock turned ON */
62uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */
63uint8 sd_dma_mode = DMA_MODE_SDMA; /* Default to SDMA for now */
64
65uint sd_toctl = 7;
66
67static bool trap_errs = FALSE;
68
69static const char *dma_mode_description[] = { "PIO", "SDMA", "ADMA1", "32b ADMA2", "64b ADMA2" };
70
71/* Prototypes */
72static bool sdstd_start_clock(sdioh_info_t *sd, uint16 divisor);
73static bool sdstd_start_power(sdioh_info_t *sd);
74static bool sdstd_bus_width(sdioh_info_t *sd, int width);
75static int sdstd_set_highspeed_mode(sdioh_info_t *sd, bool HSMode);
76static int sdstd_set_dma_mode(sdioh_info_t *sd, int8 dma_mode);
77static int sdstd_card_enablefuncs(sdioh_info_t *sd);
78static void sdstd_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count);
79static int sdstd_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg);
80static int sdstd_card_regread(sdioh_info_t *sd, int func, uint32 regaddr,
81 int regsize, uint32 *data);
82static int sdstd_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr,
83 int regsize, uint32 data);
84static int sdstd_driver_init(sdioh_info_t *sd);
85static bool sdstd_reset(sdioh_info_t *sd, bool host_reset, bool client_reset);
86static int sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo,
87 uint32 addr, int nbytes, uint32 *data);
88static int sdstd_abort(sdioh_info_t *sd, uint func);
89static int sdstd_check_errs(sdioh_info_t *sdioh_info, uint32 cmd, uint32 arg);
90static int set_client_block_size(sdioh_info_t *sd, int func, int blocksize);
91static void sd_map_dma(sdioh_info_t * sd);
92static void sd_unmap_dma(sdioh_info_t * sd);
93static void sd_clear_adma_dscr_buf(sdioh_info_t *sd);
94static void sd_fill_dma_data_buf(sdioh_info_t *sd, uint8 data);
95static void sd_create_adma_descriptor(sdioh_info_t *sd,
96 uint32 index, uint32 addr_phys,
97 uint16 length, uint16 flags);
98static void sd_dump_adma_dscr(sdioh_info_t *sd);
99static void sdstd_dumpregs(sdioh_info_t *sd);
100
101
102/*
103 * Private register access routines.
104 */
105
106/* 16 bit PCI regs */
107
108extern uint16 sdstd_rreg16(sdioh_info_t *sd, uint reg);
109uint16
110sdstd_rreg16(sdioh_info_t *sd, uint reg)
111{
112
113 volatile uint16 data = *(volatile uint16 *)(sd->mem_space + reg);
114 sd_ctrl(("16: R Reg 0x%02x, Data 0x%x\n", reg, data));
115 return data;
116}
117
118extern void sdstd_wreg16(sdioh_info_t *sd, uint reg, uint16 data);
119void
120sdstd_wreg16(sdioh_info_t *sd, uint reg, uint16 data)
121{
122 *(volatile uint16 *)(sd->mem_space + reg) = (uint16)data;
123 sd_ctrl(("16: W Reg 0x%02x, Data 0x%x\n", reg, data));
124}
125
126static void
127sdstd_or_reg16(sdioh_info_t *sd, uint reg, uint16 val)
128{
129 volatile uint16 data = *(volatile uint16 *)(sd->mem_space + reg);
130 sd_ctrl(("16: OR Reg 0x%02x, Val 0x%x\n", reg, val));
131 data |= val;
132 *(volatile uint16 *)(sd->mem_space + reg) = (uint16)data;
133
134}
135static void
136sdstd_mod_reg16(sdioh_info_t *sd, uint reg, int16 mask, uint16 val)
137{
138
139 volatile uint16 data = *(volatile uint16 *)(sd->mem_space + reg);
140 sd_ctrl(("16: MOD Reg 0x%02x, Mask 0x%x, Val 0x%x\n", reg, mask, val));
141 data &= ~mask;
142 data |= (val & mask);
143 *(volatile uint16 *)(sd->mem_space + reg) = (uint16)data;
144}
145
146
147/* 32 bit PCI regs */
148static uint32
149sdstd_rreg(sdioh_info_t *sd, uint reg)
150{
151 volatile uint32 data = *(volatile uint32 *)(sd->mem_space + reg);
152 sd_ctrl(("32: R Reg 0x%02x, Data 0x%x\n", reg, data));
153 return data;
154}
155static inline void
156sdstd_wreg(sdioh_info_t *sd, uint reg, uint32 data)
157{
158 *(volatile uint32 *)(sd->mem_space + reg) = (uint32)data;
159 sd_ctrl(("32: W Reg 0x%02x, Data 0x%x\n", reg, data));
160
161}
162
163/* 8 bit PCI regs */
164static inline void
165sdstd_wreg8(sdioh_info_t *sd, uint reg, uint8 data)
166{
167 *(volatile uint8 *)(sd->mem_space + reg) = (uint8)data;
168 sd_ctrl(("08: W Reg 0x%02x, Data 0x%x\n", reg, data));
169}
170static uint8
171sdstd_rreg8(sdioh_info_t *sd, uint reg)
172{
173 volatile uint8 data = *(volatile uint8 *)(sd->mem_space + reg);
174 sd_ctrl(("08: R Reg 0x%02x, Data 0x%x\n", reg, data));
175 return data;
176}
177
178/*
179 * Private work routines
180 */
181
182sdioh_info_t *glob_sd;
183
184/*
185 * Public entry points & extern's
186 */
187extern sdioh_info_t *
188sdioh_attach(osl_t *osh, void *bar0, uint irq)
189{
190 sdioh_info_t *sd;
191
192 sd_trace(("%s\n", __FUNCTION__));
193 if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
194 sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
195 return NULL;
196 }
197 bzero((char *)sd, sizeof(sdioh_info_t));
198 glob_sd = sd;
199 sd->osh = osh;
200 if (sdstd_osinit(sd) != 0) {
201 sd_err(("%s:sdstd_osinit() failed\n", __FUNCTION__));
202 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
203 return NULL;
204 }
205 sd->mem_space = (volatile char *)sdstd_reg_map(osh, (uintptr)bar0, SDIOH_REG_WINSZ);
206 sd_init_dma(sd);
207 sd->irq = irq;
208 if (sd->mem_space == NULL) {
209 sd_err(("%s:ioremap() failed\n", __FUNCTION__));
210 sdstd_osfree(sd);
211 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
212 return NULL;
213 }
214 sd_info(("%s:sd->mem_space = %p\n", __FUNCTION__, sd->mem_space));
215 sd->intr_handler = NULL;
216 sd->intr_handler_arg = NULL;
217 sd->intr_handler_valid = FALSE;
218
219 /* Set defaults */
220 sd->sd_blockmode = TRUE;
221 sd->use_client_ints = TRUE;
222 sd->sd_dma_mode = sd_dma_mode;
223
224 if (!sd->sd_blockmode)
225 sd->sd_dma_mode = DMA_MODE_NONE;
226
227 if (sdstd_driver_init(sd) != SUCCESS) {
228 /* If host CPU was reset without resetting SD bus or
229 SD device, the device will still have its RCA but
230 driver no longer knows what it is (since driver has been restarted).
231 go through once to clear the RCA and a gain reassign it.
232 */
233 sd_info(("driver_init failed - Reset RCA and try again\n"));
234 if (sdstd_driver_init(sd) != SUCCESS) {
235 sd_err(("%s:driver_init() failed()\n", __FUNCTION__));
236 if (sd->mem_space) {
237 sdstd_reg_unmap(osh, (uintptr)sd->mem_space, SDIOH_REG_WINSZ);
238 sd->mem_space = NULL;
239 }
240 sdstd_osfree(sd);
241 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
242 return (NULL);
243 }
244 }
245
246 OSL_DMADDRWIDTH(osh, 32);
247
248 /* Always map DMA buffers, so we can switch between DMA modes. */
249 sd_map_dma(sd);
250
251 if (sdstd_register_irq(sd, irq) != SUCCESS) {
252 sd_err(("%s: sdstd_register_irq() failed for irq = %d\n", __FUNCTION__, irq));
253 sdstd_free_irq(sd->irq, sd);
254 if (sd->mem_space) {
255 sdstd_reg_unmap(osh, (uintptr)sd->mem_space, SDIOH_REG_WINSZ);
256 sd->mem_space = NULL;
257 }
258
259 sdstd_osfree(sd);
260 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
261 return (NULL);
262 }
263
264 sd_trace(("%s: Done\n", __FUNCTION__));
265 return sd;
266}
267
268extern SDIOH_API_RC
269sdioh_detach(osl_t *osh, sdioh_info_t *sd)
270{
271 sd_trace(("%s\n", __FUNCTION__));
272 if (sd) {
273 sd_unmap_dma(sd);
274 sdstd_wreg16(sd, SD_IntrSignalEnable, 0);
275 sd_trace(("%s: freeing irq %d\n", __FUNCTION__, sd->irq));
276 sdstd_free_irq(sd->irq, sd);
277 if (sd->card_init_done)
278 sdstd_reset(sd, 1, 1);
279 if (sd->mem_space) {
280 sdstd_reg_unmap(osh, (uintptr)sd->mem_space, SDIOH_REG_WINSZ);
281 sd->mem_space = NULL;
282 }
283
284 sdstd_osfree(sd);
285 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
286 }
287 return SDIOH_API_RC_SUCCESS;
288}
289
290/* Configure callback to client when we receive client interrupt */
291extern SDIOH_API_RC
292sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
293{
294 sd_trace(("%s: Entering\n", __FUNCTION__));
295 sd->intr_handler = fn;
296 sd->intr_handler_arg = argh;
297 sd->intr_handler_valid = TRUE;
298 return SDIOH_API_RC_SUCCESS;
299}
300
301extern SDIOH_API_RC
302sdioh_interrupt_deregister(sdioh_info_t *sd)
303{
304 sd_trace(("%s: Entering\n", __FUNCTION__));
305 sd->intr_handler_valid = FALSE;
306 sd->intr_handler = NULL;
307 sd->intr_handler_arg = NULL;
308 return SDIOH_API_RC_SUCCESS;
309}
310
311extern SDIOH_API_RC
312sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
313{
314 sd_trace(("%s: Entering\n", __FUNCTION__));
315 *onoff = sd->client_intr_enabled;
316 return SDIOH_API_RC_SUCCESS;
317}
318
319#if defined(DHD_DEBUG)
320extern bool
321sdioh_interrupt_pending(sdioh_info_t *sd)
322{
323 uint16 intrstatus;
324 intrstatus = sdstd_rreg16(sd, SD_IntrStatus);
325 return !!(intrstatus & CLIENT_INTR);
326}
327#endif
328
329uint
330sdioh_query_iofnum(sdioh_info_t *sd)
331{
332 return sd->num_funcs;
333}
334
335/* IOVar table */
336enum {
337 IOV_MSGLEVEL = 1,
338 IOV_BLOCKMODE,
339 IOV_BLOCKSIZE,
340 IOV_DMA,
341 IOV_USEINTS,
342 IOV_NUMINTS,
343 IOV_NUMLOCALINTS,
344 IOV_HOSTREG,
345 IOV_DEVREG,
346 IOV_DIVISOR,
347 IOV_SDMODE,
348 IOV_HISPEED,
349 IOV_HCIREGS,
350 IOV_POWER,
351 IOV_YIELDCPU,
352 IOV_MINYIELD,
353 IOV_FORCERB,
354 IOV_CLOCK
355};
356
357const bcm_iovar_t sdioh_iovars[] = {
358 {"sd_msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
359 {"sd_blockmode", IOV_BLOCKMODE, 0, IOVT_BOOL, 0 },
360 {"sd_blocksize", IOV_BLOCKSIZE, 0, IOVT_UINT32, 0 }, /* ((fn << 16) | size) */
361 {"sd_dma", IOV_DMA, 0, IOVT_UINT32, 0 },
362#ifdef BCMSDYIELD
363 {"sd_yieldcpu", IOV_YIELDCPU, 0, IOVT_BOOL, 0 },
364 {"sd_minyield", IOV_MINYIELD, 0, IOVT_UINT32, 0 },
365 {"sd_forcerb", IOV_FORCERB, 0, IOVT_BOOL, 0 },
366#endif
367 {"sd_ints", IOV_USEINTS, 0, IOVT_BOOL, 0 },
368 {"sd_numints", IOV_NUMINTS, 0, IOVT_UINT32, 0 },
369 {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32, 0 },
370 {"sd_hostreg", IOV_HOSTREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
371 {"sd_devreg", IOV_DEVREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
372 {"sd_divisor", IOV_DIVISOR, 0, IOVT_UINT32, 0 },
373 {"sd_power", IOV_POWER, 0, IOVT_UINT32, 0 },
374 {"sd_clock", IOV_CLOCK, 0, IOVT_UINT32, 0 },
375 {"sd_mode", IOV_SDMODE, 0, IOVT_UINT32, 100},
376 {"sd_highspeed", IOV_HISPEED, 0, IOVT_UINT32, 0},
377 {NULL, 0, 0, 0, 0 }
378};
379
380int
381sdioh_iovar_op(sdioh_info_t *si, const char *name,
382 void *params, int plen, void *arg, int len, bool set)
383{
384 const bcm_iovar_t *vi = NULL;
385 int bcmerror = 0;
386 int val_size;
387 int32 int_val = 0;
388 bool bool_val;
389 uint32 actionid;
390
391 ASSERT(name);
392 ASSERT(len >= 0);
393
394 /* Get must have return space; Set does not take qualifiers */
395 ASSERT(set || (arg && len));
396 ASSERT(!set || (!params && !plen));
397
398 sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
399
400 if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
401 bcmerror = BCME_UNSUPPORTED;
402 goto exit;
403 }
404
405 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
406 goto exit;
407
408 /* Set up params so get and set can share the convenience variables */
409 if (params == NULL) {
410 params = arg;
411 plen = len;
412 }
413
414 if (vi->type == IOVT_VOID)
415 val_size = 0;
416 else if (vi->type == IOVT_BUFFER)
417 val_size = len;
418 else
419 val_size = sizeof(int);
420
421 if (plen >= (int)sizeof(int_val))
422 bcopy(params, &int_val, sizeof(int_val));
423
424 bool_val = (int_val != 0) ? TRUE : FALSE;
425
426 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
427 switch (actionid) {
428 case IOV_GVAL(IOV_MSGLEVEL):
429 int_val = (int32)sd_msglevel;
430 bcopy(&int_val, arg, val_size);
431 break;
432
433 case IOV_SVAL(IOV_MSGLEVEL):
434 sd_msglevel = int_val;
435 break;
436
437 case IOV_GVAL(IOV_BLOCKMODE):
438 int_val = (int32)si->sd_blockmode;
439 bcopy(&int_val, arg, val_size);
440 break;
441
442 case IOV_SVAL(IOV_BLOCKMODE):
443 si->sd_blockmode = (bool)int_val;
444 /* Haven't figured out how to make non-block mode with DMA */
445 if (!si->sd_blockmode)
446 si->sd_dma_mode = DMA_MODE_NONE;
447 break;
448
449#ifdef BCMSDYIELD
450 case IOV_GVAL(IOV_YIELDCPU):
451 int_val = sd_yieldcpu;
452 bcopy(&int_val, arg, val_size);
453 break;
454
455 case IOV_SVAL(IOV_YIELDCPU):
456 sd_yieldcpu = (bool)int_val;
457 break;
458
459 case IOV_GVAL(IOV_MINYIELD):
460 int_val = sd_minyield;
461 bcopy(&int_val, arg, val_size);
462 break;
463
464 case IOV_SVAL(IOV_MINYIELD):
465 sd_minyield = (bool)int_val;
466 break;
467
468 case IOV_GVAL(IOV_FORCERB):
469 int_val = sd_forcerb;
470 bcopy(&int_val, arg, val_size);
471 break;
472
473 case IOV_SVAL(IOV_FORCERB):
474 sd_forcerb = (bool)int_val;
475 break;
476#endif /* BCMSDYIELD */
477
478 case IOV_GVAL(IOV_BLOCKSIZE):
479 if ((uint32)int_val > si->num_funcs) {
480 bcmerror = BCME_BADARG;
481 break;
482 }
483 int_val = (int32)si->client_block_size[int_val];
484 bcopy(&int_val, arg, val_size);
485 break;
486
487 case IOV_SVAL(IOV_BLOCKSIZE):
488 {
489 uint func = ((uint32)int_val >> 16);
490 uint blksize = (uint16)int_val;
491 uint maxsize;
492
493 if (func > si->num_funcs) {
494 bcmerror = BCME_BADARG;
495 break;
496 }
497
498 switch (func) {
499 case 0: maxsize = 32; break;
500 case 1: maxsize = BLOCK_SIZE_4318; break;
501 case 2: maxsize = BLOCK_SIZE_4328; break;
502 default: maxsize = 0;
503 }
504 if (blksize > maxsize) {
505 bcmerror = BCME_BADARG;
506 break;
507 }
508 if (!blksize) {
509 blksize = maxsize;
510 }
511
512 /* Now set it */
513 sdstd_lock(si);
514 bcmerror = set_client_block_size(si, func, blksize);
515 sdstd_unlock(si);
516 break;
517 }
518
519 case IOV_GVAL(IOV_DMA):
520 int_val = (int32)si->sd_dma_mode;
521 bcopy(&int_val, arg, val_size);
522 break;
523
524 case IOV_SVAL(IOV_DMA):
525 si->sd_dma_mode = (char)int_val;
526 sdstd_set_dma_mode(si, si->sd_dma_mode);
527 break;
528
529 case IOV_GVAL(IOV_USEINTS):
530 int_val = (int32)si->use_client_ints;
531 bcopy(&int_val, arg, val_size);
532 break;
533
534 case IOV_SVAL(IOV_USEINTS):
535 si->use_client_ints = (bool)int_val;
536 if (si->use_client_ints)
537 si->intmask |= CLIENT_INTR;
538 else
539 si->intmask &= ~CLIENT_INTR;
540 break;
541
542 case IOV_GVAL(IOV_DIVISOR):
543 int_val = (uint32)sd_divisor;
544 bcopy(&int_val, arg, val_size);
545 break;
546
547 case IOV_SVAL(IOV_DIVISOR):
548 sd_divisor = int_val;
549 if (!sdstd_start_clock(si, (uint16)sd_divisor)) {
550 sd_err(("set clock failed!\n"));
551 bcmerror = BCME_ERROR;
552 }
553 break;
554
555 case IOV_GVAL(IOV_POWER):
556 int_val = (uint32)sd_power;
557 bcopy(&int_val, arg, val_size);
558 break;
559
560 case IOV_SVAL(IOV_POWER):
561 sd_power = int_val;
562 if (sd_power == 1) {
563 if (sdstd_driver_init(si) != SUCCESS) {
564 sd_err(("set SD Slot power failed!\n"));
565 bcmerror = BCME_ERROR;
566 } else {
567 sd_err(("SD Slot Powered ON.\n"));
568 }
569 } else {
570 uint8 pwr = 0;
571
572 pwr = SFIELD(pwr, PWR_BUS_EN, 0);
573 sdstd_wreg8(si, SD_PwrCntrl, pwr); /* Set Voltage level */
574 sd_err(("SD Slot Powered OFF.\n"));
575 }
576 break;
577
578 case IOV_GVAL(IOV_CLOCK):
579 int_val = (uint32)sd_clock;
580 bcopy(&int_val, arg, val_size);
581 break;
582
583 case IOV_SVAL(IOV_CLOCK):
584 sd_clock = int_val;
585 if (sd_clock == 1) {
586 sd_info(("SD Clock turned ON.\n"));
587 if (!sdstd_start_clock(si, (uint16)sd_divisor)) {
588 sd_err(("sdstd_start_clock failed\n"));
589 bcmerror = BCME_ERROR;
590 }
591 } else {
592 /* turn off HC clock */
593 sdstd_wreg16(si, SD_ClockCntrl,
594 sdstd_rreg16(si, SD_ClockCntrl) & ~((uint16)0x4));
595
596 sd_info(("SD Clock turned OFF.\n"));
597 }
598 break;
599
600 case IOV_GVAL(IOV_SDMODE):
601 int_val = (uint32)sd_sdmode;
602 bcopy(&int_val, arg, val_size);
603 break;
604
605 case IOV_SVAL(IOV_SDMODE):
606 sd_sdmode = int_val;
607
608 if (!sdstd_bus_width(si, sd_sdmode)) {
609 sd_err(("sdstd_bus_width failed\n"));
610 bcmerror = BCME_ERROR;
611 }
612 break;
613
614 case IOV_GVAL(IOV_HISPEED):
615 int_val = (uint32)sd_hiok;
616 bcopy(&int_val, arg, val_size);
617 break;
618
619 case IOV_SVAL(IOV_HISPEED):
620 sd_hiok = int_val;
621 bcmerror = sdstd_set_highspeed_mode(si, (bool)sd_hiok);
622 break;
623
624 case IOV_GVAL(IOV_NUMINTS):
625 int_val = (int32)si->intrcount;
626 bcopy(&int_val, arg, val_size);
627 break;
628
629 case IOV_GVAL(IOV_NUMLOCALINTS):
630 int_val = (int32)si->local_intrcount;
631 bcopy(&int_val, arg, val_size);
632 break;
633
634 case IOV_GVAL(IOV_HOSTREG):
635 {
636 sdreg_t *sd_ptr = (sdreg_t *)params;
637
638 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
639 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
640 bcmerror = BCME_BADARG;
641 break;
642 }
643
644 sd_trace(("%s: rreg%d at offset %d\n", __FUNCTION__,
645 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
646 sd_ptr->offset));
647 if (sd_ptr->offset & 1)
648 int_val = sdstd_rreg8(si, sd_ptr->offset);
649 else if (sd_ptr->offset & 2)
650 int_val = sdstd_rreg16(si, sd_ptr->offset);
651 else
652 int_val = sdstd_rreg(si, sd_ptr->offset);
653
654 bcopy(&int_val, arg, sizeof(int_val));
655 break;
656 }
657
658 case IOV_SVAL(IOV_HOSTREG):
659 {
660 sdreg_t *sd_ptr = (sdreg_t *)params;
661
662 if (sd_ptr->offset < SD_SysAddr || sd_ptr->offset > SD_MaxCurCap) {
663 sd_err(("%s: bad offset 0x%x\n", __FUNCTION__, sd_ptr->offset));
664 bcmerror = BCME_BADARG;
665 break;
666 }
667
668 sd_trace(("%s: wreg%d value 0x%08x at offset %d\n", __FUNCTION__, sd_ptr->value,
669 (sd_ptr->offset & 1) ? 8 : ((sd_ptr->offset & 2) ? 16 : 32),
670 sd_ptr->offset));
671 if (sd_ptr->offset & 1)
672 sdstd_wreg8(si, sd_ptr->offset, (uint8)sd_ptr->value);
673 else if (sd_ptr->offset & 2)
674 sdstd_wreg16(si, sd_ptr->offset, (uint16)sd_ptr->value);
675 else
676 sdstd_wreg(si, sd_ptr->offset, (uint32)sd_ptr->value);
677
678 break;
679 }
680
681 case IOV_GVAL(IOV_DEVREG):
682 {
683 sdreg_t *sd_ptr = (sdreg_t *)params;
684 uint8 data;
685
686 if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
687 bcmerror = BCME_SDIO_ERROR;
688 break;
689 }
690
691 int_val = (int)data;
692 bcopy(&int_val, arg, sizeof(int_val));
693 break;
694 }
695
696 case IOV_SVAL(IOV_DEVREG):
697 {
698 sdreg_t *sd_ptr = (sdreg_t *)params;
699 uint8 data = (uint8)sd_ptr->value;
700
701 if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
702 bcmerror = BCME_SDIO_ERROR;
703 break;
704 }
705 break;
706 }
707
708
709 default:
710 bcmerror = BCME_UNSUPPORTED;
711 break;
712 }
713exit:
714
715 return bcmerror;
716}
717
718extern SDIOH_API_RC
719sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
720{
721 SDIOH_API_RC status;
722 /* No lock needed since sdioh_request_byte does locking */
723 status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
724 return status;
725}
726
727extern SDIOH_API_RC
728sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
729{
730 /* No lock needed since sdioh_request_byte does locking */
731 SDIOH_API_RC status;
732 status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
733 return status;
734}
735
736extern SDIOH_API_RC
737sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
738{
739 uint32 count;
740 int offset;
741 uint32 foo;
742 uint8 *cis = cisd;
743
744 sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
745
746 if (!sd->func_cis_ptr[func]) {
747 bzero(cis, length);
748 return SDIOH_API_RC_FAIL;
749 }
750
751 sdstd_lock(sd);
752 *cis = 0;
753 for (count = 0; count < length; count++) {
754 offset = sd->func_cis_ptr[func] + count;
755 if (sdstd_card_regread(sd, 0, offset, 1, &foo)) {
756 sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
757 sdstd_unlock(sd);
758 return SDIOH_API_RC_FAIL;
759 }
760 *cis = (uint8)(foo & 0xff);
761 cis++;
762 }
763 sdstd_unlock(sd);
764 return SDIOH_API_RC_SUCCESS;
765}
766
767extern SDIOH_API_RC
768sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
769{
770 int status;
771 uint32 cmd_arg;
772 uint32 rsp5;
773
774 sdstd_lock(sd);
775 cmd_arg = 0;
776 cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
777 cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
778 cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, rw == SDIOH_READ ? 0 : 1);
779 cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
780 cmd_arg = SFIELD(cmd_arg, CMD52_DATA, rw == SDIOH_READ ? 0 : *byte);
781
782 if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_52, cmd_arg)) != SUCCESS) {
783 sdstd_unlock(sd);
784 return status;
785 }
786
787 sdstd_cmd_getrsp(sd, &rsp5, 1);
788 if (sdstd_rreg16 (sd, SD_ErrorIntrStatus) != 0) {
789 sd_err(("%s: 1: ErrorintrStatus 0x%x\n",
790 __FUNCTION__, sdstd_rreg16(sd, SD_ErrorIntrStatus)));
791 }
792 if (GFIELD(rsp5, RSP5_FLAGS) != 0x10)
793 sd_err(("%s: rsp5 flags is 0x%x\t %d\n",
794 __FUNCTION__, GFIELD(rsp5, RSP5_FLAGS), func));
795
796 if (GFIELD(rsp5, RSP5_STUFF))
797 sd_err(("%s: rsp5 stuff is 0x%x: should be 0\n",
798 __FUNCTION__, GFIELD(rsp5, RSP5_STUFF)));
799
800 if (rw == SDIOH_READ)
801 *byte = GFIELD(rsp5, RSP5_DATA);
802
803 sdstd_unlock(sd);
804 return SDIOH_API_RC_SUCCESS;
805}
806
807extern SDIOH_API_RC
808sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
809 uint32 *word, uint nbytes)
810{
811 int status;
812 bool swap = FALSE;
813
814 sdstd_lock(sd);
815
816 if (rw == SDIOH_READ) {
817 status = sdstd_card_regread(sd, func, addr, nbytes, word);
818 if (swap)
819 *word = BCMSWAP32(*word);
820 } else {
821 if (swap)
822 *word = BCMSWAP32(*word);
823 status = sdstd_card_regwrite(sd, func, addr, nbytes, *word);
824 }
825
826 sdstd_unlock(sd);
827 return (status == SUCCESS ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
828}
829
830extern SDIOH_API_RC
831sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func,
832 uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
833{
834 int len;
835 int buflen = (int)buflen_u;
836 bool fifo = (fix_inc == SDIOH_DATA_FIX);
837 uint8 *localbuf = NULL, *tmpbuf = NULL;
838 uint tmplen = 0;
839 bool local_blockmode = sd->sd_blockmode;
840
841 sdstd_lock(sd);
842
843 ASSERT(reg_width == 4);
844 ASSERT(buflen_u < (1 << 30));
845 ASSERT(sd->client_block_size[func]);
846
847 sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n",
848 __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W',
849 buflen_u, sd->r_cnt, sd->t_cnt, pkt));
850
851 /* Break buffer down into blocksize chunks:
852 * Bytemode: 1 block at a time.
853 * Blockmode: Multiples of blocksizes at a time w/ max of SD_PAGE.
854 * Both: leftovers are handled last (will be sent via bytemode).
855 */
856 while (buflen > 0) {
857 if (local_blockmode) {
858 /* Max xfer is Page size */
859 len = MIN(SD_PAGE, buflen);
860
861 /* Round down to a block boundry */
862 if (buflen > sd->client_block_size[func])
863 len = (len/sd->client_block_size[func]) *
864 sd->client_block_size[func];
865 if ((func == SDIO_FUNC_1) && ((len % 4) == 3) && (rw == SDIOH_WRITE)) {
866 tmplen = len;
867 sd_err(("%s: Rounding up buffer to mod4 length.\n", __FUNCTION__));
868 len++;
869 tmpbuf = buffer;
870 if ((localbuf = (uint8 *)MALLOC(sd->osh, len)) == NULL) {
871 sd_err(("out of memory, malloced %d bytes\n",
872 MALLOCED(sd->osh)));
873 sdstd_unlock(sd);
874 return SDIOH_API_RC_FAIL;
875 }
876 bcopy(buffer, localbuf, len);
877 buffer = localbuf;
878 }
879 } else {
880 /* Byte mode: One block at a time */
881 len = MIN(sd->client_block_size[func], buflen);
882 }
883
884 if (sdstd_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) {
885 sdstd_unlock(sd);
886 return SDIOH_API_RC_FAIL;
887 }
888
889 if (local_blockmode) {
890 if ((func == SDIO_FUNC_1) && ((tmplen % 4) == 3) && (rw == SDIOH_WRITE)) {
891 if (localbuf)
892 MFREE(sd->osh, localbuf, len);
893 len--;
894 buffer = tmpbuf;
895 sd_err(("%s: Restoring back buffer ptr and len.\n", __FUNCTION__));
896 }
897 }
898
899 buffer += len;
900 buflen -= len;
901 if (!fifo)
902 addr += len;
903 }
904 sdstd_unlock(sd);
905 return SDIOH_API_RC_SUCCESS;
906}
907
908static
909int sdstd_abort(sdioh_info_t *sd, uint func)
910{
911 int err = 0;
912 int retries;
913
914 uint16 cmd_reg;
915 uint32 cmd_arg;
916 uint32 rsp5;
917 uint8 rflags;
918
919 uint16 int_reg = 0;
920 uint16 plain_intstatus;
921
922 /* Argument is write to F0 (CCCR) IOAbort with function number */
923 cmd_arg = 0;
924 cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, SDIO_FUNC_0);
925 cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, SDIOD_CCCR_IOABORT);
926 cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SD_IO_OP_WRITE);
927 cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
928 cmd_arg = SFIELD(cmd_arg, CMD52_DATA, func);
929
930 /* Command is CMD52 write */
931 cmd_reg = 0;
932 cmd_reg = SFIELD(cmd_reg, CMD_RESP_TYPE, RESP_TYPE_48_BUSY);
933 cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 1);
934 cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 1);
935 cmd_reg = SFIELD(cmd_reg, CMD_DATA_EN, 0);
936 cmd_reg = SFIELD(cmd_reg, CMD_TYPE, CMD_TYPE_ABORT);
937 cmd_reg = SFIELD(cmd_reg, CMD_INDEX, SDIOH_CMD_52);
938
939 if (sd->sd_mode == SDIOH_MODE_SPI) {
940 cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 0);
941 cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 0);
942 }
943
944 /* Wait for CMD_INHIBIT to go away as per spec section 3.6.1.1 */
945 retries = RETRIES_SMALL;
946 while (GFIELD(sdstd_rreg(sd, SD_PresentState), PRES_CMD_INHIBIT)) {
947 if (retries == RETRIES_SMALL)
948 sd_err(("%s: Waiting for Command Inhibit, state 0x%08x\n",
949 __FUNCTION__, sdstd_rreg(sd, SD_PresentState)));
950 if (!--retries) {
951 sd_err(("%s: Command Inhibit timeout, state 0x%08x\n",
952 __FUNCTION__, sdstd_rreg(sd, SD_PresentState)));
953 if (trap_errs)
954 ASSERT(0);
955 err = BCME_SDIO_ERROR;
956 goto done;
957 }
958 }
959
960 /* Clear errors from any previous commands */
961 if ((plain_intstatus = sdstd_rreg16(sd, SD_ErrorIntrStatus)) != 0) {
962 sd_err(("abort: clearing errstat 0x%04x\n", plain_intstatus));
963 sdstd_wreg16(sd, SD_ErrorIntrStatus, plain_intstatus);
964 }
965 plain_intstatus = sdstd_rreg16(sd, SD_IntrStatus);
966 if (plain_intstatus & ~(SFIELD(0, INTSTAT_CARD_INT, 1))) {
967 sd_err(("abort: intstatus 0x%04x\n", plain_intstatus));
968 if (GFIELD(plain_intstatus, INTSTAT_CMD_COMPLETE)) {
969 sd_err(("SDSTD_ABORT: CMD COMPLETE SET BEFORE COMMAND GIVEN!!!\n"));
970 }
971 if (GFIELD(plain_intstatus, INTSTAT_CARD_REMOVAL)) {
972 sd_err(("SDSTD_ABORT: INTSTAT_CARD_REMOVAL\n"));
973 err = BCME_NODEVICE;
974 goto done;
975 }
976 }
977
978 /* Issue the command */
979 sdstd_wreg(sd, SD_Arg0, cmd_arg);
980 sdstd_wreg16(sd, SD_Command, cmd_reg);
981
982 /* In interrupt mode return, expect later CMD_COMPLETE interrupt */
983 if (!sd->polled_mode)
984 return err;
985
986 /* Otherwise, wait for the command to complete */
987 retries = RETRIES_LARGE;
988 do {
989 int_reg = sdstd_rreg16(sd, SD_IntrStatus);
990 } while (--retries &&
991 (GFIELD(int_reg, INTSTAT_ERROR_INT) == 0) &&
992 (GFIELD(int_reg, INTSTAT_CMD_COMPLETE) == 0));
993
994 /* If command completion fails, do a cmd reset and note the error */
995 if (!retries) {
996 sd_err(("%s: CMD_COMPLETE timeout: intr 0x%04x err 0x%04x state 0x%08x\n",
997 __FUNCTION__, int_reg,
998 sdstd_rreg16(sd, SD_ErrorIntrStatus),
999 sdstd_rreg(sd, SD_PresentState)));
1000
1001 sdstd_wreg8(sd, SD_SoftwareReset, SFIELD(0, SW_RESET_CMD, 1));
1002 retries = RETRIES_LARGE;
1003 do {
1004 sd_trace(("%s: waiting for CMD line reset\n", __FUNCTION__));
1005 } while ((GFIELD(sdstd_rreg8(sd, SD_SoftwareReset),
1006 SW_RESET_CMD)) && retries--);
1007
1008 if (!retries) {
1009 sd_err(("%s: Timeout waiting for CMD line reset\n", __FUNCTION__));
1010 }
1011
1012 if (trap_errs)
1013 ASSERT(0);
1014
1015 err = BCME_SDIO_ERROR;
1016 }
1017
1018 /* Clear Command Complete interrupt */
1019 int_reg = SFIELD(0, INTSTAT_CMD_COMPLETE, 1);
1020 sdstd_wreg16(sd, SD_IntrStatus, int_reg);
1021
1022 /* Check for Errors */
1023 if ((plain_intstatus = sdstd_rreg16 (sd, SD_ErrorIntrStatus)) != 0) {
1024 sd_err(("%s: ErrorintrStatus: 0x%x, "
1025 "(intrstatus = 0x%x, present state 0x%x) clearing\n",
1026 __FUNCTION__, plain_intstatus,
1027 sdstd_rreg16(sd, SD_IntrStatus),
1028 sdstd_rreg(sd, SD_PresentState)));
1029
1030 sdstd_wreg16(sd, SD_ErrorIntrStatus, plain_intstatus);
1031
1032 sdstd_wreg8(sd, SD_SoftwareReset, SFIELD(0, SW_RESET_DAT, 1));
1033 retries = RETRIES_LARGE;
1034 do {
1035 sd_trace(("%s: waiting for DAT line reset\n", __FUNCTION__));
1036 } while ((GFIELD(sdstd_rreg8(sd, SD_SoftwareReset),
1037 SW_RESET_DAT)) && retries--);
1038
1039 if (!retries) {
1040 sd_err(("%s: Timeout waiting for DAT line reset\n", __FUNCTION__));
1041 }
1042
1043 if (trap_errs)
1044 ASSERT(0);
1045
1046 /* ABORT is dataless, only cmd errs count */
1047 if (plain_intstatus & ERRINT_CMD_ERRS)
1048 err = BCME_SDIO_ERROR;
1049 }
1050
1051 /* If command failed don't bother looking at response */
1052 if (err)
1053 goto done;
1054
1055 /* Otherwise, check the response */
1056 sdstd_cmd_getrsp(sd, &rsp5, 1);
1057 rflags = GFIELD(rsp5, RSP5_FLAGS);
1058
1059 if (rflags & SD_RSP_R5_ERRBITS) {
1060 sd_err(("%s: R5 flags include errbits: 0x%02x\n", __FUNCTION__, rflags));
1061
1062 /* The CRC error flag applies to the previous command */
1063 if (rflags & (SD_RSP_R5_ERRBITS & ~SD_RSP_R5_COM_CRC_ERROR)) {
1064 err = BCME_SDIO_ERROR;
1065 goto done;
1066 }
1067 }
1068
1069 if (((rflags & (SD_RSP_R5_IO_CURRENTSTATE0 | SD_RSP_R5_IO_CURRENTSTATE1)) != 0x10) &&
1070 ((rflags & (SD_RSP_R5_IO_CURRENTSTATE0 | SD_RSP_R5_IO_CURRENTSTATE1)) != 0x20)) {
1071 sd_err(("%s: R5 flags has bad state: 0x%02x\n", __FUNCTION__, rflags));
1072 err = BCME_SDIO_ERROR;
1073 goto done;
1074 }
1075
1076 if (GFIELD(rsp5, RSP5_STUFF)) {
1077 sd_err(("%s: rsp5 stuff is 0x%x: should be 0\n",
1078 __FUNCTION__, GFIELD(rsp5, RSP5_STUFF)));
1079 err = BCME_SDIO_ERROR;
1080 goto done;
1081 }
1082
1083done:
1084 if (err == BCME_NODEVICE)
1085 return err;
1086
1087 sdstd_wreg8(sd, SD_SoftwareReset,
1088 SFIELD(SFIELD(0, SW_RESET_DAT, 1), SW_RESET_CMD, 1));
1089
1090 retries = RETRIES_LARGE;
1091 do {
1092 rflags = sdstd_rreg8(sd, SD_SoftwareReset);
1093 if (!GFIELD(rflags, SW_RESET_DAT) && !GFIELD(rflags, SW_RESET_CMD))
1094 break;
1095 } while (--retries);
1096
1097 if (!retries) {
1098 sd_err(("%s: Timeout waiting for DAT/CMD reset: 0x%02x\n",
1099 __FUNCTION__, rflags));
1100 err = BCME_SDIO_ERROR;
1101 }
1102
1103 return err;
1104}
1105
1106extern int
1107sdioh_abort(sdioh_info_t *sd, uint fnum)
1108{
1109 int ret;
1110
1111 sdstd_lock(sd);
1112 ret = sdstd_abort(sd, fnum);
1113 sdstd_unlock(sd);
1114
1115 return ret;
1116}
1117
1118int
1119sdioh_start(sdioh_info_t *sd, int stage)
1120{
1121 return SUCCESS;
1122}
1123
1124int
1125sdioh_stop(sdioh_info_t *sd)
1126{
1127 return SUCCESS;
1128}
1129
1130static int
1131sdstd_check_errs(sdioh_info_t *sdioh_info, uint32 cmd, uint32 arg)
1132{
1133 uint16 regval;
1134 uint retries;
1135 uint function = 0;
1136
1137 /* If no errors, we're done */
1138 if ((regval = sdstd_rreg16(sdioh_info, SD_ErrorIntrStatus)) == 0)
1139 return SUCCESS;
1140
1141 sd_info(("%s: ErrorIntrStatus 0x%04x (clearing), IntrStatus 0x%04x PresentState 0x%08x\n",
1142 __FUNCTION__, regval, sdstd_rreg16(sdioh_info, SD_IntrStatus),
1143 sdstd_rreg(sdioh_info, SD_PresentState)));
1144 sdstd_wreg16(sdioh_info, SD_ErrorIntrStatus, regval);
1145
1146 /* On command error, issue CMD reset */
1147 if (regval & ERRINT_CMD_ERRS) {
1148 sd_trace(("%s: issuing CMD reset\n", __FUNCTION__));
1149 sdstd_wreg8(sdioh_info, SD_SoftwareReset, SFIELD(0, SW_RESET_CMD, 1));
1150 for (retries = RETRIES_LARGE; retries; retries--)
1151 if (!(GFIELD(sdstd_rreg8(sdioh_info, SD_SoftwareReset), SW_RESET_CMD)))
1152 break;
1153 if (!retries) {
1154 sd_err(("%s: Timeout waiting for CMD line reset\n", __FUNCTION__));
1155 }
1156 }
1157
1158 /* On data error, issue DAT reset */
1159 if (regval & ERRINT_DATA_ERRS) {
1160 sd_trace(("%s: issuing DAT reset\n", __FUNCTION__));
1161 sdstd_wreg8(sdioh_info, SD_SoftwareReset, SFIELD(0, SW_RESET_DAT, 1));
1162 for (retries = RETRIES_LARGE; retries; retries--)
1163 if (!(GFIELD(sdstd_rreg8(sdioh_info, SD_SoftwareReset), SW_RESET_DAT)))
1164 break;
1165 if (!retries) {
1166 sd_err(("%s: Timeout waiting for DAT line reset\n", __FUNCTION__));
1167 }
1168 }
1169
1170 /* For an IO command (CMD52 or CMD53) issue an abort to the appropriate function */
1171 if (cmd == SDIOH_CMD_53)
1172 function = GFIELD(arg, CMD53_FUNCTION);
1173 else if (cmd == SDIOH_CMD_52)
1174 function = GFIELD(arg, CMD52_FUNCTION);
1175 if (function) {
1176 sd_trace(("%s: requesting abort for function %d after cmd %d\n",
1177 __FUNCTION__, function, cmd));
1178 sdstd_abort(sdioh_info, function);
1179 }
1180
1181 if (trap_errs)
1182 ASSERT(0);
1183
1184 return ERROR;
1185}
1186
1187
1188
1189/*
1190 * Private/Static work routines
1191 */
1192static bool
1193sdstd_reset(sdioh_info_t *sd, bool host_reset, bool client_reset)
1194{
1195 int retries = RETRIES_LARGE;
1196 uchar regval;
1197
1198 if (!sd)
1199 return TRUE;
1200
1201 sdstd_lock(sd);
1202 /* Reset client card */
1203 if (client_reset && (sd->adapter_slot != -1)) {
1204 if (sdstd_card_regwrite(sd, 0, SDIOD_CCCR_IOABORT, 1, 0x8) != SUCCESS)
1205 sd_err(("%s: Cannot write to card reg 0x%x\n",
1206 __FUNCTION__, SDIOD_CCCR_IOABORT));
1207 else
1208 sd->card_rca = 0;
1209 }
1210
1211 /* Reset host controller */
1212 if (host_reset) {
1213 regval = SFIELD(0, SW_RESET_ALL, 1);
1214 sdstd_wreg8(sd, SD_SoftwareReset, regval);
1215 do {
1216 sd_trace(("%s: waiting for reset\n", __FUNCTION__));
1217 } while ((sdstd_rreg8(sd, SD_SoftwareReset) & regval) && retries--);
1218
1219 if (!retries) {
1220 sd_err(("%s: Timeout waiting for host reset\n", __FUNCTION__));
1221 sdstd_unlock(sd);
1222 return (FALSE);
1223 }
1224
1225 /* A reset should reset bus back to 1 bit mode */
1226 sd->sd_mode = SDIOH_MODE_SD1;
1227 sdstd_set_dma_mode(sd, sd->sd_dma_mode);
1228 }
1229 sdstd_unlock(sd);
1230 return TRUE;
1231}
1232
1233/* Disable device interrupt */
1234void
1235sdstd_devintr_off(sdioh_info_t *sd)
1236{
1237 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1238 if (sd->use_client_ints) {
1239 sd->intmask &= ~CLIENT_INTR;
1240 sdstd_wreg16(sd, SD_IntrSignalEnable, sd->intmask);
1241 sdstd_rreg16(sd, SD_IntrSignalEnable); /* Sync readback */
1242 }
1243}
1244
1245/* Enable device interrupt */
1246void
1247sdstd_devintr_on(sdioh_info_t *sd)
1248{
1249 ASSERT(sd->lockcount == 0);
1250 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints));
1251 if (sd->use_client_ints) {
1252 uint16 status = sdstd_rreg16(sd, SD_IntrStatusEnable);
1253 sdstd_wreg16(sd, SD_IntrStatusEnable, SFIELD(status, INTSTAT_CARD_INT, 0));
1254 sdstd_wreg16(sd, SD_IntrStatusEnable, status);
1255
1256 sd->intmask |= CLIENT_INTR;
1257 sdstd_wreg16(sd, SD_IntrSignalEnable, sd->intmask);
1258 sdstd_rreg16(sd, SD_IntrSignalEnable); /* Sync readback */
1259 }
1260}
1261
1262#ifdef BCMSDYIELD
1263/* Enable/disable other interrupts */
1264void
1265sdstd_intrs_on(sdioh_info_t *sd, uint16 norm, uint16 err)
1266{
1267 if (err) {
1268 norm = SFIELD(norm, INTSTAT_ERROR_INT, 1);
1269 sdstd_wreg16(sd, SD_ErrorIntrSignalEnable, err);
1270 }
1271
1272 sd->intmask |= norm;
1273 sdstd_wreg16(sd, SD_IntrSignalEnable, sd->intmask);
1274 if (sd_forcerb)
1275 sdstd_rreg16(sd, SD_IntrSignalEnable); /* Sync readback */
1276}
1277
1278void
1279sdstd_intrs_off(sdioh_info_t *sd, uint16 norm, uint16 err)
1280{
1281 if (err) {
1282 norm = SFIELD(norm, INTSTAT_ERROR_INT, 1);
1283 sdstd_wreg16(sd, SD_ErrorIntrSignalEnable, 0);
1284 }
1285
1286 sd->intmask &= ~norm;
1287 sdstd_wreg16(sd, SD_IntrSignalEnable, sd->intmask);
1288 if (sd_forcerb)
1289 sdstd_rreg16(sd, SD_IntrSignalEnable); /* Sync readback */
1290}
1291#endif /* BCMSDYIELD */
1292
1293static int
1294sdstd_host_init(sdioh_info_t *sd)
1295{
1296 int num_slots, full_slot;
1297 uint8 reg8;
1298
1299 uint32 card_ins;
1300 int slot, first_bar = 0;
1301 bool detect_slots = FALSE;
1302 uint bar;
1303
1304 /* Check for Arasan ID */
1305 if ((OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_VID, 4) & 0xFFFF) == VENDOR_SI_IMAGE) {
1306 sd_info(("%s: Found Arasan Standard SDIO Host Controller\n", __FUNCTION__));
1307 sd->controller_type = SDIOH_TYPE_ARASAN_HDK;
1308 detect_slots = TRUE;
1309 } else if ((OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_VID, 4) & 0xFFFF) == VENDOR_BROADCOM) {
1310 sd_info(("%s: Found Broadcom 27xx Standard SDIO Host Controller\n", __FUNCTION__));
1311 sd->controller_type = SDIOH_TYPE_BCM27XX;
1312 detect_slots = FALSE;
1313 } else if ((OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_VID, 4) & 0xFFFF) == VENDOR_TI) {
1314 sd_info(("%s: Found TI PCIxx21 Standard SDIO Host Controller\n", __FUNCTION__));
1315 sd->controller_type = SDIOH_TYPE_TI_PCIXX21;
1316 detect_slots = TRUE;
1317 } else if ((OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_VID, 4) & 0xFFFF) == VENDOR_RICOH) {
1318 sd_info(("%s: Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter\n",
1319 __FUNCTION__));
1320 sd->controller_type = SDIOH_TYPE_RICOH_R5C822;
1321 detect_slots = TRUE;
1322 } else if ((OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_VID, 4) & 0xFFFF) == VENDOR_JMICRON) {
1323 sd_info(("%s: JMicron Standard SDIO Host Controller\n",
1324 __FUNCTION__));
1325 sd->controller_type = SDIOH_TYPE_JMICRON;
1326 detect_slots = TRUE;
1327 } else {
1328 return ERROR;
1329 }
1330
1331 /*
1332 * Determine num of slots
1333 * Search each slot
1334 */
1335
1336 first_bar = OSL_PCI_READ_CONFIG(sd->osh, SD_SlotInfo, 4) & 0x7;
1337 num_slots = (OSL_PCI_READ_CONFIG(sd->osh, SD_SlotInfo, 4) & 0xff) >> 4;
1338 num_slots &= 7;
1339 num_slots++; /* map bits to num slots according to spec */
1340
1341 if (OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_VID, 4) ==
1342 ((SDIOH_FPGA_ID << 16) | VENDOR_BROADCOM)) {
1343 sd_err(("%s: Found Broadcom Standard SDIO Host Controller FPGA\n", __FUNCTION__));
1344 /* Set BAR0 Window to SDIOSTH core */
1345 OSL_PCI_WRITE_CONFIG(sd->osh, PCI_BAR0_WIN, 4, 0x18001000);
1346
1347 /* Set defaults particular to this controller. */
1348 detect_slots = TRUE;
1349 num_slots = 1;
1350 first_bar = 0;
1351
1352 /* Controller supports ADMA2, so turn it on here. */
1353 sd->sd_dma_mode = DMA_MODE_ADMA2;
1354 }
1355
1356 /* Map in each slot on the board and query it to see if a
1357 * card is inserted. Use the first populated slot found.
1358 */
1359 if (sd->mem_space) {
1360 sdstd_reg_unmap(sd->osh, (uintptr)sd->mem_space, SDIOH_REG_WINSZ);
1361 sd->mem_space = NULL;
1362 }
1363
1364 full_slot = -1;
1365
1366 for (slot = 0; slot < num_slots; slot++) {
1367 bar = OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_BAR0 + (4*(slot + first_bar)), 4);
1368 sd->mem_space = (volatile char *)sdstd_reg_map(sd->osh,
1369 (uintptr)bar, SDIOH_REG_WINSZ);
1370
1371 sd->adapter_slot = -1;
1372
1373 if (detect_slots) {
1374 card_ins = GFIELD(sdstd_rreg(sd, SD_PresentState), PRES_CARD_PRESENT);
1375 } else {
1376 card_ins = TRUE;
1377 }
1378
1379 if (card_ins) {
1380 sd_info(("%s: SDIO slot %d: Full\n", __FUNCTION__, slot));
1381 if (full_slot < 0)
1382 full_slot = slot;
1383 } else {
1384 sd_info(("%s: SDIO slot %d: Empty\n", __FUNCTION__, slot));
1385 }
1386
1387 if (sd->mem_space) {
1388 sdstd_reg_unmap(sd->osh, (uintptr)sd->mem_space, SDIOH_REG_WINSZ);
1389 sd->mem_space = NULL;
1390 }
1391 }
1392
1393 if (full_slot < 0) {
1394 sd_err(("No slots on SDIO controller are populated\n"));
1395 return -1;
1396 }
1397
1398 bar = OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_BAR0 + (4*(full_slot + first_bar)), 4);
1399 sd->mem_space = (volatile char *)sdstd_reg_map(sd->osh, (uintptr)bar, SDIOH_REG_WINSZ);
1400
1401 sd_err(("Using slot %d at BAR%d [0x%08x] mem_space 0x%p\n",
1402 full_slot,
1403 (full_slot + first_bar),
1404 OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_BAR0 + (4*(full_slot + first_bar)), 4),
1405 sd->mem_space));
1406
1407
1408 sd->adapter_slot = full_slot;
1409
1410 sd->version = sdstd_rreg16(sd, SD_HostControllerVersion) & 0xFF;
1411 switch (sd->version) {
1412 case 0:
1413 sd_err(("Host Controller version 1.0, Vendor Revision: 0x%02x\n",
1414 sdstd_rreg16(sd, SD_HostControllerVersion) >> 8));
1415 break;
1416 case 1:
1417 case 2:
1418 sd_err(("Host Controller version 2.0, Vendor Revision: 0x%02x\n",
1419 sdstd_rreg16(sd, SD_HostControllerVersion) >> 8));
1420 break;
1421 default:
1422 sd_err(("%s: Host Controller version 0x%02x not supported.\n",
1423 __FUNCTION__, sd->version));
1424 break;
1425 }
1426
1427 sd->caps = sdstd_rreg(sd, SD_Capabilities); /* Cache this for later use */
1428 sd->curr_caps = sdstd_rreg(sd, SD_MaxCurCap);
1429
1430 sdstd_set_dma_mode(sd, sd->sd_dma_mode);
1431
1432
1433 sdstd_reset(sd, 1, 0);
1434
1435 /* Read SD4/SD1 mode */
1436 if ((reg8 = sdstd_rreg8(sd, SD_HostCntrl))) {
1437 if (reg8 & SD4_MODE) {
1438 sd_err(("%s: Host cntrlr already in 4 bit mode: 0x%x\n",
1439 __FUNCTION__, reg8));
1440 }
1441 }
1442
1443 /* Default power on mode is SD1 */
1444 sd->sd_mode = SDIOH_MODE_SD1;
1445 sd->polled_mode = TRUE;
1446 sd->host_init_done = TRUE;
1447 sd->card_init_done = FALSE;
1448 sd->adapter_slot = full_slot;
1449
1450 return (SUCCESS);
1451}
1452#define CMD5_RETRIES 200
1453static int
1454get_ocr(sdioh_info_t *sd, uint32 *cmd_arg, uint32 *cmd_rsp)
1455{
1456 int retries, status;
1457
1458 /* Get the Card's Operation Condition. Occasionally the board
1459 * takes a while to become ready
1460 */
1461 retries = CMD5_RETRIES;
1462 do {
1463 *cmd_rsp = 0;
1464 if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_5, *cmd_arg))
1465 != SUCCESS) {
1466 sd_err(("%s: CMD5 failed\n", __FUNCTION__));
1467 return status;
1468 }
1469 sdstd_cmd_getrsp(sd, cmd_rsp, 1);
1470 if (!GFIELD(*cmd_rsp, RSP4_CARD_READY))
1471 sd_trace(("%s: Waiting for card to become ready\n", __FUNCTION__));
1472 } while ((!GFIELD(*cmd_rsp, RSP4_CARD_READY)) && --retries);
1473 if (!retries)
1474 return ERROR;
1475
1476 return (SUCCESS);
1477}
1478
1479static int
1480sdstd_client_init(sdioh_info_t *sd)
1481{
1482 uint32 cmd_arg, cmd_rsp;
1483 int status;
1484 uint8 fn_ints;
1485
1486
1487 sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot));
1488
1489 /* Clear any pending ints */
1490 sdstd_wreg16(sd, SD_IntrStatus, 0x1ff);
1491 sdstd_wreg16(sd, SD_ErrorIntrStatus, 0x0fff);
1492
1493 /* Enable both Normal and Error Status. This does not enable
1494 * interrupts, it only enables the status bits to
1495 * become 'live'
1496 */
1497 sdstd_wreg16(sd, SD_IntrStatusEnable, 0x1ff);
1498 sdstd_wreg16(sd, SD_ErrorIntrStatusEnable, 0xffff);
1499
1500 sdstd_wreg16(sd, SD_IntrSignalEnable, 0); /* Disable ints for now. */
1501
1502 /* Start at ~400KHz clock rate for initialization */
1503 if (!sdstd_start_clock(sd, 128)) {
1504 sd_err(("sdstd_start_clock failed\n"));
1505 return ERROR;
1506 }
1507 if (!sdstd_start_power(sd)) {
1508 sd_err(("sdstd_start_power failed\n"));
1509 return ERROR;
1510 }
1511
1512 if (sd->num_funcs == 0) {
1513 sd_err(("%s: No IO funcs!\n", __FUNCTION__));
1514 return ERROR;
1515 }
1516
1517 /* In SPI mode, issue CMD0 first */
1518 if (sd->sd_mode == SDIOH_MODE_SPI) {
1519 cmd_arg = 0;
1520 if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_0, cmd_arg))
1521 != SUCCESS) {
1522 sd_err(("BCMSDIOH: cardinit: CMD0 failed!\n"));
1523 return status;
1524 }
1525 }
1526
1527 if (sd->sd_mode != SDIOH_MODE_SPI) {
1528 uint16 rsp6_status;
1529
1530 /* Card is operational. Ask it to send an RCA */
1531 cmd_arg = 0;
1532 if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_3, cmd_arg))
1533 != SUCCESS) {
1534 sd_err(("%s: CMD3 failed!\n", __FUNCTION__));
1535 return status;
1536 }
1537
1538 /* Verify the card status returned with the cmd response */
1539 sdstd_cmd_getrsp(sd, &cmd_rsp, 1);
1540 rsp6_status = GFIELD(cmd_rsp, RSP6_STATUS);
1541 if (GFIELD(rsp6_status, RSP6STAT_COM_CRC_ERROR) ||
1542 GFIELD(rsp6_status, RSP6STAT_ILLEGAL_CMD) ||
1543 GFIELD(rsp6_status, RSP6STAT_ERROR)) {
1544 sd_err(("%s: CMD3 response error. Response = 0x%x!\n",
1545 __FUNCTION__, rsp6_status));
1546 return ERROR;
1547 }
1548
1549 /* Save the Card's RCA */
1550 sd->card_rca = GFIELD(cmd_rsp, RSP6_IO_RCA);
1551 sd_info(("RCA is 0x%x\n", sd->card_rca));
1552
1553 if (rsp6_status)
1554 sd_err(("raw status is 0x%x\n", rsp6_status));
1555
1556 /* Select the card */
1557 cmd_arg = SFIELD(0, CMD7_RCA, sd->card_rca);
1558 if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_7, cmd_arg))
1559 != SUCCESS) {
1560 sd_err(("%s: CMD7 failed!\n", __FUNCTION__));
1561 return status;
1562 }
1563 sdstd_cmd_getrsp(sd, &cmd_rsp, 1);
1564 if (cmd_rsp != SDIOH_CMD7_EXP_STATUS) {
1565 sd_err(("%s: CMD7 response error. Response = 0x%x!\n",
1566 __FUNCTION__, cmd_rsp));
1567 return ERROR;
1568 }
1569 }
1570
1571 sdstd_card_enablefuncs(sd);
1572
1573 if (!sdstd_bus_width(sd, sd_sdmode)) {
1574 sd_err(("sdstd_bus_width failed\n"));
1575 return ERROR;
1576 }
1577
1578 set_client_block_size(sd, 1, BLOCK_SIZE_4318);
1579 fn_ints = INTR_CTL_FUNC1_EN;
1580
1581 if (sd->num_funcs >= 2) {
1582 set_client_block_size(sd, 2, sd_f2_blocksize /* BLOCK_SIZE_4328 */);
1583 fn_ints |= INTR_CTL_FUNC2_EN;
1584 }
1585
1586 /* Enable/Disable Client interrupts */
1587 /* Turn on here but disable at host controller? */
1588 if (sdstd_card_regwrite(sd, 0, SDIOD_CCCR_INTEN, 1,
1589 (fn_ints | INTR_CTL_MASTER_EN)) != SUCCESS) {
1590 sd_err(("%s: Could not enable ints in CCCR\n", __FUNCTION__));
1591 return ERROR;
1592 }
1593
1594 /* Switch to High-speed clocking mode if both host and device support it */
1595 sdstd_set_highspeed_mode(sd, (bool)sd_hiok);
1596
1597 /* After configuring for High-Speed mode, set the desired clock rate. */
1598 if (!sdstd_start_clock(sd, (uint16)sd_divisor)) {
1599 sd_err(("sdstd_start_clock failed\n"));
1600 return ERROR;
1601 }
1602
1603 sd->card_init_done = TRUE;
1604
1605 return SUCCESS;
1606}
1607
1608static int
1609sdstd_set_highspeed_mode(sdioh_info_t *sd, bool HSMode)
1610{
1611 uint32 regdata;
1612 int status;
1613 uint8 reg8;
1614
1615 reg8 = sdstd_rreg8(sd, SD_HostCntrl);
1616
1617
1618 if (HSMode == TRUE) {
1619 if (sd_hiok && (GFIELD(sd->caps, CAP_HIGHSPEED)) == 0) {
1620 sd_err(("Host Controller does not support hi-speed mode.\n"));
1621 return BCME_ERROR;
1622 }
1623
1624 sd_info(("Attempting to enable High-Speed mode.\n"));
1625
1626 if ((status = sdstd_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
1627 1, &regdata)) != SUCCESS) {
1628 return BCME_SDIO_ERROR;
1629 }
1630 if (regdata & SDIO_SPEED_SHS) {
1631 sd_info(("Device supports High-Speed mode.\n"));
1632
1633 regdata |= SDIO_SPEED_EHS;
1634
1635 sd_info(("Writing %08x to Card at %08x\n",
1636 regdata, SDIOD_CCCR_SPEED_CONTROL));
1637 if ((status = sdstd_card_regwrite(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
1638 1, regdata)) != BCME_OK) {
1639 return BCME_SDIO_ERROR;
1640 }
1641
1642 if ((status = sdstd_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
1643 1, &regdata)) != BCME_OK) {
1644 return BCME_SDIO_ERROR;
1645 }
1646
1647 sd_info(("Read %08x to Card at %08x\n", regdata, SDIOD_CCCR_SPEED_CONTROL));
1648
1649 reg8 = SFIELD(reg8, HOST_HI_SPEED_EN, 1);
1650
1651 sd_err(("High-speed clocking mode enabled.\n"));
1652 }
1653 else {
1654 sd_err(("Device does not support High-Speed Mode.\n"));
1655 reg8 = SFIELD(reg8, HOST_HI_SPEED_EN, 0);
1656 }
1657 } else {
1658 /* Force off device bit */
1659 if ((status = sdstd_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
1660 1, &regdata)) != BCME_OK) {
1661 return status;
1662 }
1663 if (regdata & SDIO_SPEED_EHS) {
1664 regdata &= ~SDIO_SPEED_EHS;
1665 if ((status = sdstd_card_regwrite(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
1666 1, regdata)) != BCME_OK) {
1667 return status;
1668 }
1669 }
1670
1671 sd_err(("High-speed clocking mode disabled.\n"));
1672 reg8 = SFIELD(reg8, HOST_HI_SPEED_EN, 0);
1673 }
1674
1675 sdstd_wreg8(sd, SD_HostCntrl, reg8);
1676
1677 return BCME_OK;
1678}
1679
1680/* Select DMA Mode:
1681 * If dma_mode == DMA_MODE_AUTO, pick the "best" mode.
1682 * Otherwise, pick the selected mode if supported.
1683 * If not supported, use PIO mode.
1684 */
1685static int
1686sdstd_set_dma_mode(sdioh_info_t *sd, int8 dma_mode)
1687{
1688 uint8 reg8, dma_sel_bits = SDIOH_SDMA_MODE;
1689 int8 prev_dma_mode = sd->sd_dma_mode;
1690
1691 switch (prev_dma_mode) {
1692 case DMA_MODE_AUTO:
1693 sd_dma(("%s: Selecting best DMA mode supported by controller.\n",
1694 __FUNCTION__));
1695 if (GFIELD(sd->caps, CAP_ADMA2)) {
1696 sd->sd_dma_mode = DMA_MODE_ADMA2;
1697 dma_sel_bits = SDIOH_ADMA2_MODE;
1698 } else if (GFIELD(sd->caps, CAP_ADMA1)) {
1699 sd->sd_dma_mode = DMA_MODE_ADMA1;
1700 dma_sel_bits = SDIOH_ADMA1_MODE;
1701 } else if (GFIELD(sd->caps, CAP_DMA)) {
1702 sd->sd_dma_mode = DMA_MODE_SDMA;
1703 } else {
1704 sd->sd_dma_mode = DMA_MODE_NONE;
1705 }
1706 break;
1707 case DMA_MODE_NONE:
1708 sd->sd_dma_mode = DMA_MODE_NONE;
1709 break;
1710 case DMA_MODE_SDMA:
1711 if (GFIELD(sd->caps, CAP_DMA)) {
1712 sd->sd_dma_mode = DMA_MODE_SDMA;
1713 } else {
1714 sd_err(("%s: SDMA not supported by controller.\n", __FUNCTION__));
1715 sd->sd_dma_mode = DMA_MODE_NONE;
1716 }
1717 break;
1718 case DMA_MODE_ADMA1:
1719 if (GFIELD(sd->caps, CAP_ADMA1)) {
1720 sd->sd_dma_mode = DMA_MODE_ADMA1;
1721 dma_sel_bits = SDIOH_ADMA1_MODE;
1722 } else {
1723 sd_err(("%s: ADMA1 not supported by controller.\n", __FUNCTION__));
1724 sd->sd_dma_mode = DMA_MODE_NONE;
1725 }
1726 break;
1727 case DMA_MODE_ADMA2:
1728 if (GFIELD(sd->caps, CAP_ADMA2)) {
1729 sd->sd_dma_mode = DMA_MODE_ADMA2;
1730 dma_sel_bits = SDIOH_ADMA2_MODE;
1731 } else {
1732 sd_err(("%s: ADMA2 not supported by controller.\n", __FUNCTION__));
1733 sd->sd_dma_mode = DMA_MODE_NONE;
1734 }
1735 break;
1736 case DMA_MODE_ADMA2_64:
1737 sd_err(("%s: 64b ADMA2 not supported by driver.\n", __FUNCTION__));
1738 sd->sd_dma_mode = DMA_MODE_NONE;
1739 break;
1740 default:
1741 sd_err(("%s: Unsupported DMA Mode %d requested.\n", __FUNCTION__,
1742 prev_dma_mode));
1743 sd->sd_dma_mode = DMA_MODE_NONE;
1744 break;
1745 }
1746
1747 /* clear SysAddr, only used for SDMA */
1748 sdstd_wreg(sd, SD_SysAddr, 0);
1749
1750 sd_err(("%s: %s mode selected.\n", __FUNCTION__, dma_mode_description[sd->sd_dma_mode]));
1751
1752 reg8 = sdstd_rreg8(sd, SD_HostCntrl);
1753 reg8 = SFIELD(reg8, HOST_DMA_SEL, dma_sel_bits);
1754 sdstd_wreg8(sd, SD_HostCntrl, reg8);
1755 sd_dma(("%s: SD_HostCntrl=0x%02x\n", __FUNCTION__, reg8));
1756
1757 return BCME_OK;
1758}
1759
1760
1761bool
1762sdstd_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor)
1763{
1764 uint rc, count;
1765 uint16 divisor;
1766
1767 /* turn off HC clock */
1768 sdstd_wreg16(sd, SD_ClockCntrl,
1769 sdstd_rreg16(sd, SD_ClockCntrl) & ~((uint16)0x4)); /* Disable the HC clock */
1770
1771 /* Set divisor */
1772
1773 divisor = (new_sd_divisor >> 1) << 8;
1774
1775 sd_info(("Clock control is 0x%x\n", sdstd_rreg16(sd, SD_ClockCntrl)));
1776 sdstd_mod_reg16(sd, SD_ClockCntrl, 0xff00, divisor);
1777 sd_info(("%s: Using clock divisor of %d (regval 0x%04x)\n", __FUNCTION__,
1778 new_sd_divisor, divisor));
1779
1780 sd_info(("Primary Clock Freq = %d MHz\n", GFIELD(sd->caps, CAP_TO_CLKFREQ)));
1781
1782 if (GFIELD(sd->caps, CAP_TO_CLKFREQ) == 50) {
1783 sd_info(("%s: Resulting SDIO clock is %d %s\n", __FUNCTION__,
1784 ((50 % new_sd_divisor) ? (50000 / new_sd_divisor) : (50 / new_sd_divisor)),
1785 ((50 % new_sd_divisor) ? "KHz" : "MHz")));
1786 } else if (GFIELD(sd->caps, CAP_TO_CLKFREQ) == 48) {
1787 sd_info(("%s: Resulting SDIO clock is %d %s\n", __FUNCTION__,
1788 ((48 % new_sd_divisor) ? (48000 / new_sd_divisor) : (48 / new_sd_divisor)),
1789 ((48 % new_sd_divisor) ? "KHz" : "MHz")));
1790 } else if (GFIELD(sd->caps, CAP_TO_CLKFREQ) == 33) {
1791 sd_info(("%s: Resulting SDIO clock is %d %s\n", __FUNCTION__,
1792 ((33 % new_sd_divisor) ? (33000 / new_sd_divisor) : (33 / new_sd_divisor)),
1793 ((33 % new_sd_divisor) ? "KHz" : "MHz")));
1794
1795 } else if (sd->controller_type == SDIOH_TYPE_BCM27XX) {
1796 } else {
1797 sd_err(("Need to determine divisor for %d MHz clocks\n",
1798 GFIELD(sd->caps, CAP_TO_CLKFREQ)));
1799 sd_err(("Consult SD Host Controller Spec: Clock Control Register\n"));
1800 return (FALSE);
1801 }
1802
1803 sdstd_or_reg16(sd, SD_ClockCntrl, 0x1); /* Enable the clock */
1804
1805 /* Wait for clock to stabilize */
1806 rc = (sdstd_rreg16(sd, SD_ClockCntrl) & 2);
1807 count = 0;
1808 while (!rc) {
1809 OSL_DELAY(1);
1810 sd_info(("Waiting for clock to become stable 0x%x\n", rc));
1811 rc = (sdstd_rreg16(sd, SD_ClockCntrl) & 2);
1812 count++;
1813 if (count > 10000) {
1814 sd_err(("%s:Clocks failed to stabilize after %u attempts",
1815 __FUNCTION__, count));
1816 return (FALSE);
1817 }
1818 }
1819 /* Turn on clock */
1820 sdstd_or_reg16(sd, SD_ClockCntrl, 0x4);
1821
1822 /* Set timeout control (adjust default value based on divisor).
1823 * Disabling timeout interrupts during setting is advised by host spec.
1824 */
1825 {
1826 uint16 regdata;
1827 uint toval;
1828
1829 toval = sd_toctl;
1830 divisor = new_sd_divisor;
1831
1832 while (toval && !(divisor & 1)) {
1833 toval -= 1;
1834 divisor >>= 1;
1835 }
1836
1837 regdata = sdstd_rreg16(sd, SD_ErrorIntrStatusEnable);
1838 sdstd_wreg16(sd, SD_ErrorIntrStatusEnable, (regdata & ~ERRINT_DATA_TIMEOUT_BIT));
1839 sdstd_wreg8(sd, SD_TimeoutCntrl, (uint8)toval);
1840 sdstd_wreg16(sd, SD_ErrorIntrStatusEnable, regdata);
1841 }
1842
1843 OSL_DELAY(2);
1844
1845 sd_info(("Final Clock control is 0x%x\n", sdstd_rreg16(sd, SD_ClockCntrl)));
1846
1847 return TRUE;
1848}
1849
1850bool
1851sdstd_start_power(sdioh_info_t *sd)
1852{
1853 char *s;
1854 uint32 cmd_arg;
1855 uint32 cmd_rsp;
1856 uint8 pwr = 0;
1857 int volts;
1858
1859 volts = 0;
1860 s = NULL;
1861 if (GFIELD(sd->caps, CAP_VOLT_1_8)) {
1862 volts = 5;
1863 s = "1.8";
1864 }
1865 if (GFIELD(sd->caps, CAP_VOLT_3_0)) {
1866 volts = 6;
1867 s = "3.0";
1868 }
1869 if (GFIELD(sd->caps, CAP_VOLT_3_3)) {
1870 volts = 7;
1871 s = "3.3";
1872 }
1873
1874 pwr = SFIELD(pwr, PWR_VOLTS, volts);
1875 pwr = SFIELD(pwr, PWR_BUS_EN, 1);
1876 sdstd_wreg8(sd, SD_PwrCntrl, pwr); /* Set Voltage level */
1877 sd_info(("Setting Bus Power to %s Volts\n", s));
1878
1879 /* Wait for power to stabilize, Dongle takes longer than NIC. */
1880 OSL_DELAY(250000);
1881
1882 /* Get the Card's Operation Condition. Occasionally the board
1883 * takes a while to become ready
1884 */
1885 cmd_arg = 0;
1886 cmd_rsp = 0;
1887 if (get_ocr(sd, &cmd_arg, &cmd_rsp) != SUCCESS) {
1888 sd_err(("%s: Failed to get OCR bailing\n", __FUNCTION__));
1889 sdstd_reset(sd, 0, 1);
1890 return FALSE;
1891 }
1892
1893 sd_info(("mem_present = %d\n", GFIELD(cmd_rsp, RSP4_MEM_PRESENT)));
1894 sd_info(("num_funcs = %d\n", GFIELD(cmd_rsp, RSP4_NUM_FUNCS)));
1895 sd_info(("card_ready = %d\n", GFIELD(cmd_rsp, RSP4_CARD_READY)));
1896 sd_info(("OCR = 0x%x\n", GFIELD(cmd_rsp, RSP4_IO_OCR)));
1897
1898 /* Verify that the card supports I/O mode */
1899 if (GFIELD(cmd_rsp, RSP4_NUM_FUNCS) == 0) {
1900 sd_err(("%s: Card does not support I/O\n", __FUNCTION__));
1901 return ERROR;
1902 }
1903 sd->num_funcs = GFIELD(cmd_rsp, RSP4_NUM_FUNCS);
1904
1905 /* Examine voltage: Arasan only supports 3.3 volts,
1906 * so look for 3.2-3.3 Volts and also 3.3-3.4 volts.
1907 */
1908
1909 if ((GFIELD(cmd_rsp, RSP4_IO_OCR) & (0x3 << 20)) == 0) {
1910 sd_err(("This client does not support 3.3 volts!\n"));
1911 return ERROR;
1912 }
1913 sd_info(("Leaving bus power at 3.3 Volts\n"));
1914
1915 cmd_arg = SFIELD(0, CMD5_OCR, 0xfff000);
1916 cmd_rsp = 0;
1917 get_ocr(sd, &cmd_arg, &cmd_rsp);
1918 sd_info(("OCR = 0x%x\n", GFIELD(cmd_rsp, RSP4_IO_OCR)));
1919 return TRUE;
1920}
1921
1922bool
1923sdstd_bus_width(sdioh_info_t *sd, int new_mode)
1924{
1925 uint32 regdata;
1926 int status;
1927 uint8 reg8;
1928
1929 sd_trace(("%s\n", __FUNCTION__));
1930 if (sd->sd_mode == new_mode) {
1931 sd_info(("%s: Already at width %d\n", __FUNCTION__, new_mode));
1932 /* Could exit, but continue just in case... */
1933 }
1934
1935 /* Set client side via reg 0x7 in CCCR */
1936 if ((status = sdstd_card_regread (sd, 0, SDIOD_CCCR_BICTRL, 1, &regdata)) != SUCCESS)
1937 return (bool)status;
1938 regdata &= ~BUS_SD_DATA_WIDTH_MASK;
1939 if (new_mode == SDIOH_MODE_SD4) {
1940 sd_info(("Changing to SD4 Mode\n"));
1941 regdata |= SD4_MODE;
1942 } else if (new_mode == SDIOH_MODE_SD1) {
1943 sd_info(("Changing to SD1 Mode\n"));
1944 } else {
1945 sd_err(("SPI Mode not supported by Standard Host Controller\n"));
1946 }
1947
1948 if ((status = sdstd_card_regwrite (sd, 0, SDIOD_CCCR_BICTRL, 1, regdata)) != SUCCESS)
1949 return (bool)status;
1950
1951 /* Set host side via Host reg */
1952 reg8 = sdstd_rreg8(sd, SD_HostCntrl) & ~SD4_MODE;
1953 if (new_mode == SDIOH_MODE_SD4)
1954 reg8 |= SD4_MODE;
1955 sdstd_wreg8(sd, SD_HostCntrl, reg8);
1956
1957 sd->sd_mode = new_mode;
1958
1959 return TRUE;
1960}
1961
1962static int
1963sdstd_driver_init(sdioh_info_t *sd)
1964{
1965 sd_trace(("%s\n", __FUNCTION__));
1966 if ((sdstd_host_init(sd)) != SUCCESS) {
1967 return ERROR;
1968 }
1969
1970 if (sdstd_client_init(sd) != SUCCESS) {
1971 return ERROR;
1972 }
1973
1974 return SUCCESS;
1975}
1976
1977static int
1978sdstd_get_cisaddr(sdioh_info_t *sd, uint32 regaddr)
1979{
1980 /* read 24 bits and return valid 17 bit addr */
1981 int i;
1982 uint32 scratch, regdata;
1983 uint8 *ptr = (uint8 *)&scratch;
1984 for (i = 0; i < 3; i++) {
1985 if ((sdstd_card_regread (sd, 0, regaddr, 1, &regdata)) != SUCCESS)
1986 sd_err(("%s: Can't read!\n", __FUNCTION__));
1987
1988 *ptr++ = (uint8) regdata;
1989 regaddr++;
1990 }
1991 /* Only the lower 17-bits are valid */
1992 scratch = ltoh32(scratch);
1993 scratch &= 0x0001FFFF;
1994 return (scratch);
1995}
1996
1997static int
1998sdstd_card_enablefuncs(sdioh_info_t *sd)
1999{
2000 int status;
2001 uint32 regdata;
2002 uint32 fbraddr;
2003 uint8 func;
2004
2005 sd_trace(("%s\n", __FUNCTION__));
2006
2007 /* Get the Card's common CIS address */
2008 sd->com_cis_ptr = sdstd_get_cisaddr(sd, SDIOD_CCCR_CISPTR_0);
2009 sd->func_cis_ptr[0] = sd->com_cis_ptr;
2010 sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
2011
2012 /* Get the Card's function CIS (for each function) */
2013 for (fbraddr = SDIOD_FBR_STARTADDR, func = 1;
2014 func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
2015 sd->func_cis_ptr[func] = sdstd_get_cisaddr(sd, SDIOD_FBR_CISPTR_0 + fbraddr);
2016 sd_info(("%s: Function %d CIS Ptr = 0x%x\n",
2017 __FUNCTION__, func, sd->func_cis_ptr[func]));
2018 }
2019
2020 /* Enable function 1 on the card */
2021 regdata = SDIO_FUNC_ENABLE_1;
2022 if ((status = sdstd_card_regwrite(sd, 0, SDIOD_CCCR_IOEN, 1, regdata)) != SUCCESS)
2023 return status;
2024
2025 return SUCCESS;
2026}
2027
2028/* Read client card reg */
2029static int
2030sdstd_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
2031{
2032 int status;
2033 uint32 cmd_arg;
2034 uint32 rsp5;
2035
2036
2037 cmd_arg = 0;
2038
2039 if ((func == 0) || (regsize == 1)) {
2040 cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
2041 cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
2042 cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_READ);
2043 cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
2044 cmd_arg = SFIELD(cmd_arg, CMD52_DATA, 0);
2045
2046 if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_52, cmd_arg))
2047 != SUCCESS)
2048 return status;
2049
2050 sdstd_cmd_getrsp(sd, &rsp5, 1);
2051 if (sdstd_rreg16(sd, SD_ErrorIntrStatus) != 0) {
2052 sd_err(("%s: 1: ErrorintrStatus 0x%x\n",
2053 __FUNCTION__, sdstd_rreg16(sd, SD_ErrorIntrStatus)));
2054 }
2055
2056 if (GFIELD(rsp5, RSP5_FLAGS) != 0x10)
2057 sd_err(("%s: rsp5 flags is 0x%x\t %d\n",
2058 __FUNCTION__, GFIELD(rsp5, RSP5_FLAGS), func));
2059
2060 if (GFIELD(rsp5, RSP5_STUFF))
2061 sd_err(("%s: rsp5 stuff is 0x%x: should be 0\n",
2062 __FUNCTION__, GFIELD(rsp5, RSP5_STUFF)));
2063 *data = GFIELD(rsp5, RSP5_DATA);
2064 } else {
2065 cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize);
2066 cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1);
2067 cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0);
2068 cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func);
2069 cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, regaddr);
2070 cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_READ);
2071
2072 sd->data_xfer_count = regsize;
2073
2074 /* sdstd_cmd_issue() returns with the command complete bit
2075 * in the ISR already cleared
2076 */
2077 if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_53, cmd_arg))
2078 != SUCCESS)
2079 return status;
2080
2081 sdstd_cmd_getrsp(sd, &rsp5, 1);
2082
2083 if (GFIELD(rsp5, RSP5_FLAGS) != 0x10)
2084 sd_err(("%s: rsp5 flags is 0x%x\t %d\n",
2085 __FUNCTION__, GFIELD(rsp5, RSP5_FLAGS), func));
2086
2087 if (GFIELD(rsp5, RSP5_STUFF))
2088 sd_err(("%s: rsp5 stuff is 0x%x: should be 0\n",
2089 __FUNCTION__, GFIELD(rsp5, RSP5_STUFF)));
2090
2091 if (sd->polled_mode) {
2092 volatile uint16 int_reg;
2093 int retries = RETRIES_LARGE;
2094
2095 /* Wait for Read Buffer to become ready */
2096 do {
2097 int_reg = sdstd_rreg16(sd, SD_IntrStatus);
2098 } while (--retries && (GFIELD(int_reg, INTSTAT_BUF_READ_READY) == 0));
2099
2100 if (!retries) {
2101 sd_err(("%s: Timeout on Buf_Read_Ready: "
2102 "intStat: 0x%x errint: 0x%x PresentState 0x%x\n",
2103 __FUNCTION__, int_reg,
2104 sdstd_rreg16(sd, SD_ErrorIntrStatus),
2105 sdstd_rreg(sd, SD_PresentState)));
2106 sdstd_check_errs(sd, SDIOH_CMD_53, cmd_arg);
2107 return (ERROR);
2108 }
2109
2110 /* Have Buffer Ready, so clear it and read the data */
2111 sdstd_wreg16(sd, SD_IntrStatus, SFIELD(0, INTSTAT_BUF_READ_READY, 1));
2112 if (regsize == 2)
2113 *data = sdstd_rreg16(sd, SD_BufferDataPort0);
2114 else
2115 *data = sdstd_rreg(sd, SD_BufferDataPort0);
2116
2117 /* Check Status.
2118 * After the data is read, the Transfer Complete bit should be on
2119 */
2120 retries = RETRIES_LARGE;
2121 do {
2122 int_reg = sdstd_rreg16(sd, SD_IntrStatus);
2123 } while (--retries && (GFIELD(int_reg, INTSTAT_XFER_COMPLETE) == 0));
2124
2125 /* Check for any errors from the data phase */
2126 if (sdstd_check_errs(sd, SDIOH_CMD_53, cmd_arg))
2127 return ERROR;
2128
2129 if (!retries) {
2130 sd_err(("%s: Timeout on xfer complete: "
2131 "intr 0x%04x err 0x%04x state 0x%08x\n",
2132 __FUNCTION__, int_reg,
2133 sdstd_rreg16(sd, SD_ErrorIntrStatus),
2134 sdstd_rreg(sd, SD_PresentState)));
2135 return (ERROR);
2136 }
2137
2138 sdstd_wreg16(sd, SD_IntrStatus, SFIELD(0, INTSTAT_XFER_COMPLETE, 1));
2139 }
2140 }
2141 if (sd->polled_mode) {
2142 if (regsize == 2)
2143 *data &= 0xffff;
2144 }
2145 return SUCCESS;
2146}
2147
2148bool
2149check_client_intr(sdioh_info_t *sd)
2150{
2151 uint16 raw_int, cur_int, old_int;
2152
2153 raw_int = sdstd_rreg16(sd, SD_IntrStatus);
2154 cur_int = raw_int & sd->intmask;
2155
2156 if (!cur_int) {
2157 /* Not an error -- might share interrupts... */
2158 return FALSE;
2159 }
2160
2161 if (GFIELD(cur_int, INTSTAT_CARD_INT)) {
2162 old_int = sdstd_rreg16(sd, SD_IntrStatusEnable);
2163 sdstd_wreg16(sd, SD_IntrStatusEnable, SFIELD(old_int, INTSTAT_CARD_INT, 0));
2164
2165 if (sd->client_intr_enabled && sd->use_client_ints) {
2166 sd->intrcount++;
2167 ASSERT(sd->intr_handler);
2168 ASSERT(sd->intr_handler_arg);
2169 (sd->intr_handler)(sd->intr_handler_arg);
2170 } else {
2171 sd_err(("%s: Not ready for intr: enabled %d, handler %p\n",
2172 __FUNCTION__, sd->client_intr_enabled, sd->intr_handler));
2173 }
2174 sdstd_wreg16(sd, SD_IntrStatusEnable, old_int);
2175 } else {
2176 /* Local interrupt: disable, set flag, and save intrstatus */
2177 sdstd_wreg16(sd, SD_IntrSignalEnable, 0);
2178 sdstd_wreg16(sd, SD_ErrorIntrSignalEnable, 0);
2179 sd->local_intrcount++;
2180 sd->got_hcint = TRUE;
2181 sd->last_intrstatus = cur_int;
2182 }
2183
2184 return TRUE;
2185}
2186
2187void
2188sdstd_spinbits(sdioh_info_t *sd, uint16 norm, uint16 err)
2189{
2190 uint16 int_reg, err_reg;
2191 int retries = RETRIES_LARGE;
2192
2193 do {
2194 int_reg = sdstd_rreg16(sd, SD_IntrStatus);
2195 err_reg = sdstd_rreg16(sd, SD_ErrorIntrStatus);
2196 } while (--retries && !(int_reg & norm) && !(err_reg & err));
2197
2198 norm |= sd->intmask;
2199 if (err_reg & err)
2200 norm = SFIELD(norm, INTSTAT_ERROR_INT, 1);
2201 sd->last_intrstatus = int_reg & norm;
2202}
2203
2204/* write a client register */
2205static int
2206sdstd_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data)
2207{
2208 int status;
2209 uint32 cmd_arg, rsp5, flags;
2210
2211 cmd_arg = 0;
2212
2213 if ((func == 0) || (regsize == 1)) {
2214 cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
2215 cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
2216 cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_WRITE);
2217 cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
2218 cmd_arg = SFIELD(cmd_arg, CMD52_DATA, data & 0xff);
2219 if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_52, cmd_arg))
2220 != SUCCESS)
2221 return status;
2222
2223 sdstd_cmd_getrsp(sd, &rsp5, 1);
2224 flags = GFIELD(rsp5, RSP5_FLAGS);
2225 if (flags && (flags != 0x10))
2226 sd_err(("%s: rsp5.rsp5.flags = 0x%x, expecting 0x10\n",
2227 __FUNCTION__, flags));
2228 }
2229 else {
2230 cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize);
2231 cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1);
2232 cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0);
2233 cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func);
2234 cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, regaddr);
2235 cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_WRITE);
2236
2237 sd->data_xfer_count = regsize;
2238
2239 /* sdstd_cmd_issue() returns with the command complete bit
2240 * in the ISR already cleared
2241 */
2242 if ((status = sdstd_cmd_issue(sd, USE_DMA(sd), SDIOH_CMD_53, cmd_arg))
2243 != SUCCESS)
2244 return status;
2245
2246 sdstd_cmd_getrsp(sd, &rsp5, 1);
2247
2248 if (GFIELD(rsp5, RSP5_FLAGS) != 0x10)
2249 sd_err(("%s: rsp5 flags = 0x%x, expecting 0x10\n",
2250 __FUNCTION__, GFIELD(rsp5, RSP5_FLAGS)));
2251 if (GFIELD(rsp5, RSP5_STUFF))
2252 sd_err(("%s: rsp5 stuff is 0x%x: expecting 0\n",
2253 __FUNCTION__, GFIELD(rsp5, RSP5_STUFF)));
2254
2255 if (sd->polled_mode) {
2256 uint16 int_reg;
2257 int retries = RETRIES_LARGE;
2258
2259 /* Wait for Write Buffer to become ready */
2260 do {
2261 int_reg = sdstd_rreg16(sd, SD_IntrStatus);
2262 } while (--retries && (GFIELD(int_reg, INTSTAT_BUF_WRITE_READY) == 0));
2263
2264 if (!retries) {
2265 sd_err(("%s: Timeout on Buf_Write_Ready: intStat: 0x%x "
2266 "errint: 0x%x PresentState 0x%x\n",
2267 __FUNCTION__, int_reg,
2268 sdstd_rreg16(sd, SD_ErrorIntrStatus),
2269 sdstd_rreg(sd, SD_PresentState)));
2270 sdstd_check_errs(sd, SDIOH_CMD_53, cmd_arg);
2271 return (ERROR);
2272 }
2273 /* Clear Write Buf Ready bit */
2274 int_reg = 0;
2275 int_reg = SFIELD(int_reg, INTSTAT_BUF_WRITE_READY, 1);
2276 sdstd_wreg16(sd, SD_IntrStatus, int_reg);
2277
2278 /* At this point we have Buffer Ready, so write the data */
2279 if (regsize == 2)
2280 sdstd_wreg16(sd, SD_BufferDataPort0, (uint16) data);
2281 else
2282 sdstd_wreg(sd, SD_BufferDataPort0, data);
2283
2284 /* Wait for Transfer Complete */
2285 retries = RETRIES_LARGE;
2286 do {
2287 int_reg = sdstd_rreg16(sd, SD_IntrStatus);
2288 } while (--retries && (GFIELD(int_reg, INTSTAT_XFER_COMPLETE) == 0));
2289
2290 /* Check for any errors from the data phase */
2291 if (sdstd_check_errs(sd, SDIOH_CMD_53, cmd_arg))
2292 return ERROR;
2293
2294 if (retries == 0) {
2295 sd_err(("%s: Timeout for xfer complete; State = 0x%x, "
2296 "intr state=0x%x, Errintstatus 0x%x rcnt %d, tcnt %d\n",
2297 __FUNCTION__, sdstd_rreg(sd, SD_PresentState),
2298 int_reg, sdstd_rreg16(sd, SD_ErrorIntrStatus),
2299 sd->r_cnt, sd->t_cnt));
2300 }
2301 /* Clear the status bits */
2302 sdstd_wreg16(sd, SD_IntrStatus, SFIELD(int_reg, INTSTAT_CARD_INT, 0));
2303 }
2304 }
2305 return SUCCESS;
2306}
2307
2308void
2309sdstd_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count /* num 32 bit words */)
2310{
2311 int rsp_count;
2312 int respaddr = SD_Response0;
2313
2314 if (count > 4)
2315 count = 4;
2316
2317 for (rsp_count = 0; rsp_count < count; rsp_count++) {
2318 *rsp_buffer++ = sdstd_rreg(sd, respaddr);
2319 respaddr += 4;
2320 }
2321}
2322
2323static int
2324sdstd_cmd_issue(sdioh_info_t *sdioh_info, bool use_dma, uint32 cmd, uint32 arg)
2325{
2326 uint16 cmd_reg;
2327 int retries;
2328 uint32 cmd_arg;
2329 uint16 xfer_reg = 0;
2330
2331
2332 if ((sdioh_info->sd_mode == SDIOH_MODE_SPI) &&
2333 ((cmd == SDIOH_CMD_3) || (cmd == SDIOH_CMD_7) || (cmd == SDIOH_CMD_15))) {
2334 sd_err(("%s: Cmd %d is not for SPI\n", __FUNCTION__, cmd));
2335 return ERROR;
2336 }
2337
2338 retries = RETRIES_SMALL;
2339 while ((GFIELD(sdstd_rreg(sdioh_info, SD_PresentState), PRES_CMD_INHIBIT)) && --retries) {
2340 if (retries == RETRIES_SMALL)
2341 sd_err(("%s: Waiting for Command Inhibit cmd = %d 0x%x\n",
2342 __FUNCTION__, cmd, sdstd_rreg(sdioh_info, SD_PresentState)));
2343 }
2344 if (!retries) {
2345 sd_err(("%s: Command Inhibit timeout\n", __FUNCTION__));
2346 if (trap_errs)
2347 ASSERT(0);
2348 return ERROR;
2349 }
2350
2351
2352 cmd_reg = 0;
2353 switch (cmd) {
2354 case SDIOH_CMD_0: /* Set Card to Idle State - No Response */
2355 sd_data(("%s: CMD%d\n", __FUNCTION__, cmd));
2356 cmd_reg = SFIELD(cmd_reg, CMD_RESP_TYPE, RESP_TYPE_NONE);
2357 cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 0);
2358 cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 0);
2359 cmd_reg = SFIELD(cmd_reg, CMD_DATA_EN, 0);
2360 cmd_reg = SFIELD(cmd_reg, CMD_TYPE, CMD_TYPE_NORMAL);
2361 cmd_reg = SFIELD(cmd_reg, CMD_INDEX, cmd);
2362 break;
2363
2364 case SDIOH_CMD_3: /* Ask card to send RCA - Response R6 */
2365 sd_data(("%s: CMD%d\n", __FUNCTION__, cmd));
2366 cmd_reg = SFIELD(cmd_reg, CMD_RESP_TYPE, RESP_TYPE_48);
2367 cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 0);
2368 cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 0);
2369 cmd_reg = SFIELD(cmd_reg, CMD_DATA_EN, 0);
2370 cmd_reg = SFIELD(cmd_reg, CMD_TYPE, CMD_TYPE_NORMAL);
2371 cmd_reg = SFIELD(cmd_reg, CMD_INDEX, cmd);
2372 break;
2373
2374 case SDIOH_CMD_5: /* Send Operation condition - Response R4 */
2375 sd_data(("%s: CMD%d\n", __FUNCTION__, cmd));
2376 cmd_reg = SFIELD(cmd_reg, CMD_RESP_TYPE, RESP_TYPE_48);
2377 cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 0);
2378 cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 0);
2379 cmd_reg = SFIELD(cmd_reg, CMD_DATA_EN, 0);
2380 cmd_reg = SFIELD(cmd_reg, CMD_TYPE, CMD_TYPE_NORMAL);
2381 cmd_reg = SFIELD(cmd_reg, CMD_INDEX, cmd);
2382 break;
2383
2384 case SDIOH_CMD_7: /* Select card - Response R1 */
2385 sd_data(("%s: CMD%d\n", __FUNCTION__, cmd));
2386 cmd_reg = SFIELD(cmd_reg, CMD_RESP_TYPE, RESP_TYPE_48);
2387 cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 1);
2388 cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 1);
2389 cmd_reg = SFIELD(cmd_reg, CMD_DATA_EN, 0);
2390 cmd_reg = SFIELD(cmd_reg, CMD_TYPE, CMD_TYPE_NORMAL);
2391 cmd_reg = SFIELD(cmd_reg, CMD_INDEX, cmd);
2392 break;
2393
2394 case SDIOH_CMD_15: /* Set card to inactive state - Response None */
2395 sd_data(("%s: CMD%d\n", __FUNCTION__, cmd));
2396 cmd_reg = SFIELD(cmd_reg, CMD_RESP_TYPE, RESP_TYPE_NONE);
2397 cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 0);
2398 cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 0);
2399 cmd_reg = SFIELD(cmd_reg, CMD_DATA_EN, 0);
2400 cmd_reg = SFIELD(cmd_reg, CMD_TYPE, CMD_TYPE_NORMAL);
2401 cmd_reg = SFIELD(cmd_reg, CMD_INDEX, cmd);
2402 break;
2403
2404 case SDIOH_CMD_52: /* IO R/W Direct (single byte) - Response R5 */
2405
2406 sd_data(("%s: CMD52 func(%d) addr(0x%x) %s data(0x%x)\n",
2407 __FUNCTION__,
2408 GFIELD(arg, CMD52_FUNCTION),
2409 GFIELD(arg, CMD52_REG_ADDR),
2410 GFIELD(arg, CMD52_RW_FLAG) ? "W" : "R",
2411 GFIELD(arg, CMD52_DATA)));
2412
2413 cmd_reg = SFIELD(cmd_reg, CMD_RESP_TYPE, RESP_TYPE_48);
2414 cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 1);
2415 cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 1);
2416 cmd_reg = SFIELD(cmd_reg, CMD_DATA_EN, 0);
2417 cmd_reg = SFIELD(cmd_reg, CMD_TYPE, CMD_TYPE_NORMAL);
2418 cmd_reg = SFIELD(cmd_reg, CMD_INDEX, cmd);
2419 break;
2420
2421 case SDIOH_CMD_53: /* IO R/W Extended (multiple bytes/blocks) */
2422
2423 sd_data(("%s: CMD53 func(%d) addr(0x%x) %s mode(%s) cnt(%d), %s\n",
2424 __FUNCTION__,
2425 GFIELD(arg, CMD53_FUNCTION),
2426 GFIELD(arg, CMD53_REG_ADDR),
2427 GFIELD(arg, CMD53_RW_FLAG) ? "W" : "R",
2428 GFIELD(arg, CMD53_BLK_MODE) ? "Block" : "Byte",
2429 GFIELD(arg, CMD53_BYTE_BLK_CNT),
2430 GFIELD(arg, CMD53_OP_CODE) ? "Incrementing addr" : "Single addr"));
2431
2432 cmd_arg = arg;
2433 xfer_reg = 0;
2434
2435 cmd_reg = SFIELD(cmd_reg, CMD_RESP_TYPE, RESP_TYPE_48);
2436 cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 1);
2437 cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 1);
2438 cmd_reg = SFIELD(cmd_reg, CMD_DATA_EN, 1);
2439 cmd_reg = SFIELD(cmd_reg, CMD_TYPE, CMD_TYPE_NORMAL);
2440 cmd_reg = SFIELD(cmd_reg, CMD_INDEX, cmd);
2441
2442 use_dma = USE_DMA(sdioh_info) && GFIELD(cmd_arg, CMD53_BLK_MODE);
2443
2444 if (GFIELD(cmd_arg, CMD53_BLK_MODE)) {
2445 uint16 blocksize;
2446 uint16 blockcount;
2447 int func;
2448
2449 ASSERT(sdioh_info->sd_blockmode);
2450
2451 func = GFIELD(cmd_arg, CMD53_FUNCTION);
2452 blocksize = MIN((int)sdioh_info->data_xfer_count,
2453 sdioh_info->client_block_size[func]);
2454 blockcount = GFIELD(cmd_arg, CMD53_BYTE_BLK_CNT);
2455
2456 /* data_xfer_cnt is already setup so that for multiblock mode,
2457 * it is the entire buffer length. For non-block or single block,
2458 * it is < 64 bytes
2459 */
2460 if (use_dma) {
2461 switch (sdioh_info->sd_dma_mode) {
2462 case DMA_MODE_SDMA:
2463 sd_dma(("%s: SDMA: SysAddr reg was 0x%x now 0x%x\n",
2464 __FUNCTION__, sdstd_rreg(sdioh_info, SD_SysAddr),
2465 (uint32)sdioh_info->dma_phys));
2466 sdstd_wreg(sdioh_info, SD_SysAddr, sdioh_info->dma_phys);
2467 break;
2468 case DMA_MODE_ADMA1:
2469 case DMA_MODE_ADMA2:
2470 sd_dma(("%s: ADMA: Using ADMA\n", __FUNCTION__));
2471 sd_create_adma_descriptor(sdioh_info, 0,
2472 sdioh_info->dma_phys, blockcount*blocksize,
2473 ADMA2_ATTRIBUTE_VALID | ADMA2_ATTRIBUTE_END |
2474 ADMA2_ATTRIBUTE_INT | ADMA2_ATTRIBUTE_ACT_TRAN);
2475 /* Dump descriptor if DMA debugging is enabled. */
2476 if (sd_msglevel & SDH_DMA_VAL) {
2477 sd_dump_adma_dscr(sdioh_info);
2478 }
2479
2480 sdstd_wreg(sdioh_info, SD_ADMA_SysAddr,
2481 sdioh_info->adma2_dscr_phys);
2482 break;
2483 default:
2484 sd_err(("%s: unsupported DMA mode %d.\n",
2485 __FUNCTION__, sdioh_info->sd_dma_mode));
2486 break;
2487 }
2488 }
2489
2490 sd_trace(("%s: Setting block count %d, block size %d bytes\n",
2491 __FUNCTION__, blockcount, blocksize));
2492 sdstd_wreg16(sdioh_info, SD_BlockSize, blocksize);
2493 sdstd_wreg16(sdioh_info, SD_BlockCount, blockcount);
2494
2495 xfer_reg = SFIELD(xfer_reg, XFER_DMA_ENABLE, use_dma);
2496
2497 if (sdioh_info->client_block_size[func] != blocksize)
2498 set_client_block_size(sdioh_info, 1, blocksize);
2499
2500 if (blockcount > 1) {
2501 xfer_reg = SFIELD(xfer_reg, XFER_MULTI_BLOCK, 1);
2502 xfer_reg = SFIELD(xfer_reg, XFER_BLK_COUNT_EN, 1);
2503 xfer_reg = SFIELD(xfer_reg, XFER_CMD_12_EN, 0);
2504 } else {
2505 xfer_reg = SFIELD(xfer_reg, XFER_MULTI_BLOCK, 0);
2506 xfer_reg = SFIELD(xfer_reg, XFER_BLK_COUNT_EN, 0);
2507 xfer_reg = SFIELD(xfer_reg, XFER_CMD_12_EN, 0);
2508 }
2509
2510 if (GFIELD(cmd_arg, CMD53_RW_FLAG) == SDIOH_XFER_TYPE_READ)
2511 xfer_reg = SFIELD(xfer_reg, XFER_DATA_DIRECTION, 1);
2512 else
2513 xfer_reg = SFIELD(xfer_reg, XFER_DATA_DIRECTION, 0);
2514
2515 retries = RETRIES_SMALL;
2516 while (GFIELD(sdstd_rreg(sdioh_info, SD_PresentState),
2517 PRES_DAT_INHIBIT) && --retries)
2518 sd_err(("%s: Waiting for Data Inhibit cmd = %d\n",
2519 __FUNCTION__, cmd));
2520 if (!retries) {
2521 sd_err(("%s: Data Inhibit timeout\n", __FUNCTION__));
2522 if (trap_errs)
2523 ASSERT(0);
2524 return ERROR;
2525 }
2526 sdstd_wreg16(sdioh_info, SD_TransferMode, xfer_reg);
2527
2528 } else { /* Non block mode */
2529 uint16 bytes = GFIELD(cmd_arg, CMD53_BYTE_BLK_CNT);
2530 /* The byte/block count field only has 9 bits,
2531 * so, to do a 512-byte bytemode transfer, this
2532 * field will contain 0, but we need to tell the
2533 * controller we're transferring 512 bytes.
2534 */
2535 if (bytes == 0) bytes = 512;
2536
2537 if (use_dma)
2538 sdstd_wreg(sdioh_info, SD_SysAddr, sdioh_info->dma_phys);
2539
2540 /* PCI: Transfer Mode register 0x0c */
2541 xfer_reg = SFIELD(xfer_reg, XFER_DMA_ENABLE, bytes <= 4 ? 0 : use_dma);
2542 xfer_reg = SFIELD(xfer_reg, XFER_CMD_12_EN, 0);
2543 if (GFIELD(cmd_arg, CMD53_RW_FLAG) == SDIOH_XFER_TYPE_READ)
2544 xfer_reg = SFIELD(xfer_reg, XFER_DATA_DIRECTION, 1);
2545 else
2546 xfer_reg = SFIELD(xfer_reg, XFER_DATA_DIRECTION, 0);
2547 /* See table 2-8 Host Controller spec ver 1.00 */
2548 xfer_reg = SFIELD(xfer_reg, XFER_BLK_COUNT_EN, 0); /* Dont care */
2549 xfer_reg = SFIELD(xfer_reg, XFER_MULTI_BLOCK, 0);
2550
2551 sdstd_wreg16(sdioh_info, SD_BlockSize, bytes);
2552
2553 sdstd_wreg16(sdioh_info, SD_BlockCount, 1);
2554
2555 retries = RETRIES_SMALL;
2556 while (GFIELD(sdstd_rreg(sdioh_info, SD_PresentState),
2557 PRES_DAT_INHIBIT) && --retries)
2558 sd_err(("%s: Waiting for Data Inhibit cmd = %d\n",
2559 __FUNCTION__, cmd));
2560 if (!retries) {
2561 sd_err(("%s: Data Inhibit timeout\n", __FUNCTION__));
2562 if (trap_errs)
2563 ASSERT(0);
2564 return ERROR;
2565 }
2566 sdstd_wreg16(sdioh_info, SD_TransferMode, xfer_reg);
2567 }
2568 break;
2569
2570 default:
2571 sd_err(("%s: Unknown command\n", __FUNCTION__));
2572 return ERROR;
2573 }
2574
2575 if (sdioh_info->sd_mode == SDIOH_MODE_SPI) {
2576 cmd_reg = SFIELD(cmd_reg, CMD_CRC_EN, 0);
2577 cmd_reg = SFIELD(cmd_reg, CMD_INDEX_EN, 0);
2578 }
2579
2580 /* Setup and issue the SDIO command */
2581 sdstd_wreg(sdioh_info, SD_Arg0, arg);
2582 sdstd_wreg16(sdioh_info, SD_Command, cmd_reg);
2583
2584 /* If we are in polled mode, wait for the command to complete.
2585 * In interrupt mode, return immediately. The calling function will
2586 * know that the command has completed when the CMDATDONE interrupt
2587 * is asserted
2588 */
2589 if (sdioh_info->polled_mode) {
2590 uint16 int_reg = 0;
2591 int retries = RETRIES_LARGE;
2592
2593 do {
2594 int_reg = sdstd_rreg16(sdioh_info, SD_IntrStatus);
2595 } while (--retries &&
2596 (GFIELD(int_reg, INTSTAT_ERROR_INT) == 0) &&
2597 (GFIELD(int_reg, INTSTAT_CMD_COMPLETE) == 0));
2598
2599 if (!retries) {
2600 sd_err(("%s: CMD_COMPLETE timeout: intrStatus: 0x%x "
2601 "error stat 0x%x state 0x%x\n",
2602 __FUNCTION__, int_reg,
2603 sdstd_rreg16(sdioh_info, SD_ErrorIntrStatus),
2604 sdstd_rreg(sdioh_info, SD_PresentState)));
2605
2606 /* Attempt to reset CMD line when we get a CMD timeout */
2607 sdstd_wreg8(sdioh_info, SD_SoftwareReset, SFIELD(0, SW_RESET_CMD, 1));
2608 retries = RETRIES_LARGE;
2609 do {
2610 sd_trace(("%s: waiting for CMD line reset\n", __FUNCTION__));
2611 } while ((GFIELD(sdstd_rreg8(sdioh_info, SD_SoftwareReset),
2612 SW_RESET_CMD)) && retries--);
2613
2614 if (!retries) {
2615 sd_err(("%s: Timeout waiting for CMD line reset\n", __FUNCTION__));
2616 }
2617
2618 if (trap_errs)
2619 ASSERT(0);
2620 return (ERROR);
2621 }
2622
2623 /* Clear Command Complete interrupt */
2624 int_reg = SFIELD(0, INTSTAT_CMD_COMPLETE, 1);
2625 sdstd_wreg16(sdioh_info, SD_IntrStatus, int_reg);
2626
2627 /* Check for Errors */
2628 if (sdstd_check_errs(sdioh_info, cmd, arg)) {
2629 if (trap_errs)
2630 ASSERT(0);
2631 return ERROR;
2632 }
2633 }
2634 return SUCCESS;
2635}
2636
2637
2638static int
2639sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int nbytes, uint32 *data)
2640{
2641 int status;
2642 uint32 cmd_arg;
2643 uint32 rsp5;
2644 uint16 int_reg, int_bit;
2645 uint flags;
2646 int num_blocks, blocksize;
2647 bool local_blockmode, local_dma;
2648 bool read = rw == SDIOH_READ ? 1 : 0;
2649 bool yield = FALSE;
2650
2651 ASSERT(nbytes);
2652
2653 cmd_arg = 0;
2654
2655 sd_data(("%s: %s 53 addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n",
2656 __FUNCTION__, read ? "Rd" : "Wr", addr, nbytes, sd->r_cnt, sd->t_cnt));
2657
2658 if (read) sd->r_cnt++; else sd->t_cnt++;
2659
2660 local_blockmode = sd->sd_blockmode;
2661 local_dma = USE_DMA(sd);
2662
2663 /* Don't bother with block mode on small xfers */
2664 if (nbytes < sd->client_block_size[func]) {
2665 sd_data(("setting local blockmode to false: nbytes (%d) != block_size (%d)\n",
2666 nbytes, sd->client_block_size[func]));
2667 local_blockmode = FALSE;
2668 local_dma = FALSE;
2669 }
2670
2671 if (local_blockmode) {
2672 blocksize = MIN(sd->client_block_size[func], nbytes);
2673 num_blocks = nbytes/blocksize;
2674 cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, num_blocks);
2675 cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 1);
2676 } else {
2677 num_blocks = 1;
2678 blocksize = nbytes;
2679 cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, nbytes);
2680 cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0);
2681 }
2682
2683 if (local_dma && !read) {
2684 bcopy(data, sd->dma_buf, nbytes);
2685 sd_sync_dma(sd, read, nbytes);
2686 }
2687
2688 if (fifo)
2689 cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 0);
2690 else
2691 cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1);
2692
2693 cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func);
2694 cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, addr);
2695 if (read)
2696 cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_READ);
2697 else
2698 cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_WRITE);
2699
2700 sd->data_xfer_count = nbytes;
2701
2702 /* sdstd_cmd_issue() returns with the command complete bit
2703 * in the ISR already cleared
2704 */
2705 if ((status = sdstd_cmd_issue(sd, local_dma, SDIOH_CMD_53, cmd_arg)) != SUCCESS) {
2706 sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, (read ? "read" : "write")));
2707 return status;
2708 }
2709
2710 sdstd_cmd_getrsp(sd, &rsp5, 1);
2711
2712 if ((flags = GFIELD(rsp5, RSP5_FLAGS)) != 0x10) {
2713 sd_err(("%s: Rsp5: nbytes %d, dma %d blockmode %d, read %d "
2714 "numblocks %d, blocksize %d\n",
2715 __FUNCTION__, nbytes, local_dma, local_dma, read, num_blocks, blocksize));
2716
2717 if (flags & 1)
2718 sd_err(("%s: rsp5: Command not accepted: arg out of range 0x%x, "
2719 "bytes %d dma %d\n",
2720 __FUNCTION__, flags, GFIELD(cmd_arg, CMD53_BYTE_BLK_CNT),
2721 GFIELD(cmd_arg, CMD53_BLK_MODE)));
2722 if (flags & 0x8)
2723 sd_err(("%s: Rsp5: General Error\n", __FUNCTION__));
2724
2725 sd_err(("%s: rsp5 flags = 0x%x, expecting 0x10 returning error\n",
2726 __FUNCTION__, flags));
2727 if (trap_errs)
2728 ASSERT(0);
2729 return ERROR;
2730 }
2731
2732 if (GFIELD(rsp5, RSP5_STUFF))
2733 sd_err(("%s: rsp5 stuff is 0x%x: expecting 0\n",
2734 __FUNCTION__, GFIELD(rsp5, RSP5_STUFF)));
2735
2736#ifdef BCMSDYIELD
2737 yield = sd_yieldcpu && ((uint)nbytes >= sd_minyield);
2738#endif
2739
2740 if (!local_dma) {
2741 int bytes, i;
2742 uint32 tmp;
2743 for (i = 0; i < num_blocks; i++) {
2744 int words;
2745
2746 /* Decide which status bit we're waiting for */
2747 if (read)
2748 int_bit = SFIELD(0, INTSTAT_BUF_READ_READY, 1);
2749 else
2750 int_bit = SFIELD(0, INTSTAT_BUF_WRITE_READY, 1);
2751
2752 /* If not on, wait for it (or for xfer error) */
2753 int_reg = sdstd_rreg16(sd, SD_IntrStatus);
2754 if (!(int_reg & int_bit))
2755 int_reg = sdstd_waitbits(sd, int_bit, ERRINT_TRANSFER_ERRS, yield);
2756
2757 /* Confirm we got the bit w/o error */
2758 if (!(int_reg & int_bit) || GFIELD(int_reg, INTSTAT_ERROR_INT)) {
2759 sd_err(("%s: Error or timeout for Buf_%s_Ready: intStat: 0x%x "
2760 "errint: 0x%x PresentState 0x%x\n",
2761 __FUNCTION__, read ? "Read" : "Write", int_reg,
2762 sdstd_rreg16(sd, SD_ErrorIntrStatus),
2763 sdstd_rreg(sd, SD_PresentState)));
2764 sdstd_dumpregs(sd);
2765 sdstd_check_errs(sd, SDIOH_CMD_53, cmd_arg);
2766 return (ERROR);
2767 }
2768
2769 /* Clear Buf Ready bit */
2770 sdstd_wreg16(sd, SD_IntrStatus, int_bit);
2771
2772 /* At this point we have Buffer Ready, write the data 4 bytes at a time */
2773 for (words = blocksize/4; words; words--) {
2774 if (read)
2775 *data = sdstd_rreg(sd, SD_BufferDataPort0);
2776 else
2777 sdstd_wreg(sd, SD_BufferDataPort0, *data);
2778 data++;
2779 }
2780
2781 bytes = blocksize % 4;
2782
2783 /* If no leftover bytes, go to next block */
2784 if (!bytes)
2785 continue;
2786
2787 switch (bytes) {
2788 case 1:
2789 /* R/W 8 bits */
2790 if (read)
2791 *(data++) = (uint32)(sdstd_rreg8(sd, SD_BufferDataPort0));
2792 else
2793 sdstd_wreg8(sd, SD_BufferDataPort0,
2794 (uint8)(*(data++) & 0xff));
2795 break;
2796 case 2:
2797 /* R/W 16 bits */
2798 if (read)
2799 *(data++) = (uint32)sdstd_rreg16(sd, SD_BufferDataPort0);
2800 else
2801 sdstd_wreg16(sd, SD_BufferDataPort0, (uint16)(*(data++)));
2802 break;
2803 case 3:
2804 /* R/W 24 bits:
2805 * SD_BufferDataPort0[0-15] | SD_BufferDataPort1[16-23]
2806 */
2807 if (read) {
2808 tmp = (uint32)sdstd_rreg16(sd, SD_BufferDataPort0);
2809 tmp |= ((uint32)(sdstd_rreg8(sd,
2810 SD_BufferDataPort1)) << 16);
2811 *(data++) = tmp;
2812 } else {
2813 tmp = *(data++);
2814 sdstd_wreg16(sd, SD_BufferDataPort0, (uint16)tmp & 0xffff);
2815 sdstd_wreg8(sd, SD_BufferDataPort1,
2816 (uint8)((tmp >> 16) & 0xff));
2817 }
2818 break;
2819 default:
2820 sd_err(("%s: Unexpected bytes leftover %d\n",
2821 __FUNCTION__, bytes));
2822 ASSERT(0);
2823 break;
2824 }
2825 }
2826 } /* End PIO processing */
2827
2828 /* Wait for Transfer Complete or Transfer Error */
2829 int_bit = SFIELD(0, INTSTAT_XFER_COMPLETE, 1);
2830
2831 /* If not on, wait for it (or for xfer error) */
2832 int_reg = sdstd_rreg16(sd, SD_IntrStatus);
2833 if (!(int_reg & int_bit))
2834 int_reg = sdstd_waitbits(sd, int_bit, ERRINT_TRANSFER_ERRS, yield);
2835
2836 /* Check for any errors from the data phase */
2837 if (sdstd_check_errs(sd, SDIOH_CMD_53, cmd_arg))
2838 return ERROR;
2839
2840 /* May have gotten a software timeout if not blocking? */
2841 int_reg = sdstd_rreg16(sd, SD_IntrStatus);
2842 if (!(int_reg & int_bit)) {
2843 sd_err(("%s: Error or Timeout for xfer complete; %s, dma %d, State 0x%08x, "
2844 "intr 0x%04x, Err 0x%04x, len = %d, rcnt %d, tcnt %d\n",
2845 __FUNCTION__, read ? "R" : "W", local_dma,
2846 sdstd_rreg(sd, SD_PresentState), int_reg,
2847 sdstd_rreg16(sd, SD_ErrorIntrStatus), nbytes,
2848 sd->r_cnt, sd->t_cnt));
2849 sdstd_dumpregs(sd);
2850 return ERROR;
2851 }
2852
2853 /* Clear the status bits */
2854 int_reg = int_bit;
2855 if (local_dma) {
2856 /* DMA Complete */
2857 /* Reads in particular don't have DMA_COMPLETE set */
2858 int_reg = SFIELD(int_reg, INTSTAT_DMA_INT, 1);
2859 }
2860 sdstd_wreg16(sd, SD_IntrStatus, int_reg);
2861
2862 /* Fetch data */
2863 if (local_dma && read) {
2864 sd_sync_dma(sd, read, nbytes);
2865 bcopy(sd->dma_buf, data, nbytes);
2866 }
2867 return SUCCESS;
2868}
2869
2870static int
2871set_client_block_size(sdioh_info_t *sd, int func, int block_size)
2872{
2873 int base;
2874 int err = 0;
2875
2876
2877 sd_err(("%s: Setting block size %d, func %d\n", __FUNCTION__, block_size, func));
2878 sd->client_block_size[func] = block_size;
2879
2880 /* Set the block size in the SDIO Card register */
2881 base = func * SDIOD_FBR_SIZE;
2882 err = sdstd_card_regwrite(sd, 0, base+SDIOD_CCCR_BLKSIZE_0, 1, block_size & 0xff);
2883 if (!err) {
2884 err = sdstd_card_regwrite(sd, 0, base+SDIOD_CCCR_BLKSIZE_1, 1,
2885 (block_size >> 8) & 0xff);
2886 }
2887
2888 /* Do not set the block size in the SDIO Host register, that
2889 * is func dependent and will get done on an individual
2890 * transaction basis
2891 */
2892
2893 return (err ? BCME_SDIO_ERROR : 0);
2894}
2895
2896/* Reset and re-initialize the device */
2897int
2898sdioh_sdio_reset(sdioh_info_t *si)
2899{
2900 uint8 hreg;
2901
2902 /* Reset the attached device (use slower clock for safety) */
2903 sdstd_start_clock(si, 128);
2904 sdstd_reset(si, 0, 1);
2905
2906 /* Reset portions of the host state accordingly */
2907 hreg = sdstd_rreg8(si, SD_HostCntrl);
2908 hreg = SFIELD(hreg, HOST_HI_SPEED_EN, 0);
2909 hreg = SFIELD(hreg, HOST_DATA_WIDTH, 0);
2910 si->sd_mode = SDIOH_MODE_SD1;
2911
2912 /* Reinitialize the card */
2913 si->card_init_done = FALSE;
2914 return sdstd_client_init(si);
2915}
2916
2917
2918static void
2919sd_map_dma(sdioh_info_t * sd)
2920{
2921
2922 void *va;
2923
2924 if ((va = DMA_ALLOC_CONSISTENT(sd->osh, SD_PAGE,
2925 &sd->dma_start_phys, 0x12, 12)) == NULL) {
2926 sd->sd_dma_mode = DMA_MODE_NONE;
2927 sd->dma_start_buf = 0;
2928 sd->dma_buf = (void *)0;
2929 sd->dma_phys = 0;
2930 sd->alloced_dma_size = SD_PAGE;
2931 sd_err(("%s: DMA_ALLOC failed. Disabling DMA support.\n", __FUNCTION__));
2932 } else {
2933 sd->dma_start_buf = va;
2934 sd->dma_buf = (void *)ROUNDUP((uintptr)va, SD_PAGE);
2935 sd->dma_phys = ROUNDUP((sd->dma_start_phys), SD_PAGE);
2936 sd->alloced_dma_size = SD_PAGE;
2937 sd_err(("%s: Mapped DMA Buffer %dbytes @virt/phys: %p/0x%lx\n",
2938 __FUNCTION__, sd->alloced_dma_size, sd->dma_buf, sd->dma_phys));
2939 sd_fill_dma_data_buf(sd, 0xA5);
2940 }
2941
2942 if ((va = DMA_ALLOC_CONSISTENT(sd->osh, SD_PAGE,
2943 &sd->adma2_dscr_start_phys, 0x12, 12)) == NULL) {
2944 sd->sd_dma_mode = DMA_MODE_NONE;
2945 sd->adma2_dscr_start_buf = 0;
2946 sd->adma2_dscr_buf = (void *)0;
2947 sd->adma2_dscr_phys = 0;
2948 sd->alloced_adma2_dscr_size = 0;
2949 sd_err(("%s: DMA_ALLOC failed for descriptor buffer. "
2950 "Disabling DMA support.\n", __FUNCTION__));
2951 } else {
2952 sd->adma2_dscr_start_buf = va;
2953 sd->adma2_dscr_buf = (void *)ROUNDUP((uintptr)va, SD_PAGE);
2954 sd->adma2_dscr_phys = ROUNDUP((sd->adma2_dscr_start_phys), SD_PAGE);
2955 sd->alloced_adma2_dscr_size = SD_PAGE;
2956 }
2957
2958 sd_err(("%s: Mapped ADMA2 Descriptor Buffer %dbytes @virt/phys: %p/0x%lx\n",
2959 __FUNCTION__, sd->alloced_adma2_dscr_size, sd->adma2_dscr_buf,
2960 sd->adma2_dscr_phys));
2961 sd_clear_adma_dscr_buf(sd);
2962}
2963
2964static void
2965sd_unmap_dma(sdioh_info_t * sd)
2966{
2967 if (sd->dma_start_buf) {
2968 DMA_FREE_CONSISTENT(sd->osh, sd->dma_start_buf, sd->alloced_dma_size,
2969 sd->dma_start_phys, 0x12);
2970 }
2971
2972 if (sd->adma2_dscr_start_buf) {
2973 DMA_FREE_CONSISTENT(sd->osh, sd->adma2_dscr_start_buf, sd->alloced_adma2_dscr_size,
2974 sd->adma2_dscr_start_phys, 0x12);
2975 }
2976}
2977
2978static void sd_clear_adma_dscr_buf(sdioh_info_t *sd)
2979{
2980 bzero((char *)sd->adma2_dscr_buf, SD_PAGE);
2981 sd_dump_adma_dscr(sd);
2982}
2983
2984static void sd_fill_dma_data_buf(sdioh_info_t *sd, uint8 data)
2985{
2986 memset((char *)sd->dma_buf, data, SD_PAGE);
2987}
2988
2989
2990static void sd_create_adma_descriptor(sdioh_info_t *sd, uint32 index,
2991 uint32 addr_phys, uint16 length, uint16 flags)
2992{
2993 adma2_dscr_32b_t *adma2_dscr_table;
2994 adma1_dscr_t *adma1_dscr_table;
2995
2996 adma2_dscr_table = sd->adma2_dscr_buf;
2997 adma1_dscr_table = sd->adma2_dscr_buf;
2998
2999 switch (sd->sd_dma_mode) {
3000 case DMA_MODE_ADMA2:
3001 sd_dma(("%s: creating ADMA2 descriptor for index %d\n",
3002 __FUNCTION__, index));
3003
3004 adma2_dscr_table[index].phys_addr = addr_phys;
3005 adma2_dscr_table[index].len_attr = length << 16;
3006 adma2_dscr_table[index].len_attr |= flags;
3007 break;
3008 case DMA_MODE_ADMA1:
3009 /* ADMA1 requires two descriptors, one for len
3010 * and the other for data transfer
3011 */
3012 index <<= 1;
3013
3014 sd_dma(("%s: creating ADMA1 descriptor for index %d\n",
3015 __FUNCTION__, index));
3016
3017 adma1_dscr_table[index].phys_addr_attr = length << 12;
3018 adma1_dscr_table[index].phys_addr_attr |= (ADMA1_ATTRIBUTE_ACT_SET |
3019 ADMA2_ATTRIBUTE_VALID);
3020 adma1_dscr_table[index+1].phys_addr_attr = addr_phys & 0xFFFFF000;
3021 adma1_dscr_table[index+1].phys_addr_attr |= (flags & 0x3f);
3022 break;
3023 default:
3024 sd_err(("%s: cannot create ADMA descriptor for DMA mode %d\n",
3025 __FUNCTION__, sd->sd_dma_mode));
3026 break;
3027 }
3028}
3029
3030
3031static void sd_dump_adma_dscr(sdioh_info_t *sd)
3032{
3033 adma2_dscr_32b_t *adma2_dscr_table;
3034 adma1_dscr_t *adma1_dscr_table;
3035 uint32 i = 0;
3036 uint16 flags;
3037 char flags_str[32];
3038
3039 ASSERT(sd->adma2_dscr_buf != NULL);
3040
3041 adma2_dscr_table = sd->adma2_dscr_buf;
3042 adma1_dscr_table = sd->adma2_dscr_buf;
3043
3044 switch (sd->sd_dma_mode) {
3045 case DMA_MODE_ADMA2:
3046 sd_err(("ADMA2 Descriptor Table (%dbytes) @virt/phys: %p/0x%lx\n",
3047 SD_PAGE, sd->adma2_dscr_buf, sd->adma2_dscr_phys));
3048 sd_err((" #[Descr VA ] Buffer PA | Len | Flags (5:4 2 1 0)"
3049 " |\n"));
3050 while (adma2_dscr_table->len_attr & ADMA2_ATTRIBUTE_VALID) {
3051 flags = adma2_dscr_table->len_attr & 0xFFFF;
3052 sprintf(flags_str, "%s%s%s%s",
3053 ((flags & ADMA2_ATTRIBUTE_ACT_LINK) ==
3054 ADMA2_ATTRIBUTE_ACT_LINK) ? "LINK " :
3055 ((flags & ADMA2_ATTRIBUTE_ACT_LINK) ==
3056 ADMA2_ATTRIBUTE_ACT_TRAN) ? "TRAN " :
3057 ((flags & ADMA2_ATTRIBUTE_ACT_LINK) ==
3058 ADMA2_ATTRIBUTE_ACT_NOP) ? "NOP " : "RSV ",
3059 (flags & ADMA2_ATTRIBUTE_INT ? "INT " : " "),
3060 (flags & ADMA2_ATTRIBUTE_END ? "END " : " "),
3061 (flags & ADMA2_ATTRIBUTE_VALID ? "VALID" : ""));
3062 sd_err(("%2d[0x%p]: 0x%08x | 0x%04x | 0x%04x (%s) |\n",
3063 i, adma2_dscr_table, adma2_dscr_table->phys_addr,
3064 adma2_dscr_table->len_attr >> 16, flags, flags_str));
3065 i++;
3066
3067 /* Follow LINK descriptors or skip to next. */
3068 if ((flags & ADMA2_ATTRIBUTE_ACT_LINK) ==
3069 ADMA2_ATTRIBUTE_ACT_LINK) {
3070 adma2_dscr_table = phys_to_virt(
3071 adma2_dscr_table->phys_addr);
3072 } else {
3073 adma2_dscr_table++;
3074 }
3075
3076 }
3077 break;
3078 case DMA_MODE_ADMA1:
3079 sd_err(("ADMA1 Descriptor Table (%dbytes) @virt/phys: %p/0x%lx\n",
3080 SD_PAGE, sd->adma2_dscr_buf, sd->adma2_dscr_phys));
3081 sd_err((" #[Descr VA ] Buffer PA | Flags (5:4 2 1 0) |\n"));
3082
3083 for (i = 0; adma1_dscr_table->phys_addr_attr & ADMA2_ATTRIBUTE_VALID; i++) {
3084 flags = adma1_dscr_table->phys_addr_attr & 0x3F;
3085 sprintf(flags_str, "%s%s%s%s",
3086 ((flags & ADMA2_ATTRIBUTE_ACT_LINK) ==
3087 ADMA2_ATTRIBUTE_ACT_LINK) ? "LINK " :
3088 ((flags & ADMA2_ATTRIBUTE_ACT_LINK) ==
3089 ADMA2_ATTRIBUTE_ACT_TRAN) ? "TRAN " :
3090 ((flags & ADMA2_ATTRIBUTE_ACT_LINK) ==
3091 ADMA2_ATTRIBUTE_ACT_NOP) ? "NOP " : "SET ",
3092 (flags & ADMA2_ATTRIBUTE_INT ? "INT " : " "),
3093 (flags & ADMA2_ATTRIBUTE_END ? "END " : " "),
3094 (flags & ADMA2_ATTRIBUTE_VALID ? "VALID" : ""));
3095 sd_err(("%2d[0x%p]: 0x%08x | 0x%04x | (%s) |\n",
3096 i, adma1_dscr_table,
3097 adma1_dscr_table->phys_addr_attr & 0xFFFFF000,
3098 flags, flags_str));
3099
3100 /* Follow LINK descriptors or skip to next. */
3101 if ((flags & ADMA2_ATTRIBUTE_ACT_LINK) ==
3102 ADMA2_ATTRIBUTE_ACT_LINK) {
3103 adma1_dscr_table = phys_to_virt(
3104 adma1_dscr_table->phys_addr_attr & 0xFFFFF000);
3105 } else {
3106 adma1_dscr_table++;
3107 }
3108 }
3109 break;
3110 default:
3111 sd_err(("Unknown DMA Descriptor Table Format.\n"));
3112 break;
3113 }
3114}
3115
3116static void sdstd_dumpregs(sdioh_info_t *sd)
3117{
3118 sd_err(("IntrStatus: 0x%04x ErrorIntrStatus 0x%04x\n",
3119 sdstd_rreg16(sd, SD_IntrStatus),
3120 sdstd_rreg16(sd, SD_ErrorIntrStatus)));
3121 sd_err(("IntrStatusEnable: 0x%04x ErrorIntrStatusEnable 0x%04x\n",
3122 sdstd_rreg16(sd, SD_IntrStatusEnable),
3123 sdstd_rreg16(sd, SD_ErrorIntrStatusEnable)));
3124 sd_err(("IntrSignalEnable: 0x%04x ErrorIntrSignalEnable 0x%04x\n",
3125 sdstd_rreg16(sd, SD_IntrSignalEnable),
3126 sdstd_rreg16(sd, SD_ErrorIntrSignalEnable)));
3127}
diff --git a/drivers/net/wireless/bcm4329/bcmsdstd_linux.c b/drivers/net/wireless/bcm4329/bcmsdstd_linux.c
new file mode 100644
index 00000000000..a8b98e2054a
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmsdstd_linux.c
@@ -0,0 +1,251 @@
1/*
2 * 'Standard' SDIO HOST CONTROLLER driver - linux portion
3 *
4 * Copyright (C) 1999-2010, 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_linux.c,v 1.11.18.2.16.1 2010/08/17 17:03:13 Exp $
25 */
26
27#include <typedefs.h>
28#include <pcicfg.h>
29#include <bcmutils.h>
30#include <sdio.h> /* SDIO Specs */
31#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
32#include <sdiovar.h> /* to get msglevel bit values */
33
34#include <linux/sched.h> /* request_irq() */
35
36#include <bcmsdstd.h>
37
38struct sdos_info {
39 sdioh_info_t *sd;
40 spinlock_t lock;
41 wait_queue_head_t intr_wait_queue;
42};
43
44#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
45#define BLOCKABLE() (!in_atomic())
46#else
47#define BLOCKABLE() (!in_interrupt())
48#endif
49
50/* Interrupt handler */
51static irqreturn_t
52sdstd_isr(int irq, void *dev_id
53#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
54, struct pt_regs *ptregs
55#endif
56)
57{
58 sdioh_info_t *sd;
59 struct sdos_info *sdos;
60 bool ours;
61
62 sd = (sdioh_info_t *)dev_id;
63
64 if (!sd->card_init_done) {
65 sd_err(("%s: Hey Bogus intr...not even initted: irq %d\n", __FUNCTION__, irq));
66 return IRQ_RETVAL(FALSE);
67 } else {
68 ours = check_client_intr(sd);
69
70 /* For local interrupts, wake the waiting process */
71 if (ours && sd->got_hcint) {
72 sd_trace(("INTR->WAKE\n"));
73 sdos = (struct sdos_info *)sd->sdos_info;
74 wake_up_interruptible(&sdos->intr_wait_queue);
75 }
76 return IRQ_RETVAL(ours);
77 }
78}
79
80/* Register with Linux for interrupts */
81int
82sdstd_register_irq(sdioh_info_t *sd, uint irq)
83{
84 sd_trace(("Entering %s: irq == %d\n", __FUNCTION__, irq));
85 if (request_irq(irq, sdstd_isr, IRQF_SHARED, "bcmsdstd", sd) < 0) {
86 sd_err(("%s: request_irq() failed\n", __FUNCTION__));
87 return ERROR;
88 }
89 return SUCCESS;
90}
91
92/* Free Linux irq */
93void
94sdstd_free_irq(uint irq, sdioh_info_t *sd)
95{
96 free_irq(irq, sd);
97}
98
99/* Map Host controller registers */
100
101uint32 *
102sdstd_reg_map(osl_t *osh, int32 addr, int size)
103{
104 return (uint32 *)REG_MAP(addr, size);
105}
106
107void
108sdstd_reg_unmap(osl_t *osh, int32 addr, int size)
109{
110 REG_UNMAP((void*)(uintptr)addr);
111}
112
113int
114sdstd_osinit(sdioh_info_t *sd)
115{
116 struct sdos_info *sdos;
117
118 sdos = (struct sdos_info*)MALLOC(sd->osh, sizeof(struct sdos_info));
119 sd->sdos_info = (void*)sdos;
120 if (sdos == NULL)
121 return BCME_NOMEM;
122
123 sdos->sd = sd;
124 spin_lock_init(&sdos->lock);
125 init_waitqueue_head(&sdos->intr_wait_queue);
126 return BCME_OK;
127}
128
129void
130sdstd_osfree(sdioh_info_t *sd)
131{
132 struct sdos_info *sdos;
133 ASSERT(sd && sd->sdos_info);
134
135 sdos = (struct sdos_info *)sd->sdos_info;
136 MFREE(sd->osh, sdos, sizeof(struct sdos_info));
137}
138
139/* Interrupt enable/disable */
140SDIOH_API_RC
141sdioh_interrupt_set(sdioh_info_t *sd, bool enable)
142{
143 ulong flags;
144 struct sdos_info *sdos;
145
146 sd_trace(("%s: %s\n", __FUNCTION__, enable ? "Enabling" : "Disabling"));
147
148 sdos = (struct sdos_info *)sd->sdos_info;
149 ASSERT(sdos);
150
151 if (!(sd->host_init_done && sd->card_init_done)) {
152 sd_err(("%s: Card & Host are not initted - bailing\n", __FUNCTION__));
153 return SDIOH_API_RC_FAIL;
154 }
155
156 if (enable && !(sd->intr_handler && sd->intr_handler_arg)) {
157 sd_err(("%s: no handler registered, will not enable\n", __FUNCTION__));
158 return SDIOH_API_RC_FAIL;
159 }
160
161 /* Ensure atomicity for enable/disable calls */
162 spin_lock_irqsave(&sdos->lock, flags);
163
164 sd->client_intr_enabled = enable;
165 if (enable && !sd->lockcount)
166 sdstd_devintr_on(sd);
167 else
168 sdstd_devintr_off(sd);
169
170 spin_unlock_irqrestore(&sdos->lock, flags);
171
172 return SDIOH_API_RC_SUCCESS;
173}
174
175/* Protect against reentrancy (disable device interrupts while executing) */
176void
177sdstd_lock(sdioh_info_t *sd)
178{
179 ulong flags;
180 struct sdos_info *sdos;
181
182 sdos = (struct sdos_info *)sd->sdos_info;
183 ASSERT(sdos);
184
185 sd_trace(("%s: %d\n", __FUNCTION__, sd->lockcount));
186
187 spin_lock_irqsave(&sdos->lock, flags);
188 if (sd->lockcount) {
189 sd_err(("%s: Already locked! called from %p\n",
190 __FUNCTION__,
191 __builtin_return_address(0)));
192 ASSERT(sd->lockcount == 0);
193 }
194 sdstd_devintr_off(sd);
195 sd->lockcount++;
196 spin_unlock_irqrestore(&sdos->lock, flags);
197}
198
199/* Enable client interrupt */
200void
201sdstd_unlock(sdioh_info_t *sd)
202{
203 ulong flags;
204 struct sdos_info *sdos;
205
206 sd_trace(("%s: %d, %d\n", __FUNCTION__, sd->lockcount, sd->client_intr_enabled));
207 ASSERT(sd->lockcount > 0);
208
209 sdos = (struct sdos_info *)sd->sdos_info;
210 ASSERT(sdos);
211
212 spin_lock_irqsave(&sdos->lock, flags);
213 if (--sd->lockcount == 0 && sd->client_intr_enabled) {
214 sdstd_devintr_on(sd);
215 }
216 spin_unlock_irqrestore(&sdos->lock, flags);
217}
218
219uint16
220sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield)
221{
222 struct sdos_info *sdos;
223
224 sdos = (struct sdos_info *)sd->sdos_info;
225
226#ifndef BCMSDYIELD
227 ASSERT(!yield);
228#endif
229 sd_trace(("%s: int 0x%02x err 0x%02x yield %d canblock %d\n",
230 __FUNCTION__, norm, err, yield, BLOCKABLE()));
231
232 /* Clear the "interrupt happened" flag and last intrstatus */
233 sd->got_hcint = FALSE;
234 sd->last_intrstatus = 0;
235
236#ifdef BCMSDYIELD
237 if (yield && BLOCKABLE()) {
238 /* Enable interrupts, wait for the indication, then disable */
239 sdstd_intrs_on(sd, norm, err);
240 wait_event_interruptible(sdos->intr_wait_queue, (sd->got_hcint));
241 sdstd_intrs_off(sd, norm, err);
242 } else
243#endif /* BCMSDYIELD */
244 {
245 sdstd_spinbits(sd, norm, err);
246 }
247
248 sd_trace(("%s: last_intrstatus 0x%04x\n", __FUNCTION__, sd->last_intrstatus));
249
250 return sd->last_intrstatus;
251}
diff --git a/drivers/net/wireless/bcm4329/bcmutils.c b/drivers/net/wireless/bcm4329/bcmutils.c
new file mode 100644
index 00000000000..43c04ee92f3
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmutils.c
@@ -0,0 +1,1838 @@
1/*
2 * Driver O/S-independent utility routines
3 *
4 * Copyright (C) 1999-2010, 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.210.4.5.2.4.6.19 2010/04/26 06:05:25 Exp $
24 */
25
26#include <typedefs.h>
27#include <bcmdefs.h>
28#include <stdarg.h>
29#include <bcmutils.h>
30#ifdef BCMDRIVER
31#include <osl.h>
32#include <siutils.h>
33#else
34#include <stdio.h>
35#include <string.h>
36/* This case for external supplicant use */
37#if defined(BCMEXTSUP)
38#include <bcm_osl.h>
39#endif
40
41#endif /* BCMDRIVER */
42#include <bcmendian.h>
43#include <bcmdevs.h>
44#include <proto/ethernet.h>
45#include <proto/vlan.h>
46#include <proto/bcmip.h>
47#include <proto/802.1d.h>
48#include <proto/802.11.h>
49
50
51#ifdef BCMDRIVER
52
53
54/* copy a pkt buffer chain into a buffer */
55uint
56pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf)
57{
58 uint n, ret = 0;
59
60 if (len < 0)
61 len = 4096; /* "infinite" */
62
63 /* skip 'offset' bytes */
64 for (; p && offset; p = PKTNEXT(osh, p)) {
65 if (offset < (uint)PKTLEN(osh, p))
66 break;
67 offset -= PKTLEN(osh, p);
68 }
69
70 if (!p)
71 return 0;
72
73 /* copy the data */
74 for (; p && len; p = PKTNEXT(osh, p)) {
75 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
76 bcopy(PKTDATA(osh, p) + offset, buf, n);
77 buf += n;
78 len -= n;
79 ret += n;
80 offset = 0;
81 }
82
83 return ret;
84}
85
86/* copy a buffer into a pkt buffer chain */
87uint
88pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf)
89{
90 uint n, ret = 0;
91
92 /* skip 'offset' bytes */
93 for (; p && offset; p = PKTNEXT(osh, p)) {
94 if (offset < (uint)PKTLEN(osh, p))
95 break;
96 offset -= PKTLEN(osh, p);
97 }
98
99 if (!p)
100 return 0;
101
102 /* copy the data */
103 for (; p && len; p = PKTNEXT(osh, p)) {
104 n = MIN((uint)PKTLEN(osh, p) - offset, (uint)len);
105 bcopy(buf, PKTDATA(osh, p) + offset, n);
106 buf += n;
107 len -= n;
108 ret += n;
109 offset = 0;
110 }
111
112 return ret;
113}
114
115
116
117/* return total length of buffer chain */
118uint
119pkttotlen(osl_t *osh, void *p)
120{
121 uint total;
122
123 total = 0;
124 for (; p; p = PKTNEXT(osh, p))
125 total += PKTLEN(osh, p);
126 return (total);
127}
128
129/* return the last buffer of chained pkt */
130void *
131pktlast(osl_t *osh, void *p)
132{
133 for (; PKTNEXT(osh, p); p = PKTNEXT(osh, p))
134 ;
135
136 return (p);
137}
138
139/* count segments of a chained packet */
140uint
141pktsegcnt(osl_t *osh, void *p)
142{
143 uint cnt;
144
145 for (cnt = 0; p; p = PKTNEXT(osh, p))
146 cnt++;
147
148 return cnt;
149}
150
151
152/*
153 * osl multiple-precedence packet queue
154 * hi_prec is always >= the number of the highest non-empty precedence
155 */
156void *
157pktq_penq(struct pktq *pq, int prec, void *p)
158{
159 struct pktq_prec *q;
160
161 ASSERT(prec >= 0 && prec < pq->num_prec);
162 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
163
164 ASSERT(!pktq_full(pq));
165 ASSERT(!pktq_pfull(pq, prec));
166
167 q = &pq->q[prec];
168
169 if (q->head)
170 PKTSETLINK(q->tail, p);
171 else
172 q->head = p;
173
174 q->tail = p;
175 q->len++;
176
177 pq->len++;
178
179 if (pq->hi_prec < prec)
180 pq->hi_prec = (uint8)prec;
181
182 return p;
183}
184
185void *
186pktq_penq_head(struct pktq *pq, int prec, void *p)
187{
188 struct pktq_prec *q;
189
190 ASSERT(prec >= 0 && prec < pq->num_prec);
191 ASSERT(PKTLINK(p) == NULL); /* queueing chains not allowed */
192
193 ASSERT(!pktq_full(pq));
194 ASSERT(!pktq_pfull(pq, prec));
195
196 q = &pq->q[prec];
197
198 if (q->head == NULL)
199 q->tail = p;
200
201 PKTSETLINK(p, q->head);
202 q->head = p;
203 q->len++;
204
205 pq->len++;
206
207 if (pq->hi_prec < prec)
208 pq->hi_prec = (uint8)prec;
209
210 return p;
211}
212
213void *
214pktq_pdeq(struct pktq *pq, int prec)
215{
216 struct pktq_prec *q;
217 void *p;
218
219 ASSERT(prec >= 0 && prec < pq->num_prec);
220
221 q = &pq->q[prec];
222
223 if ((p = q->head) == NULL)
224 return NULL;
225
226 if ((q->head = PKTLINK(p)) == NULL)
227 q->tail = NULL;
228
229 q->len--;
230
231 pq->len--;
232
233 PKTSETLINK(p, NULL);
234
235 return p;
236}
237
238void *
239pktq_pdeq_tail(struct pktq *pq, int prec)
240{
241 struct pktq_prec *q;
242 void *p, *prev;
243
244 ASSERT(prec >= 0 && prec < pq->num_prec);
245
246 q = &pq->q[prec];
247
248 if ((p = q->head) == NULL)
249 return NULL;
250
251 for (prev = NULL; p != q->tail; p = PKTLINK(p))
252 prev = p;
253
254 if (prev)
255 PKTSETLINK(prev, NULL);
256 else
257 q->head = NULL;
258
259 q->tail = prev;
260 q->len--;
261
262 pq->len--;
263
264 return p;
265}
266
267void
268pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir)
269{
270 struct pktq_prec *q;
271 void *p;
272
273 q = &pq->q[prec];
274 p = q->head;
275 while (p) {
276 q->head = PKTLINK(p);
277 PKTSETLINK(p, NULL);
278 PKTFREE(osh, p, dir);
279 q->len--;
280 pq->len--;
281 p = q->head;
282 }
283 ASSERT(q->len == 0);
284 q->tail = NULL;
285}
286
287bool
288pktq_pdel(struct pktq *pq, void *pktbuf, int prec)
289{
290 struct pktq_prec *q;
291 void *p;
292
293 ASSERT(prec >= 0 && prec < pq->num_prec);
294
295 if (!pktbuf)
296 return FALSE;
297
298 q = &pq->q[prec];
299
300 if (q->head == pktbuf) {
301 if ((q->head = PKTLINK(pktbuf)) == NULL)
302 q->tail = NULL;
303 } else {
304 for (p = q->head; p && PKTLINK(p) != pktbuf; p = PKTLINK(p))
305 ;
306 if (p == NULL)
307 return FALSE;
308
309 PKTSETLINK(p, PKTLINK(pktbuf));
310 if (q->tail == pktbuf)
311 q->tail = p;
312 }
313
314 q->len--;
315 pq->len--;
316 PKTSETLINK(pktbuf, NULL);
317 return TRUE;
318}
319
320void
321pktq_init(struct pktq *pq, int num_prec, int max_len)
322{
323 int prec;
324
325 ASSERT(num_prec > 0 && num_prec <= PKTQ_MAX_PREC);
326
327 /* pq is variable size; only zero out what's requested */
328 bzero(pq, OFFSETOF(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec));
329
330 pq->num_prec = (uint16)num_prec;
331
332 pq->max = (uint16)max_len;
333
334 for (prec = 0; prec < num_prec; prec++)
335 pq->q[prec].max = pq->max;
336}
337
338void *
339pktq_deq(struct pktq *pq, int *prec_out)
340{
341 struct pktq_prec *q;
342 void *p;
343 int prec;
344
345 if (pq->len == 0)
346 return NULL;
347
348 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
349 pq->hi_prec--;
350
351 q = &pq->q[prec];
352
353 if ((p = q->head) == NULL)
354 return NULL;
355
356 if ((q->head = PKTLINK(p)) == NULL)
357 q->tail = NULL;
358
359 q->len--;
360
361 pq->len--;
362
363 if (prec_out)
364 *prec_out = prec;
365
366 PKTSETLINK(p, NULL);
367
368 return p;
369}
370
371void *
372pktq_deq_tail(struct pktq *pq, int *prec_out)
373{
374 struct pktq_prec *q;
375 void *p, *prev;
376 int prec;
377
378 if (pq->len == 0)
379 return NULL;
380
381 for (prec = 0; prec < pq->hi_prec; prec++)
382 if (pq->q[prec].head)
383 break;
384
385 q = &pq->q[prec];
386
387 if ((p = q->head) == NULL)
388 return NULL;
389
390 for (prev = NULL; p != q->tail; p = PKTLINK(p))
391 prev = p;
392
393 if (prev)
394 PKTSETLINK(prev, NULL);
395 else
396 q->head = NULL;
397
398 q->tail = prev;
399 q->len--;
400
401 pq->len--;
402
403 if (prec_out)
404 *prec_out = prec;
405
406 PKTSETLINK(p, NULL);
407
408 return p;
409}
410
411void *
412pktq_peek(struct pktq *pq, int *prec_out)
413{
414 int prec;
415
416 if (pq->len == 0)
417 return NULL;
418
419 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
420 pq->hi_prec--;
421
422 if (prec_out)
423 *prec_out = prec;
424
425 return (pq->q[prec].head);
426}
427
428void *
429pktq_peek_tail(struct pktq *pq, int *prec_out)
430{
431 int prec;
432
433 if (pq->len == 0)
434 return NULL;
435
436 for (prec = 0; prec < pq->hi_prec; prec++)
437 if (pq->q[prec].head)
438 break;
439
440 if (prec_out)
441 *prec_out = prec;
442
443 return (pq->q[prec].tail);
444}
445
446void
447pktq_flush(osl_t *osh, struct pktq *pq, bool dir)
448{
449 int prec;
450 for (prec = 0; prec < pq->num_prec; prec++)
451 pktq_pflush(osh, pq, prec, dir);
452 ASSERT(pq->len == 0);
453}
454
455/* Return sum of lengths of a specific set of precedences */
456int
457pktq_mlen(struct pktq *pq, uint prec_bmp)
458{
459 int prec, len;
460
461 len = 0;
462
463 for (prec = 0; prec <= pq->hi_prec; prec++)
464 if (prec_bmp & (1 << prec))
465 len += pq->q[prec].len;
466
467 return len;
468}
469
470/* Priority dequeue from a specific set of precedences */
471void *
472pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out)
473{
474 struct pktq_prec *q;
475 void *p;
476 int prec;
477
478 if (pq->len == 0)
479 return NULL;
480
481 while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
482 pq->hi_prec--;
483
484 while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
485 if (prec-- == 0)
486 return NULL;
487
488 q = &pq->q[prec];
489
490 if ((p = q->head) == NULL)
491 return NULL;
492
493 if ((q->head = PKTLINK(p)) == NULL)
494 q->tail = NULL;
495
496 q->len--;
497
498 if (prec_out)
499 *prec_out = prec;
500
501 pq->len--;
502
503 PKTSETLINK(p, NULL);
504
505 return p;
506}
507#endif /* BCMDRIVER */
508
509
510
511const unsigned char bcm_ctype[] = {
512 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 0-7 */
513 _BCM_C, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C|_BCM_S, _BCM_C,
514 _BCM_C, /* 8-15 */
515 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 16-23 */
516 _BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C,_BCM_C, /* 24-31 */
517 _BCM_S|_BCM_SP,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 32-39 */
518 _BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 40-47 */
519 _BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D,_BCM_D, /* 48-55 */
520 _BCM_D,_BCM_D,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 56-63 */
521 _BCM_P, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X, _BCM_U|_BCM_X,
522 _BCM_U|_BCM_X, _BCM_U, /* 64-71 */
523 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 72-79 */
524 _BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U,_BCM_U, /* 80-87 */
525 _BCM_U,_BCM_U,_BCM_U,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_P, /* 88-95 */
526 _BCM_P, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X, _BCM_L|_BCM_X,
527 _BCM_L|_BCM_X, _BCM_L, /* 96-103 */
528 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 104-111 */
529 _BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L,_BCM_L, /* 112-119 */
530 _BCM_L,_BCM_L,_BCM_L,_BCM_P,_BCM_P,_BCM_P,_BCM_P,_BCM_C, /* 120-127 */
531 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 128-143 */
532 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 144-159 */
533 _BCM_S|_BCM_SP, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
534 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 160-175 */
535 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P,
536 _BCM_P, _BCM_P, _BCM_P, _BCM_P, _BCM_P, /* 176-191 */
537 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U,
538 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, /* 192-207 */
539 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_P, _BCM_U, _BCM_U, _BCM_U,
540 _BCM_U, _BCM_U, _BCM_U, _BCM_U, _BCM_L, /* 208-223 */
541 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L,
542 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, /* 224-239 */
543 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_P, _BCM_L, _BCM_L, _BCM_L,
544 _BCM_L, _BCM_L, _BCM_L, _BCM_L, _BCM_L /* 240-255 */
545};
546
547ulong
548bcm_strtoul(char *cp, char **endp, uint base)
549{
550 ulong result, last_result = 0, value;
551 bool minus;
552
553 minus = FALSE;
554
555 while (bcm_isspace(*cp))
556 cp++;
557
558 if (cp[0] == '+')
559 cp++;
560 else if (cp[0] == '-') {
561 minus = TRUE;
562 cp++;
563 }
564
565 if (base == 0) {
566 if (cp[0] == '0') {
567 if ((cp[1] == 'x') || (cp[1] == 'X')) {
568 base = 16;
569 cp = &cp[2];
570 } else {
571 base = 8;
572 cp = &cp[1];
573 }
574 } else
575 base = 10;
576 } else if (base == 16 && (cp[0] == '0') && ((cp[1] == 'x') || (cp[1] == 'X'))) {
577 cp = &cp[2];
578 }
579
580 result = 0;
581
582 while (bcm_isxdigit(*cp) &&
583 (value = bcm_isdigit(*cp) ? *cp-'0' : bcm_toupper(*cp)-'A'+10) < base) {
584 result = result*base + value;
585 /* Detected overflow */
586 if (result < last_result && !minus)
587 return (ulong)-1;
588 last_result = result;
589 cp++;
590 }
591
592 if (minus)
593 result = (ulong)(-(long)result);
594
595 if (endp)
596 *endp = (char *)cp;
597
598 return (result);
599}
600
601int
602bcm_atoi(char *s)
603{
604 return (int)bcm_strtoul(s, NULL, 10);
605}
606
607/* return pointer to location of substring 'needle' in 'haystack' */
608char*
609bcmstrstr(char *haystack, char *needle)
610{
611 int len, nlen;
612 int i;
613
614 if ((haystack == NULL) || (needle == NULL))
615 return (haystack);
616
617 nlen = strlen(needle);
618 len = strlen(haystack) - nlen + 1;
619
620 for (i = 0; i < len; i++)
621 if (memcmp(needle, &haystack[i], nlen) == 0)
622 return (&haystack[i]);
623 return (NULL);
624}
625
626char*
627bcmstrcat(char *dest, const char *src)
628{
629 char *p;
630
631 p = dest + strlen(dest);
632
633 while ((*p++ = *src++) != '\0')
634 ;
635
636 return (dest);
637}
638
639char*
640bcmstrncat(char *dest, const char *src, uint size)
641{
642 char *endp;
643 char *p;
644
645 p = dest + strlen(dest);
646 endp = p + size;
647
648 while (p != endp && (*p++ = *src++) != '\0')
649 ;
650
651 return (dest);
652}
653
654
655/****************************************************************************
656* Function: bcmstrtok
657*
658* Purpose:
659* Tokenizes a string. This function is conceptually similiar to ANSI C strtok(),
660* but allows strToken() to be used by different strings or callers at the same
661* time. Each call modifies '*string' by substituting a NULL character for the
662* first delimiter that is encountered, and updates 'string' to point to the char
663* after the delimiter. Leading delimiters are skipped.
664*
665* Parameters:
666* string (mod) Ptr to string ptr, updated by token.
667* delimiters (in) Set of delimiter characters.
668* tokdelim (out) Character that delimits the returned token. (May
669* be set to NULL if token delimiter is not required).
670*
671* Returns: Pointer to the next token found. NULL when no more tokens are found.
672*****************************************************************************
673*/
674char *
675bcmstrtok(char **string, const char *delimiters, char *tokdelim)
676{
677 unsigned char *str;
678 unsigned long map[8];
679 int count;
680 char *nextoken;
681
682 if (tokdelim != NULL) {
683 /* Prime the token delimiter */
684 *tokdelim = '\0';
685 }
686
687 /* Clear control map */
688 for (count = 0; count < 8; count++) {
689 map[count] = 0;
690 }
691
692 /* Set bits in delimiter table */
693 do {
694 map[*delimiters >> 5] |= (1 << (*delimiters & 31));
695 }
696 while (*delimiters++);
697
698 str = (unsigned char*)*string;
699
700 /* Find beginning of token (skip over leading delimiters). Note that
701 * there is no token iff this loop sets str to point to the terminal
702 * null (*str == '\0')
703 */
704 while (((map[*str >> 5] & (1 << (*str & 31))) && *str) || (*str == ' ')) {
705 str++;
706 }
707
708 nextoken = (char*)str;
709
710 /* Find the end of the token. If it is not the end of the string,
711 * put a null there.
712 */
713 for (; *str; str++) {
714 if (map[*str >> 5] & (1 << (*str & 31))) {
715 if (tokdelim != NULL) {
716 *tokdelim = *str;
717 }
718
719 *str++ = '\0';
720 break;
721 }
722 }
723
724 *string = (char*)str;
725
726 /* Determine if a token has been found. */
727 if (nextoken == (char *) str) {
728 return NULL;
729 }
730 else {
731 return nextoken;
732 }
733}
734
735
736#define xToLower(C) \
737 ((C >= 'A' && C <= 'Z') ? (char)((int)C - (int)'A' + (int)'a') : C)
738
739
740/****************************************************************************
741* Function: bcmstricmp
742*
743* Purpose: Compare to strings case insensitively.
744*
745* Parameters: s1 (in) First string to compare.
746* s2 (in) Second string to compare.
747*
748* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
749* t1 > t2, when ignoring case sensitivity.
750*****************************************************************************
751*/
752int
753bcmstricmp(const char *s1, const char *s2)
754{
755 char dc, sc;
756
757 while (*s2 && *s1) {
758 dc = xToLower(*s1);
759 sc = xToLower(*s2);
760 if (dc < sc) return -1;
761 if (dc > sc) return 1;
762 s1++;
763 s2++;
764 }
765
766 if (*s1 && !*s2) return 1;
767 if (!*s1 && *s2) return -1;
768 return 0;
769}
770
771
772/****************************************************************************
773* Function: bcmstrnicmp
774*
775* Purpose: Compare to strings case insensitively, upto a max of 'cnt'
776* characters.
777*
778* Parameters: s1 (in) First string to compare.
779* s2 (in) Second string to compare.
780* cnt (in) Max characters to compare.
781*
782* Returns: Return 0 if the two strings are equal, -1 if t1 < t2 and 1 if
783* t1 > t2, when ignoring case sensitivity.
784*****************************************************************************
785*/
786int
787bcmstrnicmp(const char* s1, const char* s2, int cnt)
788{
789 char dc, sc;
790
791 while (*s2 && *s1 && cnt) {
792 dc = xToLower(*s1);
793 sc = xToLower(*s2);
794 if (dc < sc) return -1;
795 if (dc > sc) return 1;
796 s1++;
797 s2++;
798 cnt--;
799 }
800
801 if (!cnt) return 0;
802 if (*s1 && !*s2) return 1;
803 if (!*s1 && *s2) return -1;
804 return 0;
805}
806
807/* parse a xx:xx:xx:xx:xx:xx format ethernet address */
808int
809bcm_ether_atoe(char *p, struct ether_addr *ea)
810{
811 int i = 0;
812
813 for (;;) {
814 ea->octet[i++] = (char) bcm_strtoul(p, &p, 16);
815 if (!*p++ || i == 6)
816 break;
817 }
818
819 return (i == 6);
820}
821
822
823#if defined(CONFIG_USBRNDIS_RETAIL) || defined(NDIS_MINIPORT_DRIVER)
824/* registry routine buffer preparation utility functions:
825 * parameter order is like strncpy, but returns count
826 * of bytes copied. Minimum bytes copied is null char(1)/wchar(2)
827 */
828ulong
829wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen)
830{
831 ulong copyct = 1;
832 ushort i;
833
834 if (abuflen == 0)
835 return 0;
836
837 /* wbuflen is in bytes */
838 wbuflen /= sizeof(ushort);
839
840 for (i = 0; i < wbuflen; ++i) {
841 if (--abuflen == 0)
842 break;
843 *abuf++ = (char) *wbuf++;
844 ++copyct;
845 }
846 *abuf = '\0';
847
848 return copyct;
849}
850#endif /* CONFIG_USBRNDIS_RETAIL || NDIS_MINIPORT_DRIVER */
851
852char *
853bcm_ether_ntoa(const struct ether_addr *ea, char *buf)
854{
855 static const char template[] = "%02x:%02x:%02x:%02x:%02x:%02x";
856 snprintf(buf, 18, template,
857 ea->octet[0]&0xff, ea->octet[1]&0xff, ea->octet[2]&0xff,
858 ea->octet[3]&0xff, ea->octet[4]&0xff, ea->octet[5]&0xff);
859 return (buf);
860}
861
862char *
863bcm_ip_ntoa(struct ipv4_addr *ia, char *buf)
864{
865 snprintf(buf, 16, "%d.%d.%d.%d",
866 ia->addr[0], ia->addr[1], ia->addr[2], ia->addr[3]);
867 return (buf);
868}
869
870#ifdef BCMDRIVER
871
872void
873bcm_mdelay(uint ms)
874{
875 uint i;
876
877 for (i = 0; i < ms; i++) {
878 OSL_DELAY(1000);
879 }
880}
881
882
883
884
885
886
887#if defined(DHD_DEBUG)
888/* pretty hex print a pkt buffer chain */
889void
890prpkt(const char *msg, osl_t *osh, void *p0)
891{
892 void *p;
893
894 if (msg && (msg[0] != '\0'))
895 printf("%s:\n", msg);
896
897 for (p = p0; p; p = PKTNEXT(osh, p))
898 prhex(NULL, PKTDATA(osh, p), PKTLEN(osh, p));
899}
900#endif
901
902/* Takes an Ethernet frame and sets out-of-bound PKTPRIO.
903 * Also updates the inplace vlan tag if requested.
904 * For debugging, it returns an indication of what it did.
905 */
906uint
907pktsetprio(void *pkt, bool update_vtag)
908{
909 struct ether_header *eh;
910 struct ethervlan_header *evh;
911 uint8 *pktdata;
912 int priority = 0;
913 int rc = 0;
914
915 pktdata = (uint8 *) PKTDATA(NULL, pkt);
916 ASSERT(ISALIGNED((uintptr)pktdata, sizeof(uint16)));
917
918 eh = (struct ether_header *) pktdata;
919
920 if (ntoh16(eh->ether_type) == ETHER_TYPE_8021Q) {
921 uint16 vlan_tag;
922 int vlan_prio, dscp_prio = 0;
923
924 evh = (struct ethervlan_header *)eh;
925
926 vlan_tag = ntoh16(evh->vlan_tag);
927 vlan_prio = (int) (vlan_tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK;
928
929 if (ntoh16(evh->ether_type) == ETHER_TYPE_IP) {
930 uint8 *ip_body = pktdata + sizeof(struct ethervlan_header);
931 uint8 tos_tc = IP_TOS(ip_body);
932 dscp_prio = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
933 }
934
935 /* DSCP priority gets precedence over 802.1P (vlan tag) */
936 if (dscp_prio != 0) {
937 priority = dscp_prio;
938 rc |= PKTPRIO_VDSCP;
939 } else {
940 priority = vlan_prio;
941 rc |= PKTPRIO_VLAN;
942 }
943 /*
944 * If the DSCP priority is not the same as the VLAN priority,
945 * then overwrite the priority field in the vlan tag, with the
946 * DSCP priority value. This is required for Linux APs because
947 * the VLAN driver on Linux, overwrites the skb->priority field
948 * with the priority value in the vlan tag
949 */
950 if (update_vtag && (priority != vlan_prio)) {
951 vlan_tag &= ~(VLAN_PRI_MASK << VLAN_PRI_SHIFT);
952 vlan_tag |= (uint16)priority << VLAN_PRI_SHIFT;
953 evh->vlan_tag = hton16(vlan_tag);
954 rc |= PKTPRIO_UPD;
955 }
956 } else if (ntoh16(eh->ether_type) == ETHER_TYPE_IP) {
957 uint8 *ip_body = pktdata + sizeof(struct ether_header);
958 uint8 tos_tc = IP_TOS(ip_body);
959 priority = (int)(tos_tc >> IPV4_TOS_PREC_SHIFT);
960 rc |= PKTPRIO_DSCP;
961 }
962
963 ASSERT(priority >= 0 && priority <= MAXPRIO);
964 PKTSETPRIO(pkt, priority);
965 return (rc | priority);
966}
967
968static char bcm_undeferrstr[BCME_STRLEN];
969
970static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE;
971
972/* Convert the error codes into related error strings */
973const char *
974bcmerrorstr(int bcmerror)
975{
976 /* check if someone added a bcmerror code but forgot to add errorstring */
977 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(bcmerrorstrtable) - 1));
978
979 if (bcmerror > 0 || bcmerror < BCME_LAST) {
980 snprintf(bcm_undeferrstr, BCME_STRLEN, "Undefined error %d", bcmerror);
981 return bcm_undeferrstr;
982 }
983
984 ASSERT(strlen(bcmerrorstrtable[-bcmerror]) < BCME_STRLEN);
985
986 return bcmerrorstrtable[-bcmerror];
987}
988
989
990
991/* iovar table lookup */
992const bcm_iovar_t*
993bcm_iovar_lookup(const bcm_iovar_t *table, const char *name)
994{
995 const bcm_iovar_t *vi;
996 const char *lookup_name;
997
998 /* skip any ':' delimited option prefixes */
999 lookup_name = strrchr(name, ':');
1000 if (lookup_name != NULL)
1001 lookup_name++;
1002 else
1003 lookup_name = name;
1004
1005 ASSERT(table != NULL);
1006
1007 for (vi = table; vi->name; vi++) {
1008 if (!strcmp(vi->name, lookup_name))
1009 return vi;
1010 }
1011 /* ran to end of table */
1012
1013 return NULL; /* var name not found */
1014}
1015
1016int
1017bcm_iovar_lencheck(const bcm_iovar_t *vi, void *arg, int len, bool set)
1018{
1019 int bcmerror = 0;
1020
1021 /* length check on io buf */
1022 switch (vi->type) {
1023 case IOVT_BOOL:
1024 case IOVT_INT8:
1025 case IOVT_INT16:
1026 case IOVT_INT32:
1027 case IOVT_UINT8:
1028 case IOVT_UINT16:
1029 case IOVT_UINT32:
1030 /* all integers are int32 sized args at the ioctl interface */
1031 if (len < (int)sizeof(int)) {
1032 bcmerror = BCME_BUFTOOSHORT;
1033 }
1034 break;
1035
1036 case IOVT_BUFFER:
1037 /* buffer must meet minimum length requirement */
1038 if (len < vi->minlen) {
1039 bcmerror = BCME_BUFTOOSHORT;
1040 }
1041 break;
1042
1043 case IOVT_VOID:
1044 if (!set) {
1045 /* Cannot return nil... */
1046 bcmerror = BCME_UNSUPPORTED;
1047 } else if (len) {
1048 /* Set is an action w/o parameters */
1049 bcmerror = BCME_BUFTOOLONG;
1050 }
1051 break;
1052
1053 default:
1054 /* unknown type for length check in iovar info */
1055 ASSERT(0);
1056 bcmerror = BCME_UNSUPPORTED;
1057 }
1058
1059 return bcmerror;
1060}
1061
1062#endif /* BCMDRIVER */
1063
1064/*******************************************************************************
1065 * crc8
1066 *
1067 * Computes a crc8 over the input data using the polynomial:
1068 *
1069 * x^8 + x^7 +x^6 + x^4 + x^2 + 1
1070 *
1071 * The caller provides the initial value (either CRC8_INIT_VALUE
1072 * or the previous returned value) to allow for processing of
1073 * discontiguous blocks of data. When generating the CRC the
1074 * caller is responsible for complementing the final return value
1075 * and inserting it into the byte stream. When checking, a final
1076 * return value of CRC8_GOOD_VALUE indicates a valid CRC.
1077 *
1078 * Reference: Dallas Semiconductor Application Note 27
1079 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1080 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1081 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1082 *
1083 * ****************************************************************************
1084 */
1085
1086STATIC const uint8 crc8_table[256] = {
1087 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
1088 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
1089 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
1090 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
1091 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
1092 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
1093 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
1094 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
1095 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
1096 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
1097 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
1098 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
1099 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
1100 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
1101 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
1102 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
1103 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
1104 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
1105 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
1106 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
1107 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
1108 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
1109 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
1110 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
1111 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
1112 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
1113 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
1114 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
1115 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
1116 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
1117 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
1118 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F
1119};
1120
1121#define CRC_INNER_LOOP(n, c, x) \
1122 (c) = ((c) >> 8) ^ crc##n##_table[((c) ^ (x)) & 0xff]
1123
1124uint8
1125hndcrc8(
1126 uint8 *pdata, /* pointer to array of data to process */
1127 uint nbytes, /* number of input data bytes to process */
1128 uint8 crc /* either CRC8_INIT_VALUE or previous return value */
1129)
1130{
1131 /* hard code the crc loop instead of using CRC_INNER_LOOP macro
1132 * to avoid the undefined and unnecessary (uint8 >> 8) operation.
1133 */
1134 while (nbytes-- > 0)
1135 crc = crc8_table[(crc ^ *pdata++) & 0xff];
1136
1137 return crc;
1138}
1139
1140/*******************************************************************************
1141 * crc16
1142 *
1143 * Computes a crc16 over the input data using the polynomial:
1144 *
1145 * x^16 + x^12 +x^5 + 1
1146 *
1147 * The caller provides the initial value (either CRC16_INIT_VALUE
1148 * or the previous returned value) to allow for processing of
1149 * discontiguous blocks of data. When generating the CRC the
1150 * caller is responsible for complementing the final return value
1151 * and inserting it into the byte stream. When checking, a final
1152 * return value of CRC16_GOOD_VALUE indicates a valid CRC.
1153 *
1154 * Reference: Dallas Semiconductor Application Note 27
1155 * Williams, Ross N., "A Painless Guide to CRC Error Detection Algorithms",
1156 * ver 3, Aug 1993, ross@guest.adelaide.edu.au, Rocksoft Pty Ltd.,
1157 * ftp://ftp.rocksoft.com/clients/rocksoft/papers/crc_v3.txt
1158 *
1159 * ****************************************************************************
1160 */
1161
1162static const uint16 crc16_table[256] = {
1163 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF,
1164 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7,
1165 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E,
1166 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
1167 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD,
1168 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5,
1169 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C,
1170 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974,
1171 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB,
1172 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3,
1173 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A,
1174 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72,
1175 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
1176 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1,
1177 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738,
1178 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70,
1179 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7,
1180 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF,
1181 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036,
1182 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E,
1183 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5,
1184 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
1185 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134,
1186 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C,
1187 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3,
1188 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB,
1189 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232,
1190 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A,
1191 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1,
1192 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9,
1193 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
1194 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78
1195};
1196
1197uint16
1198hndcrc16(
1199 uint8 *pdata, /* pointer to array of data to process */
1200 uint nbytes, /* number of input data bytes to process */
1201 uint16 crc /* either CRC16_INIT_VALUE or previous return value */
1202)
1203{
1204 while (nbytes-- > 0)
1205 CRC_INNER_LOOP(16, crc, *pdata++);
1206 return crc;
1207}
1208
1209STATIC const uint32 crc32_table[256] = {
1210 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
1211 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1212 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
1213 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1214 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
1215 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1216 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
1217 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1218 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
1219 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1220 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
1221 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1222 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
1223 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1224 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
1225 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1226 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
1227 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1228 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
1229 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1230 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
1231 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1232 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
1233 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1234 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
1235 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1236 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
1237 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1238 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
1239 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1240 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
1241 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1242 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
1243 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1244 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
1245 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1246 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
1247 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1248 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
1249 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1250 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
1251 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1252 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
1253 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1254 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
1255 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1256 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
1257 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1258 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
1259 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1260 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
1261 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1262 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
1263 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1264 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
1265 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1266 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
1267 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1268 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
1269 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1270 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
1271 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1272 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
1273 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1274};
1275
1276uint32
1277hndcrc32(
1278 uint8 *pdata, /* pointer to array of data to process */
1279 uint nbytes, /* number of input data bytes to process */
1280 uint32 crc /* either CRC32_INIT_VALUE or previous return value */
1281)
1282{
1283 uint8 *pend;
1284#ifdef __mips__
1285 uint8 tmp[4];
1286 ulong *tptr = (ulong *)tmp;
1287
1288 /* in case the beginning of the buffer isn't aligned */
1289 pend = (uint8 *)((uint)(pdata + 3) & 0xfffffffc);
1290 nbytes -= (pend - pdata);
1291 while (pdata < pend)
1292 CRC_INNER_LOOP(32, crc, *pdata++);
1293
1294 /* handle bulk of data as 32-bit words */
1295 pend = pdata + (nbytes & 0xfffffffc);
1296 while (pdata < pend) {
1297 *tptr = *(ulong *)pdata;
1298 pdata += sizeof(ulong *);
1299 CRC_INNER_LOOP(32, crc, tmp[0]);
1300 CRC_INNER_LOOP(32, crc, tmp[1]);
1301 CRC_INNER_LOOP(32, crc, tmp[2]);
1302 CRC_INNER_LOOP(32, crc, tmp[3]);
1303 }
1304
1305 /* 1-3 bytes at end of buffer */
1306 pend = pdata + (nbytes & 0x03);
1307 while (pdata < pend)
1308 CRC_INNER_LOOP(32, crc, *pdata++);
1309#else
1310 pend = pdata + nbytes;
1311 while (pdata < pend)
1312 CRC_INNER_LOOP(32, crc, *pdata++);
1313#endif /* __mips__ */
1314
1315 return crc;
1316}
1317
1318#ifdef notdef
1319#define CLEN 1499 /* CRC Length */
1320#define CBUFSIZ (CLEN+4)
1321#define CNBUFS 5 /* # of bufs */
1322
1323void testcrc32(void)
1324{
1325 uint j, k, l;
1326 uint8 *buf;
1327 uint len[CNBUFS];
1328 uint32 crcr;
1329 uint32 crc32tv[CNBUFS] =
1330 {0xd2cb1faa, 0xd385c8fa, 0xf5b4f3f3, 0x55789e20, 0x00343110};
1331
1332 ASSERT((buf = MALLOC(CBUFSIZ*CNBUFS)) != NULL);
1333
1334 /* step through all possible alignments */
1335 for (l = 0; l <= 4; l++) {
1336 for (j = 0; j < CNBUFS; j++) {
1337 len[j] = CLEN;
1338 for (k = 0; k < len[j]; k++)
1339 *(buf + j*CBUFSIZ + (k+l)) = (j+k) & 0xff;
1340 }
1341
1342 for (j = 0; j < CNBUFS; j++) {
1343 crcr = crc32(buf + j*CBUFSIZ + l, len[j], CRC32_INIT_VALUE);
1344 ASSERT(crcr == crc32tv[j]);
1345 }
1346 }
1347
1348 MFREE(buf, CBUFSIZ*CNBUFS);
1349 return;
1350}
1351#endif /* notdef */
1352
1353/*
1354 * Advance from the current 1-byte tag/1-byte length/variable-length value
1355 * triple, to the next, returning a pointer to the next.
1356 * If the current or next TLV is invalid (does not fit in given buffer length),
1357 * NULL is returned.
1358 * *buflen is not modified if the TLV elt parameter is invalid, or is decremented
1359 * by the TLV parameter's length if it is valid.
1360 */
1361bcm_tlv_t *
1362bcm_next_tlv(bcm_tlv_t *elt, int *buflen)
1363{
1364 int len;
1365
1366 /* validate current elt */
1367 if (!bcm_valid_tlv(elt, *buflen))
1368 return NULL;
1369
1370 /* advance to next elt */
1371 len = elt->len;
1372 elt = (bcm_tlv_t*)(elt->data + len);
1373 *buflen -= (2 + len);
1374
1375 /* validate next elt */
1376 if (!bcm_valid_tlv(elt, *buflen))
1377 return NULL;
1378
1379 return elt;
1380}
1381
1382/*
1383 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1384 * triples, returning a pointer to the substring whose first element
1385 * matches tag
1386 */
1387bcm_tlv_t *
1388bcm_parse_tlvs(void *buf, int buflen, uint key)
1389{
1390 bcm_tlv_t *elt;
1391 int totlen;
1392
1393 elt = (bcm_tlv_t*)buf;
1394 totlen = buflen;
1395
1396 /* find tagged parameter */
1397 while (totlen >= 2) {
1398 int len = elt->len;
1399
1400 /* validate remaining totlen */
1401 if ((elt->id == key) && (totlen >= (len + 2)))
1402 return (elt);
1403
1404 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1405 totlen -= (len + 2);
1406 }
1407
1408 return NULL;
1409}
1410
1411/*
1412 * Traverse a string of 1-byte tag/1-byte length/variable-length value
1413 * triples, returning a pointer to the substring whose first element
1414 * matches tag. Stop parsing when we see an element whose ID is greater
1415 * than the target key.
1416 */
1417bcm_tlv_t *
1418bcm_parse_ordered_tlvs(void *buf, int buflen, uint key)
1419{
1420 bcm_tlv_t *elt;
1421 int totlen;
1422
1423 elt = (bcm_tlv_t*)buf;
1424 totlen = buflen;
1425
1426 /* find tagged parameter */
1427 while (totlen >= 2) {
1428 uint id = elt->id;
1429 int len = elt->len;
1430
1431 /* Punt if we start seeing IDs > than target key */
1432 if (id > key)
1433 return (NULL);
1434
1435 /* validate remaining totlen */
1436 if ((id == key) && (totlen >= (len + 2)))
1437 return (elt);
1438
1439 elt = (bcm_tlv_t*)((uint8*)elt + (len + 2));
1440 totlen -= (len + 2);
1441 }
1442 return NULL;
1443}
1444
1445#if defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || defined(WLMSG_ASSOC) || \
1446 defined(DHD_DEBUG)
1447int
1448bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len)
1449{
1450 int i;
1451 char* p = buf;
1452 char hexstr[16];
1453 int slen = 0;
1454 uint32 bit;
1455 const char* name;
1456
1457 if (len < 2 || !buf)
1458 return 0;
1459
1460 buf[0] = '\0';
1461 len -= 1;
1462
1463 for (i = 0; flags != 0; i++) {
1464 bit = bd[i].bit;
1465 name = bd[i].name;
1466 if (bit == 0 && flags) {
1467 /* print any unnamed bits */
1468 sprintf(hexstr, "0x%X", flags);
1469 name = hexstr;
1470 flags = 0; /* exit loop */
1471 } else if ((flags & bit) == 0)
1472 continue;
1473 slen += strlen(name);
1474 if (len < slen)
1475 break;
1476 if (p != buf) p += sprintf(p, " "); /* btwn flag space */
1477 strcat(p, name);
1478 p += strlen(name);
1479 flags &= ~bit;
1480 len -= slen;
1481 slen = 1; /* account for btwn flag space */
1482 }
1483
1484 /* indicate the str was too short */
1485 if (flags != 0) {
1486 if (len == 0)
1487 p--; /* overwrite last char */
1488 p += sprintf(p, ">");
1489 }
1490
1491 return (int)(p - buf);
1492}
1493
1494/* print bytes formatted as hex to a string. return the resulting string length */
1495int
1496bcm_format_hex(char *str, const void *bytes, int len)
1497{
1498 int i;
1499 char *p = str;
1500 const uint8 *src = (const uint8*)bytes;
1501
1502 for (i = 0; i < len; i++) {
1503 p += sprintf(p, "%02X", *src);
1504 src++;
1505 }
1506 return (int)(p - str);
1507}
1508
1509/* pretty hex print a contiguous buffer */
1510void
1511prhex(const char *msg, uchar *buf, uint nbytes)
1512{
1513 char line[128], *p;
1514 uint i;
1515
1516 if (msg && (msg[0] != '\0'))
1517 printf("%s:\n", msg);
1518
1519 p = line;
1520 for (i = 0; i < nbytes; i++) {
1521 if (i % 16 == 0) {
1522 p += sprintf(p, " %04d: ", i); /* line prefix */
1523 }
1524 p += sprintf(p, "%02x ", buf[i]);
1525 if (i % 16 == 15) {
1526 printf("%s\n", line); /* flush line */
1527 p = line;
1528 }
1529 }
1530
1531 /* flush last partial line */
1532 if (p != line)
1533 printf("%s\n", line);
1534}
1535#endif
1536
1537
1538/* Produce a human-readable string for boardrev */
1539char *
1540bcm_brev_str(uint32 brev, char *buf)
1541{
1542 if (brev < 0x100)
1543 snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
1544 else
1545 snprintf(buf, 8, "%c%03x", ((brev & 0xf000) == 0x1000) ? 'P' : 'A', brev & 0xfff);
1546
1547 return (buf);
1548}
1549
1550#define BUFSIZE_TODUMP_ATONCE 512 /* Buffer size */
1551
1552/* dump large strings to console */
1553void
1554printbig(char *buf)
1555{
1556 uint len, max_len;
1557 char c;
1558
1559 len = strlen(buf);
1560
1561 max_len = BUFSIZE_TODUMP_ATONCE;
1562
1563 while (len > max_len) {
1564 c = buf[max_len];
1565 buf[max_len] = '\0';
1566 printf("%s", buf);
1567 buf[max_len] = c;
1568
1569 buf += max_len;
1570 len -= max_len;
1571 }
1572 /* print the remaining string */
1573 printf("%s\n", buf);
1574 return;
1575}
1576
1577/* routine to dump fields in a fileddesc structure */
1578uint
1579bcmdumpfields(bcmutl_rdreg_rtn read_rtn, void *arg0, uint arg1, struct fielddesc *fielddesc_array,
1580 char *buf, uint32 bufsize)
1581{
1582 uint filled_len;
1583 int len;
1584 struct fielddesc *cur_ptr;
1585
1586 filled_len = 0;
1587 cur_ptr = fielddesc_array;
1588
1589 while (bufsize > 1) {
1590 if (cur_ptr->nameandfmt == NULL)
1591 break;
1592 len = snprintf(buf, bufsize, cur_ptr->nameandfmt,
1593 read_rtn(arg0, arg1, cur_ptr->offset));
1594 /* check for snprintf overflow or error */
1595 if (len < 0 || (uint32)len >= bufsize)
1596 len = bufsize - 1;
1597 buf += len;
1598 bufsize -= len;
1599 filled_len += len;
1600 cur_ptr++;
1601 }
1602 return filled_len;
1603}
1604
1605uint
1606bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
1607{
1608 uint len;
1609
1610 len = strlen(name) + 1;
1611
1612 if ((len + datalen) > buflen)
1613 return 0;
1614
1615 strncpy(buf, name, buflen);
1616
1617 /* append data onto the end of the name string */
1618 memcpy(&buf[len], data, datalen);
1619 len += datalen;
1620
1621 return len;
1622}
1623
1624/* Quarter dBm units to mW
1625 * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153
1626 * Table is offset so the last entry is largest mW value that fits in
1627 * a uint16.
1628 */
1629
1630#define QDBM_OFFSET 153 /* Offset for first entry */
1631#define QDBM_TABLE_LEN 40 /* Table size */
1632
1633/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET.
1634 * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2
1635 */
1636#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */
1637
1638/* Largest mW value that will round down to the last table entry,
1639 * QDBM_OFFSET + QDBM_TABLE_LEN-1.
1640 * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2.
1641 */
1642#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */
1643
1644static const uint16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = {
1645/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */
1646/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000,
1647/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849,
1648/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119,
1649/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811,
1650/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096
1651};
1652
1653uint16
1654bcm_qdbm_to_mw(uint8 qdbm)
1655{
1656 uint factor = 1;
1657 int idx = qdbm - QDBM_OFFSET;
1658
1659 if (idx >= QDBM_TABLE_LEN) {
1660 /* clamp to max uint16 mW value */
1661 return 0xFFFF;
1662 }
1663
1664 /* scale the qdBm index up to the range of the table 0-40
1665 * where an offset of 40 qdBm equals a factor of 10 mW.
1666 */
1667 while (idx < 0) {
1668 idx += 40;
1669 factor *= 10;
1670 }
1671
1672 /* return the mW value scaled down to the correct factor of 10,
1673 * adding in factor/2 to get proper rounding.
1674 */
1675 return ((nqdBm_to_mW_map[idx] + factor/2) / factor);
1676}
1677
1678uint8
1679bcm_mw_to_qdbm(uint16 mw)
1680{
1681 uint8 qdbm;
1682 int offset;
1683 uint mw_uint = mw;
1684 uint boundary;
1685
1686 /* handle boundary case */
1687 if (mw_uint <= 1)
1688 return 0;
1689
1690 offset = QDBM_OFFSET;
1691
1692 /* move mw into the range of the table */
1693 while (mw_uint < QDBM_TABLE_LOW_BOUND) {
1694 mw_uint *= 10;
1695 offset -= 40;
1696 }
1697
1698 for (qdbm = 0; qdbm < QDBM_TABLE_LEN-1; qdbm++) {
1699 boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm+1] -
1700 nqdBm_to_mW_map[qdbm])/2;
1701 if (mw_uint < boundary) break;
1702 }
1703
1704 qdbm += (uint8)offset;
1705
1706 return (qdbm);
1707}
1708
1709
1710uint
1711bcm_bitcount(uint8 *bitmap, uint length)
1712{
1713 uint bitcount = 0, i;
1714 uint8 tmp;
1715 for (i = 0; i < length; i++) {
1716 tmp = bitmap[i];
1717 while (tmp) {
1718 bitcount++;
1719 tmp &= (tmp - 1);
1720 }
1721 }
1722 return bitcount;
1723}
1724
1725#ifdef BCMDRIVER
1726
1727/* Initialization of bcmstrbuf structure */
1728void
1729bcm_binit(struct bcmstrbuf *b, char *buf, uint size)
1730{
1731 b->origsize = b->size = size;
1732 b->origbuf = b->buf = buf;
1733}
1734
1735/* Buffer sprintf wrapper to guard against buffer overflow */
1736int
1737bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...)
1738{
1739 va_list ap;
1740 int r;
1741
1742 va_start(ap, fmt);
1743 r = vsnprintf(b->buf, b->size, fmt, ap);
1744
1745 /* Non Ansi C99 compliant returns -1,
1746 * Ansi compliant return r >= b->size,
1747 * bcmstdlib returns 0, handle all
1748 */
1749 if ((r == -1) || (r >= (int)b->size) || (r == 0)) {
1750 b->size = 0;
1751 } else {
1752 b->size -= r;
1753 b->buf += r;
1754 }
1755
1756 va_end(ap);
1757
1758 return r;
1759}
1760
1761void
1762bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount)
1763{
1764 int i;
1765
1766 for (i = 0; i < num_bytes; i++) {
1767 num[i] += amount;
1768 if (num[i] >= amount)
1769 break;
1770 amount = 1;
1771 }
1772}
1773
1774int
1775bcm_cmp_bytes(uchar *arg1, uchar *arg2, uint8 nbytes)
1776{
1777 int i;
1778
1779 for (i = nbytes - 1; i >= 0; i--) {
1780 if (arg1[i] != arg2[i])
1781 return (arg1[i] - arg2[i]);
1782 }
1783 return 0;
1784}
1785
1786void
1787bcm_print_bytes(char *name, const uchar *data, int len)
1788{
1789 int i;
1790 int per_line = 0;
1791
1792 printf("%s: %d \n", name ? name : "", len);
1793 for (i = 0; i < len; i++) {
1794 printf("%02x ", *data++);
1795 per_line++;
1796 if (per_line == 16) {
1797 per_line = 0;
1798 printf("\n");
1799 }
1800 }
1801 printf("\n");
1802}
1803
1804/*
1805 * buffer length needed for wlc_format_ssid
1806 * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
1807 */
1808
1809#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
1810 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
1811int
1812bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len)
1813{
1814 uint i, c;
1815 char *p = buf;
1816 char *endp = buf + SSID_FMT_BUF_LEN;
1817
1818 if (ssid_len > DOT11_MAX_SSID_LEN) ssid_len = DOT11_MAX_SSID_LEN;
1819
1820 for (i = 0; i < ssid_len; i++) {
1821 c = (uint)ssid[i];
1822 if (c == '\\') {
1823 *p++ = '\\';
1824 *p++ = '\\';
1825 } else if (bcm_isprint((uchar)c)) {
1826 *p++ = (char)c;
1827 } else {
1828 p += snprintf(p, (endp - p), "\\x%02X", c);
1829 }
1830 }
1831 *p = '\0';
1832 ASSERT(p < endp);
1833
1834 return (int)(p - buf);
1835}
1836#endif
1837
1838#endif /* BCMDRIVER */
diff --git a/drivers/net/wireless/bcm4329/bcmwifi.c b/drivers/net/wireless/bcm4329/bcmwifi.c
new file mode 100644
index 00000000000..803acf842a2
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/bcmwifi.c
@@ -0,0 +1,199 @@
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-2010, 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.18.24.2.4.1 2009/09/25 00:32:01 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#endif
41#include <bcmwifi.h>
42
43#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
44#include <bcmstdlib.h>
45#endif
46
47
48
49
50
51char *
52wf_chspec_ntoa(chanspec_t chspec, char *buf)
53{
54 const char *band, *bw, *sb;
55 uint channel;
56
57 band = "";
58 bw = "";
59 sb = "";
60 channel = CHSPEC_CHANNEL(chspec);
61
62 if ((CHSPEC_IS2G(chspec) && channel > CH_MAX_2G_CHANNEL) ||
63 (CHSPEC_IS5G(chspec) && channel <= CH_MAX_2G_CHANNEL))
64 band = (CHSPEC_IS2G(chspec)) ? "b" : "a";
65 if (CHSPEC_IS40(chspec)) {
66 if (CHSPEC_SB_UPPER(chspec)) {
67 sb = "u";
68 channel += CH_10MHZ_APART;
69 } else {
70 sb = "l";
71 channel -= CH_10MHZ_APART;
72 }
73 } else if (CHSPEC_IS10(chspec)) {
74 bw = "n";
75 }
76
77
78 snprintf(buf, 6, "%d%s%s%s", channel, band, bw, sb);
79 return (buf);
80}
81
82
83chanspec_t
84wf_chspec_aton(char *a)
85{
86 char *endp = NULL;
87 uint channel, band, bw, ctl_sb;
88 char c;
89
90 channel = strtoul(a, &endp, 10);
91
92
93 if (endp == a)
94 return 0;
95
96 if (channel > MAXCHANNEL)
97 return 0;
98
99 band = ((channel <= CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
100 bw = WL_CHANSPEC_BW_20;
101 ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
102
103 a = endp;
104
105 c = tolower(a[0]);
106 if (c == '\0')
107 goto done;
108
109
110 if (c == 'a' || c == 'b') {
111 band = (c == 'a') ? WL_CHANSPEC_BAND_5G : WL_CHANSPEC_BAND_2G;
112 a++;
113 c = tolower(a[0]);
114 if (c == '\0')
115 goto done;
116 }
117
118
119 if (c == 'n') {
120 bw = WL_CHANSPEC_BW_10;
121 } else if (c == 'l') {
122 bw = WL_CHANSPEC_BW_40;
123 ctl_sb = WL_CHANSPEC_CTL_SB_LOWER;
124
125 if (channel <= (MAXCHANNEL - CH_20MHZ_APART))
126 channel += CH_10MHZ_APART;
127 else
128 return 0;
129 } else if (c == 'u') {
130 bw = WL_CHANSPEC_BW_40;
131 ctl_sb = WL_CHANSPEC_CTL_SB_UPPER;
132
133 if (channel > CH_20MHZ_APART)
134 channel -= CH_10MHZ_APART;
135 else
136 return 0;
137 } else {
138 return 0;
139 }
140
141done:
142 return (channel | band | bw | ctl_sb);
143}
144
145
146int
147wf_mhz2channel(uint freq, uint start_factor)
148{
149 int ch = -1;
150 uint base;
151 int offset;
152
153
154 if (start_factor == 0) {
155 if (freq >= 2400 && freq <= 2500)
156 start_factor = WF_CHAN_FACTOR_2_4_G;
157 else if (freq >= 5000 && freq <= 6000)
158 start_factor = WF_CHAN_FACTOR_5_G;
159 }
160
161 if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G)
162 return 14;
163
164 base = start_factor / 2;
165
166
167 if ((freq < base) || (freq > base + 1000))
168 return -1;
169
170 offset = freq - base;
171 ch = offset / 5;
172
173
174 if (offset != (ch * 5))
175 return -1;
176
177
178 if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13))
179 return -1;
180
181 return ch;
182}
183
184
185int
186wf_channel2mhz(uint ch, uint start_factor)
187{
188 int freq;
189
190 if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) ||
191 (ch <= 200))
192 freq = -1;
193 if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14))
194 freq = 2484;
195 else
196 freq = ch * 5 + start_factor / 2;
197
198 return freq;
199}
diff --git a/drivers/net/wireless/bcm4329/dhd.h b/drivers/net/wireless/bcm4329/dhd.h
new file mode 100644
index 00000000000..8f0910cfc46
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/dhd.h
@@ -0,0 +1,472 @@
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-2010, 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,v 1.32.4.7.2.4.14.49.4.9 2011/01/14 22:40:45 Exp $
28 */
29
30/****************
31 * Common types *
32 */
33
34#ifndef _dhd_h_
35#define _dhd_h_
36
37#if defined(LINUX)
38#include <linux/init.h>
39#include <linux/kernel.h>
40#include <linux/slab.h>
41#include <linux/skbuff.h>
42#include <linux/netdevice.h>
43#include <linux/etherdevice.h>
44#include <linux/random.h>
45#include <linux/spinlock.h>
46#include <linux/ethtool.h>
47#include <linux/sched.h>
48#include <asm/uaccess.h>
49#include <asm/unaligned.h>
50
51#ifdef CONFIG_HAS_WAKELOCK
52#include <linux/wakelock.h>
53#endif
54
55/* The kernel threading is sdio-specific */
56#else /* LINUX */
57#define ENOMEM 1
58#define EFAULT 2
59#define EINVAL 3
60#define EIO 4
61#define ETIMEDOUT 5
62#define ERESTARTSYS 6
63#endif /* LINUX */
64
65#include <wlioctl.h>
66
67#ifdef DHD_DEBUG
68#ifndef DHD_DEBUG_TRAP
69#define DHD_DEBUG_TRAP
70#endif
71#endif
72
73/* Forward decls */
74struct dhd_bus;
75struct dhd_prot;
76struct dhd_info;
77
78/* The level of bus communication with the dongle */
79enum dhd_bus_state {
80 DHD_BUS_DOWN, /* Not ready for frame transfers */
81 DHD_BUS_LOAD, /* Download access only (CPU reset) */
82 DHD_BUS_DATA /* Ready for frame transfers */
83};
84
85enum dhd_bus_wake_state {
86 WAKE_LOCK_OFF,
87 WAKE_LOCK_PRIV,
88 WAKE_LOCK_DPC,
89 WAKE_LOCK_IOCTL,
90 WAKE_LOCK_DOWNLOAD,
91 WAKE_LOCK_TMOUT,
92 WAKE_LOCK_WATCHDOG,
93 WAKE_LOCK_LINK_DOWN_TMOUT,
94 WAKE_LOCK_PNO_FIND_TMOUT,
95 WAKE_LOCK_SOFTAP_SET,
96 WAKE_LOCK_SOFTAP_STOP,
97 WAKE_LOCK_SOFTAP_START,
98 WAKE_LOCK_SOFTAP_THREAD,
99 WAKE_LOCK_MAX
100};
101enum dhd_prealloc_index {
102 DHD_PREALLOC_PROT = 0,
103 DHD_PREALLOC_RXBUF,
104 DHD_PREALLOC_DATABUF,
105 DHD_PREALLOC_OSL_BUF
106};
107#ifdef DHD_USE_STATIC_BUF
108extern void * dhd_os_prealloc(int section, unsigned long size);
109#endif
110/* Common structure for module and instance linkage */
111typedef struct dhd_pub {
112 /* Linkage ponters */
113 osl_t *osh; /* OSL handle */
114 struct dhd_bus *bus; /* Bus module handle */
115 struct dhd_prot *prot; /* Protocol module handle */
116 struct dhd_info *info; /* Info module handle */
117
118 /* Internal dhd items */
119 bool up; /* Driver up/down (to OS) */
120 bool txoff; /* Transmit flow-controlled */
121 bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */
122 enum dhd_bus_state busstate;
123 uint hdrlen; /* Total DHD header length (proto + bus) */
124 uint maxctl; /* Max size rxctl request from proto to bus */
125 uint rxsz; /* Rx buffer size bus module should use */
126 uint8 wme_dp; /* wme discard priority */
127
128 /* Dongle media info */
129 bool iswl; /* Dongle-resident driver is wl */
130 ulong drv_version; /* Version of dongle-resident driver */
131 struct ether_addr mac; /* MAC address obtained from dongle */
132 dngl_stats_t dstats; /* Stats for dongle-based data */
133
134 /* Additional stats for the bus level */
135 ulong tx_packets; /* Data packets sent to dongle */
136 ulong tx_multicast; /* Multicast data packets sent to dongle */
137 ulong tx_errors; /* Errors in sending data to dongle */
138 ulong tx_ctlpkts; /* Control packets sent to dongle */
139 ulong tx_ctlerrs; /* Errors sending control frames to dongle */
140 ulong rx_packets; /* Packets sent up the network interface */
141 ulong rx_multicast; /* Multicast packets sent up the network interface */
142 ulong rx_errors; /* Errors processing rx data packets */
143 ulong rx_ctlpkts; /* Control frames processed from dongle */
144 ulong rx_ctlerrs; /* Errors in processing rx control frames */
145 ulong rx_dropped; /* Packets dropped locally (no memory) */
146 ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */
147 ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */
148
149 ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */
150 ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */
151 ulong fc_packets; /* Number of flow control pkts recvd */
152
153 /* Last error return */
154 int bcmerror;
155 uint tickcnt;
156
157 /* Last error from dongle */
158 int dongle_error;
159
160 /* Suspend disable flag and "in suspend" flag */
161 int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */
162 int in_suspend; /* flag set to 1 when early suspend called */
163 int hang_was_sent; /* flag that message was send at least once */
164#ifdef PNO_SUPPORT
165 int pno_enable; /* pno status : "1" is pno enable */
166#endif /* PNO_SUPPORT */
167 int dtim_skip; /* dtim skip , default 0 means wake each dtim */
168
169 /* Pkt filter defination */
170 char * pktfilter[100];
171 int pktfilter_count;
172
173 wl_country_t dhd_cspec; /* Current Locale info */
174 char eventmask[WL_EVENTING_MASK_LEN];
175
176#ifdef CONFIG_HAS_WAKELOCK
177 struct wake_lock wow_wakelock;
178#endif
179} dhd_pub_t;
180
181#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
182
183 #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
184 #define _DHD_PM_RESUME_WAIT(a, b) do { \
185 int retry = 0; \
186 smp_mb(); \
187 while (dhd_mmc_suspend && retry++ != b) { \
188 wait_event_interruptible_timeout(a, FALSE, 3 * HZ); \
189 } \
190 } while (0)
191 #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200)
192 #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0)
193 #define DHD_PM_RESUME_RETURN_ERROR(a) do { if (dhd_mmc_suspend) return a; } while (0)
194 #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0)
195
196 #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
197 #define SPINWAIT_SLEEP(a, exp, us) do { \
198 uint countdown = (us) + 9999; \
199 while ((exp) && (countdown >= 10000)) { \
200 wait_event_interruptible_timeout(a, FALSE, HZ/100); \
201 countdown -= 10000; \
202 } \
203 } while (0)
204
205#else
206
207 #define DHD_PM_RESUME_WAIT_INIT(a)
208 #define DHD_PM_RESUME_WAIT(a)
209 #define DHD_PM_RESUME_WAIT_FOREVER(a)
210 #define DHD_PM_RESUME_RETURN_ERROR(a)
211 #define DHD_PM_RESUME_RETURN
212
213 #define DHD_SPINWAIT_SLEEP_INIT(a)
214 #define SPINWAIT_SLEEP(a, exp, us) do { \
215 uint countdown = (us) + 9; \
216 while ((exp) && (countdown >= 10)) { \
217 OSL_DELAY(10); \
218 countdown -= 10; \
219 } \
220 } while (0)
221
222#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
223
224#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */
225
226inline static void NETIF_ADDR_LOCK(struct net_device *dev)
227{
228#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
229 netif_addr_lock_bh(dev);
230#endif
231}
232
233inline static void NETIF_ADDR_UNLOCK(struct net_device *dev)
234{
235#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
236 netif_addr_unlock_bh(dev);
237#endif
238}
239
240/* Wakelock Functions */
241extern int dhd_os_wake_lock(dhd_pub_t *pub);
242extern int dhd_os_wake_unlock(dhd_pub_t *pub);
243extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub);
244extern int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub);
245
246extern void dhd_os_start_lock(dhd_pub_t *pub);
247extern void dhd_os_start_unlock(dhd_pub_t *pub);
248extern unsigned long dhd_os_spin_lock(dhd_pub_t *pub);
249extern void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags);
250
251typedef struct dhd_if_event {
252 uint8 ifidx;
253 uint8 action;
254 uint8 flags;
255 uint8 bssidx;
256} dhd_if_event_t;
257
258/*
259 * Exported from dhd OS modules (dhd_linux/dhd_ndis)
260 */
261
262/* To allow osl_attach/detach calls from os-independent modules */
263osl_t *dhd_osl_attach(void *pdev, uint bustype);
264void dhd_osl_detach(osl_t *osh);
265
266/* Indication from bus module regarding presence/insertion of dongle.
267 * Return dhd_pub_t pointer, used as handle to OS module in later calls.
268 * Returned structure should have bus and prot pointers filled in.
269 * bus_hdrlen specifies required headroom for bus module header.
270 */
271extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev);
272extern int dhd_net_attach(dhd_pub_t *dhdp, int idx);
273
274/* Indication from bus module regarding removal/absence of dongle */
275extern void dhd_detach(dhd_pub_t *dhdp);
276
277/* Indication from bus module to change flow-control state */
278extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on);
279
280extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec);
281
282/* Receive frame for delivery to OS. Callee disposes of rxp. */
283extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt);
284
285/* Return pointer to interface name */
286extern char *dhd_ifname(dhd_pub_t *dhdp, int idx);
287
288/* Request scheduling of the bus dpc */
289extern void dhd_sched_dpc(dhd_pub_t *dhdp);
290
291/* Notify tx completion */
292extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success);
293
294/* Query ioctl */
295extern int dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
296
297/* OS independent layer functions */
298extern int dhd_os_proto_block(dhd_pub_t * pub);
299extern int dhd_os_proto_unblock(dhd_pub_t * pub);
300extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending);
301extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub);
302extern unsigned int dhd_os_get_ioctl_resp_timeout(void);
303extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec);
304extern void * dhd_os_open_image(char * filename);
305extern int dhd_os_get_image_block(char * buf, int len, void * image);
306extern void dhd_os_close_image(void * image);
307extern void dhd_os_wd_timer(void *bus, uint wdtick);
308extern void dhd_os_sdlock(dhd_pub_t * pub);
309extern void dhd_os_sdunlock(dhd_pub_t * pub);
310extern void dhd_os_sdlock_txq(dhd_pub_t * pub);
311extern void dhd_os_sdunlock_txq(dhd_pub_t * pub);
312extern void dhd_os_sdlock_rxq(dhd_pub_t * pub);
313extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub);
314extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub);
315extern void dhd_customer_gpio_wlan_ctrl(int onoff);
316extern int dhd_custom_get_mac_address(unsigned char *buf);
317extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub);
318extern void dhd_os_sdlock_eventq(dhd_pub_t * pub);
319extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub);
320#ifdef DHD_DEBUG
321extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size);
322#endif /* DHD_DEBUG */
323#if defined(OOB_INTR_ONLY)
324extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr);
325#endif /* defined(OOB_INTR_ONLY) */
326extern void dhd_os_sdtxlock(dhd_pub_t * pub);
327extern void dhd_os_sdtxunlock(dhd_pub_t * pub);
328
329int setScheduler(struct task_struct *p, int policy, struct sched_param *param);
330
331typedef struct {
332 uint32 limit; /* Expiration time (usec) */
333 uint32 increment; /* Current expiration increment (usec) */
334 uint32 elapsed; /* Current elapsed time (usec) */
335 uint32 tick; /* O/S tick time (usec) */
336} dhd_timeout_t;
337
338extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec);
339extern int dhd_timeout_expired(dhd_timeout_t *tmo);
340
341extern int dhd_ifname2idx(struct dhd_info *dhd, char *name);
342extern uint8 *dhd_bssidx2bssid(dhd_pub_t *dhd, int idx);
343extern int wl_host_event(struct dhd_info *dhd, int *idx, void *pktdata,
344 wl_event_msg_t *, void **data_ptr);
345extern void wl_event_to_host_order(wl_event_msg_t * evt);
346
347extern void dhd_common_init(void);
348
349extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle,
350 char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx);
351extern void dhd_del_if(struct dhd_info *dhd, int ifidx);
352
353extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name);
354extern void dhd_vif_del(struct dhd_info *dhd, int ifidx);
355
356extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx);
357extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len);
358
359
360/* Send packet to dongle via data channel */
361extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt);
362
363/* Send event to host */
364extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data);
365extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag);
366extern uint dhd_bus_status(dhd_pub_t *dhdp);
367extern int dhd_bus_start(dhd_pub_t *dhdp);
368
369extern void print_buf(void *pbuf, int len, int bytes_per_line);
370
371
372typedef enum cust_gpio_modes {
373 WLAN_RESET_ON,
374 WLAN_RESET_OFF,
375 WLAN_POWER_ON,
376 WLAN_POWER_OFF
377} cust_gpio_modes_t;
378
379extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag);
380extern int wl_iw_send_priv_event(struct net_device *dev, char *flag);
381extern int net_os_send_hang_message(struct net_device *dev);
382
383/*
384 * Insmod parameters for debug/test
385 */
386
387/* Watchdog timer interval */
388extern uint dhd_watchdog_ms;
389
390#if defined(DHD_DEBUG)
391/* Console output poll interval */
392extern uint dhd_console_ms;
393#endif /* defined(DHD_DEBUG) */
394
395/* Use interrupts */
396extern uint dhd_intr;
397
398/* Use polling */
399extern uint dhd_poll;
400
401/* ARP offload agent mode */
402extern uint dhd_arp_mode;
403
404/* ARP offload enable */
405extern uint dhd_arp_enable;
406
407/* Pkt filte enable control */
408extern uint dhd_pkt_filter_enable;
409
410/* Pkt filter init setup */
411extern uint dhd_pkt_filter_init;
412
413/* Pkt filter mode control */
414extern uint dhd_master_mode;
415
416/* Roaming mode control */
417extern uint dhd_roam;
418
419/* Roaming mode control */
420extern uint dhd_radio_up;
421
422/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */
423extern int dhd_idletime;
424#define DHD_IDLETIME_TICKS 1
425
426/* SDIO Drive Strength */
427extern uint dhd_sdiod_drive_strength;
428
429/* Override to force tx queueing all the time */
430extern uint dhd_force_tx_queueing;
431
432/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */
433#define KEEP_ALIVE_PERIOD 55000
434#define NULL_PKT_STR "null_pkt"
435
436#ifdef SDTEST
437/* Echo packet generator (SDIO), pkts/s */
438extern uint dhd_pktgen;
439
440/* Echo packet len (0 => sawtooth, max 1800) */
441extern uint dhd_pktgen_len;
442#define MAX_PKTGEN_LEN 1800
443#endif
444
445
446/* optionally set by a module_param_string() */
447#define MOD_PARAM_PATHLEN 2048
448extern char fw_path[MOD_PARAM_PATHLEN];
449extern char nv_path[MOD_PARAM_PATHLEN];
450
451/* For supporting multiple interfaces */
452#define DHD_MAX_IFS 16
453#define DHD_DEL_IF -0xe
454#define DHD_BAD_IF -0xf
455
456
457extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar);
458extern void dhd_wait_event_wakeup(dhd_pub_t*dhd);
459
460/* dhd_commn arp offload wrapers */
461extern void dhd_arp_cleanup(dhd_pub_t *dhd);
462int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen);
463void dhd_arp_offload_add_ip(dhd_pub_t *dhd, u32 ipaddr);
464
465#define DHD_UNICAST_FILTER_NUM 0
466#define DHD_BROADCAST_FILTER_NUM 1
467#define DHD_MULTICAST4_FILTER_NUM 2
468#define DHD_MULTICAST6_FILTER_NUM 3
469extern int net_os_set_packet_filter(struct net_device *dev, int val);
470extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num);
471
472#endif /* _dhd_h_ */
diff --git a/drivers/net/wireless/bcm4329/dhd_bus.h b/drivers/net/wireless/bcm4329/dhd_bus.h
new file mode 100644
index 00000000000..97af41b313d
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/dhd_bus.h
@@ -0,0 +1,93 @@
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-2010, 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.4.6.3.2.3.6.7 2010/08/13 01:35:24 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/* Send a data frame to the dongle. Callee disposes of txp. */
52extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp);
53
54/* Send/receive a control message to/from the dongle.
55 * Expects caller to enforce a single outstanding transaction.
56 */
57extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen);
58extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen);
59
60/* Watchdog timer function */
61extern bool dhd_bus_watchdog(dhd_pub_t *dhd);
62
63#ifdef DHD_DEBUG
64/* Device console input function */
65extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen);
66#endif /* DHD_DEBUG */
67
68/* Deferred processing for the bus, return TRUE requests reschedule */
69extern bool dhd_bus_dpc(struct dhd_bus *bus);
70extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg);
71
72
73/* Check for and handle local prot-specific iovar commands */
74extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
75 void *params, int plen, void *arg, int len, bool set);
76
77/* Add bus dump output to a buffer */
78extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
79
80/* Clear any bus counters */
81extern void dhd_bus_clearcounts(dhd_pub_t *dhdp);
82
83/* return the dongle chipid */
84extern uint dhd_bus_chip(struct dhd_bus *bus);
85
86/* Set user-specified nvram parameters. */
87extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params);
88
89extern void *dhd_bus_pub(struct dhd_bus *bus);
90extern void *dhd_bus_txq(struct dhd_bus *bus);
91extern uint dhd_bus_hdrlen(struct dhd_bus *bus);
92
93#endif /* _dhd_bus_h_ */
diff --git a/drivers/net/wireless/bcm4329/dhd_cdc.c b/drivers/net/wireless/bcm4329/dhd_cdc.c
new file mode 100644
index 00000000000..4bec0b606dc
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/dhd_cdc.c
@@ -0,0 +1,535 @@
1/*
2 * DHD Protocol Module for CDC and BDC.
3 *
4 * Copyright (C) 1999-2010, 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.22.4.2.4.7.2.41 2010/06/23 19:58:18 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
44extern int dhd_preinit_ioctls(dhd_pub_t *dhd);
45
46/* Packet alignment for most efficient SDIO (can change based on platform) */
47#ifndef DHD_SDALIGN
48#define DHD_SDALIGN 32
49#endif
50#if !ISPOWEROF2(DHD_SDALIGN)
51#error DHD_SDALIGN is not a power of 2!
52#endif
53
54#define RETRIES 2 /* # of retries to retrieve matching ioctl response */
55#define BUS_HEADER_LEN (16+DHD_SDALIGN) /* Must be atleast SDPCM_RESERVE
56 * defined in dhd_sdio.c (amount of header tha might be added)
57 * plus any space that might be needed for alignment padding.
58 */
59#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for
60 * round off at the end of buffer
61 */
62
63typedef struct dhd_prot {
64 uint16 reqid;
65 uint8 pending;
66 uint32 lastcmd;
67 uint8 bus_header[BUS_HEADER_LEN];
68 cdc_ioctl_t msg;
69 unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
70} dhd_prot_t;
71
72static int
73dhdcdc_msg(dhd_pub_t *dhd)
74{
75 dhd_prot_t *prot = dhd->prot;
76 int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t);
77 int ret;
78
79 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
80
81 dhd_os_wake_lock(dhd);
82
83 /* NOTE : cdc->msg.len holds the desired length of the buffer to be
84 * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
85 * is actually sent to the dongle
86 */
87 if (len > CDC_MAX_MSG_SIZE)
88 len = CDC_MAX_MSG_SIZE;
89
90 /* Send request */
91 ret = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len);
92 dhd_os_wake_unlock(dhd);
93 return ret;
94}
95
96static int
97dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
98{
99 int ret;
100 dhd_prot_t *prot = dhd->prot;
101
102 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
103
104 do {
105 ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, len+sizeof(cdc_ioctl_t));
106 if (ret < 0)
107 break;
108 } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
109
110 return ret;
111}
112
113int
114dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len)
115{
116 dhd_prot_t *prot = dhd->prot;
117 cdc_ioctl_t *msg = &prot->msg;
118 void *info;
119 int ret = 0, retries = 0;
120 uint32 id, flags = 0;
121
122 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
123 DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
124
125
126 /* Respond "bcmerror" and "bcmerrorstr" with local cache */
127 if (cmd == WLC_GET_VAR && buf)
128 {
129 if (!strcmp((char *)buf, "bcmerrorstr"))
130 {
131 strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN);
132 goto done;
133 }
134 else if (!strcmp((char *)buf, "bcmerror"))
135 {
136 *(int *)buf = dhd->dongle_error;
137 goto done;
138 }
139 }
140
141 memset(msg, 0, sizeof(cdc_ioctl_t));
142
143 msg->cmd = htol32(cmd);
144 msg->len = htol32(len);
145 msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
146 CDC_SET_IF_IDX(msg, ifidx);
147 msg->flags = htol32(msg->flags);
148
149 if (buf)
150 memcpy(prot->buf, buf, len);
151
152 if ((ret = dhdcdc_msg(dhd)) < 0) {
153 if (!dhd->hang_was_sent)
154 DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret));
155 goto done;
156 }
157
158retry:
159 /* wait for interrupt and get first fragment */
160 if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
161 goto done;
162
163 flags = ltoh32(msg->flags);
164 id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
165
166 if ((id < prot->reqid) && (++retries < RETRIES))
167 goto retry;
168 if (id != prot->reqid) {
169 DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
170 dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
171 ret = -EINVAL;
172 goto done;
173 }
174
175 /* Check info buffer */
176 info = (void*)&msg[1];
177
178 /* Copy info buffer */
179 if (buf)
180 {
181 if (ret < (int)len)
182 len = ret;
183 memcpy(buf, info, len);
184 }
185
186 /* Check the ERROR flag */
187 if (flags & CDCF_IOC_ERROR)
188 {
189 ret = ltoh32(msg->status);
190 /* Cache error from dongle */
191 dhd->dongle_error = ret;
192 }
193
194done:
195 return ret;
196}
197
198int
199dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len)
200{
201 dhd_prot_t *prot = dhd->prot;
202 cdc_ioctl_t *msg = &prot->msg;
203 int ret = 0;
204 uint32 flags, id;
205
206 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
207 DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len));
208
209 if (dhd->busstate == DHD_BUS_DOWN) {
210 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
211 return -EIO;
212 }
213
214 /* don't talk to the dongle if fw is about to be reloaded */
215 if (dhd->hang_was_sent) {
216 DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n",
217 __FUNCTION__));
218 return -EIO;
219 }
220
221 memset(msg, 0, sizeof(cdc_ioctl_t));
222
223 msg->cmd = htol32(cmd);
224 msg->len = htol32(len);
225 msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT) | CDCF_IOC_SET;
226 CDC_SET_IF_IDX(msg, ifidx);
227 msg->flags = htol32(msg->flags);
228
229 if (buf)
230 memcpy(prot->buf, buf, len);
231
232 if ((ret = dhdcdc_msg(dhd)) < 0)
233 goto done;
234
235 if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
236 goto done;
237
238 flags = ltoh32(msg->flags);
239 id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
240
241 if (id != prot->reqid) {
242 DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
243 dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid));
244 ret = -EINVAL;
245 goto done;
246 }
247
248 /* Check the ERROR flag */
249 if (flags & CDCF_IOC_ERROR)
250 {
251 ret = ltoh32(msg->status);
252 /* Cache error from dongle */
253 dhd->dongle_error = ret;
254 }
255
256done:
257 return ret;
258}
259
260extern int dhd_bus_interface(struct dhd_bus *bus, uint arg, void* arg2);
261int
262dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len)
263{
264 dhd_prot_t *prot = dhd->prot;
265 int ret = -1;
266
267 if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) {
268 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
269 return ret;
270 }
271 dhd_os_proto_block(dhd);
272
273 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
274
275 ASSERT(len <= WLC_IOCTL_MAXLEN);
276
277 if (len > WLC_IOCTL_MAXLEN)
278 goto done;
279
280 if (prot->pending == TRUE) {
281 DHD_TRACE(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n",
282 ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd,
283 (unsigned long)prot->lastcmd));
284 if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) {
285 DHD_TRACE(("iovar cmd=%s\n", (char*)buf));
286 }
287 goto done;
288 }
289
290 prot->pending = TRUE;
291 prot->lastcmd = ioc->cmd;
292 if (ioc->set)
293 ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len);
294 else {
295 ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len);
296 if (ret > 0)
297 ioc->used = ret - sizeof(cdc_ioctl_t);
298 }
299
300 /* Too many programs assume ioctl() returns 0 on success */
301 if (ret >= 0)
302 ret = 0;
303 else {
304 cdc_ioctl_t *msg = &prot->msg;
305 ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */
306 }
307
308 /* Intercept the wme_dp ioctl here */
309 if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) {
310 int slen, val = 0;
311
312 slen = strlen("wme_dp") + 1;
313 if (len >= (int)(slen + sizeof(int)))
314 bcopy(((char *)buf + slen), &val, sizeof(int));
315 dhd->wme_dp = (uint8) ltoh32(val);
316 }
317
318 prot->pending = FALSE;
319
320done:
321 dhd_os_proto_unblock(dhd);
322
323 return ret;
324}
325
326int
327dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
328 void *params, int plen, void *arg, int len, bool set)
329{
330 return BCME_UNSUPPORTED;
331}
332
333void
334dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
335{
336 bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid);
337}
338
339
340void
341dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf)
342{
343#ifdef BDC
344 struct bdc_header *h;
345#endif /* BDC */
346
347 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
348
349#ifdef BDC
350 /* Push BDC header used to convey priority for buses that don't */
351
352
353 PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN);
354
355 h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);
356
357 h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
358 if (PKTSUMNEEDED(pktbuf))
359 h->flags |= BDC_FLAG_SUM_NEEDED;
360
361
362 h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK);
363 h->flags2 = 0;
364 h->rssi = 0;
365#endif /* BDC */
366 BDC_SET_IF_IDX(h, ifidx);
367}
368
369
370bool
371dhd_proto_fcinfo(dhd_pub_t *dhd, void *pktbuf, uint8 *fcbits)
372{
373#ifdef BDC
374 struct bdc_header *h;
375
376 if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) {
377 DHD_ERROR(("%s: rx data too short (%d < %d)\n",
378 __FUNCTION__, PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN));
379 return BCME_ERROR;
380 }
381
382 h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);
383
384 *fcbits = h->priority >> BDC_PRIORITY_FC_SHIFT;
385 if ((h->flags2 & BDC_FLAG2_FC_FLAG) == BDC_FLAG2_FC_FLAG)
386 return TRUE;
387#endif
388 return FALSE;
389}
390
391
392int
393dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf)
394{
395#ifdef BDC
396 struct bdc_header *h;
397#endif
398
399 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
400
401#ifdef BDC
402 /* Pop BDC header used to convey priority for buses that don't */
403
404 if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) {
405 DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__,
406 PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN));
407 return BCME_ERROR;
408 }
409
410 h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf);
411
412 if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) {
413 DHD_ERROR(("%s: rx data ifnum out of range (%d)\n",
414 __FUNCTION__, *ifidx));
415 return BCME_ERROR;
416 }
417
418 if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) {
419 DHD_ERROR(("%s: non-BDC packet received, flags 0x%x\n",
420 dhd_ifname(dhd, *ifidx), h->flags));
421 return BCME_ERROR;
422 }
423
424 if (h->flags & BDC_FLAG_SUM_GOOD) {
425 DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n",
426 dhd_ifname(dhd, *ifidx), h->flags));
427 PKTSETSUMGOOD(pktbuf, TRUE);
428 }
429
430 PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK));
431
432 PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN);
433#endif /* BDC */
434
435 return 0;
436}
437
438int
439dhd_prot_attach(dhd_pub_t *dhd)
440{
441 dhd_prot_t *cdc;
442
443#ifndef DHD_USE_STATIC_BUF
444 if (!(cdc = (dhd_prot_t *)MALLOC(dhd->osh, sizeof(dhd_prot_t)))) {
445 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
446 goto fail;
447 }
448#else
449 if (!(cdc = (dhd_prot_t *)dhd_os_prealloc(DHD_PREALLOC_PROT, sizeof(dhd_prot_t)))) {
450 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
451 goto fail;
452 }
453#endif /* DHD_USE_STATIC_BUF */
454 memset(cdc, 0, sizeof(dhd_prot_t));
455
456 /* ensure that the msg buf directly follows the cdc msg struct */
457 if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) {
458 DHD_ERROR(("dhd_prot_t is not correctly defined\n"));
459 goto fail;
460 }
461
462 dhd->prot = cdc;
463#ifdef BDC
464 dhd->hdrlen += BDC_HEADER_LEN;
465#endif
466 dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN;
467 return 0;
468
469fail:
470#ifndef DHD_USE_STATIC_BUF
471 if (cdc != NULL)
472 MFREE(dhd->osh, cdc, sizeof(dhd_prot_t));
473#endif
474 return BCME_NOMEM;
475}
476
477/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */
478void
479dhd_prot_detach(dhd_pub_t *dhd)
480{
481#ifndef DHD_USE_STATIC_BUF
482 MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t));
483#endif
484 dhd->prot = NULL;
485}
486
487void
488dhd_prot_dstats(dhd_pub_t *dhd)
489{
490 /* No stats from dongle added yet, copy bus stats */
491 dhd->dstats.tx_packets = dhd->tx_packets;
492 dhd->dstats.tx_errors = dhd->tx_errors;
493 dhd->dstats.rx_packets = dhd->rx_packets;
494 dhd->dstats.rx_errors = dhd->rx_errors;
495 dhd->dstats.rx_dropped = dhd->rx_dropped;
496 dhd->dstats.multicast = dhd->rx_multicast;
497 return;
498}
499
500int
501dhd_prot_init(dhd_pub_t *dhd)
502{
503 int ret = 0;
504 char buf[128];
505
506 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
507
508 dhd_os_proto_block(dhd);
509
510 /* Get the device MAC address */
511 strcpy(buf, "cur_etheraddr");
512 ret = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf));
513 if (ret < 0) {
514 dhd_os_proto_unblock(dhd);
515 return ret;
516 }
517 memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
518
519 dhd_os_proto_unblock(dhd);
520
521#ifdef EMBEDDED_PLATFORM
522 ret = dhd_preinit_ioctls(dhd);
523#endif /* EMBEDDED_PLATFORM */
524
525 /* Always assumes wl for now */
526 dhd->iswl = TRUE;
527
528 return ret;
529}
530
531void
532dhd_prot_stop(dhd_pub_t *dhd)
533{
534 /* Nothing to do for CDC */
535}
diff --git a/drivers/net/wireless/bcm4329/dhd_common.c b/drivers/net/wireless/bcm4329/dhd_common.c
new file mode 100644
index 00000000000..f7cd372d68c
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/dhd_common.c
@@ -0,0 +1,2432 @@
1/*
2 * Broadcom Dongle Host Driver (DHD), common DHD core.
3 *
4 * Copyright (C) 1999-2010, 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,v 1.5.6.8.2.6.6.69.4.25 2011-02-11 21:16:02 Exp $
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 <dhd.h>
35#include <dhd_bus.h>
36#include <dhd_proto.h>
37#include <dhd_dbg.h>
38#include <msgtrace.h>
39
40#include <wlioctl.h>
41
42#ifdef SET_RANDOM_MAC_SOFTAP
43#include <linux/random.h>
44#include <linux/jiffies.h>
45#endif
46
47#ifdef GET_CUSTOM_MAC_ENABLE
48int wifi_get_mac_addr(unsigned char *buf);
49#endif /* GET_CUSTOM_MAC_ENABLE */
50
51int dhd_msg_level;
52
53#include <wl_iw.h>
54
55char fw_path[MOD_PARAM_PATHLEN];
56char nv_path[MOD_PARAM_PATHLEN];
57
58/* Last connection success/failure status */
59uint32 dhd_conn_event;
60uint32 dhd_conn_status;
61uint32 dhd_conn_reason;
62
63#define htod32(i) i
64#define htod16(i) i
65#define dtoh32(i) i
66#define dtoh16(i) i
67
68extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
69extern void dhd_ind_scan_confirm(void *h, bool status);
70extern int dhd_wl_ioctl(dhd_pub_t *dhd, uint cmd, char *buf, uint buflen);
71void dhd_iscan_lock(void);
72void dhd_iscan_unlock(void);
73
74#if defined(SOFTAP)
75extern bool ap_fw_loaded;
76#endif
77#if defined(KEEP_ALIVE)
78int dhd_keep_alive_onoff(dhd_pub_t *dhd, int ka_on);
79#endif /* KEEP_ALIVE */
80
81/* Packet alignment for most efficient SDIO (can change based on platform) */
82#ifndef DHD_SDALIGN
83#define DHD_SDALIGN 32
84#endif
85#if !ISPOWEROF2(DHD_SDALIGN)
86#error DHD_SDALIGN is not a power of 2!
87#endif
88
89#ifdef DHD_DEBUG
90const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on "
91 __DATE__ " at " __TIME__;
92#else
93const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR;
94#endif
95
96void dhd_set_timer(void *bus, uint wdtick);
97
98/* IOVar table */
99enum {
100 IOV_VERSION = 1,
101 IOV_MSGLEVEL,
102 IOV_BCMERRORSTR,
103 IOV_BCMERROR,
104 IOV_WDTICK,
105 IOV_DUMP,
106#ifdef DHD_DEBUG
107 IOV_CONS,
108 IOV_DCONSOLE_POLL,
109#endif
110 IOV_CLEARCOUNTS,
111 IOV_LOGDUMP,
112 IOV_LOGCAL,
113 IOV_LOGSTAMP,
114 IOV_GPIOOB,
115 IOV_IOCTLTIMEOUT,
116 IOV_LAST
117};
118
119const bcm_iovar_t dhd_iovars[] = {
120 {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) },
121#ifdef DHD_DEBUG
122 {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
123#endif /* DHD_DEBUG */
124 {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN },
125 {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 },
126 {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 },
127 {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
128#ifdef DHD_DEBUG
129 {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 },
130 {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 },
131#endif
132 {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 },
133 {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 },
134 {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 },
135 {NULL, 0, 0, 0, 0 }
136};
137
138void
139dhd_common_init(void)
140{
141 /* Init global variables at run-time, not as part of the declaration.
142 * This is required to support init/de-init of the driver. Initialization
143 * of globals as part of the declaration results in non-deterministic
144 * behaviour since the value of the globals may be different on the
145 * first time that the driver is initialized vs subsequent initializations.
146 */
147 dhd_msg_level = DHD_ERROR_VAL;
148#ifdef CONFIG_BCM4329_FW_PATH
149 strncpy(fw_path, CONFIG_BCM4329_FW_PATH, MOD_PARAM_PATHLEN-1);
150#else
151 fw_path[0] = '\0';
152#endif
153#ifdef CONFIG_BCM4329_NVRAM_PATH
154 strncpy(nv_path, CONFIG_BCM4329_NVRAM_PATH, MOD_PARAM_PATHLEN-1);
155#else
156 nv_path[0] = '\0';
157#endif
158}
159
160static int
161dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
162{
163 char eabuf[ETHER_ADDR_STR_LEN];
164
165 struct bcmstrbuf b;
166 struct bcmstrbuf *strbuf = &b;
167
168 bcm_binit(strbuf, buf, buflen);
169
170 /* Base DHD info */
171 bcm_bprintf(strbuf, "%s\n", dhd_version);
172 bcm_bprintf(strbuf, "\n");
173 bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
174 dhdp->up, dhdp->txoff, dhdp->busstate);
175 bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n",
176 dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz);
177 bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n",
178 dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf));
179 bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror, dhdp->tickcnt);
180
181 bcm_bprintf(strbuf, "dongle stats:\n");
182 bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n",
183 dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes,
184 dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped);
185 bcm_bprintf(strbuf, "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n",
186 dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes,
187 dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped);
188 bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast);
189
190 bcm_bprintf(strbuf, "bus stats:\n");
191 bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n",
192 dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors);
193 bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n",
194 dhdp->tx_ctlpkts, dhdp->tx_ctlerrs);
195 bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n",
196 dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors);
197 bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld rx_flushed %ld\n",
198 dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped, dhdp->rx_flushed);
199 bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld fc_packets %ld\n",
200 dhdp->rx_readahead_cnt, dhdp->tx_realloc, dhdp->fc_packets);
201 bcm_bprintf(strbuf, "wd_dpc_sched %ld\n", dhdp->wd_dpc_sched);
202 bcm_bprintf(strbuf, "\n");
203
204 /* Add any prot info */
205 dhd_prot_dump(dhdp, strbuf);
206 bcm_bprintf(strbuf, "\n");
207
208 /* Add any bus info */
209 dhd_bus_dump(dhdp, strbuf);
210
211 return (!strbuf->size ? BCME_BUFTOOSHORT : 0);
212}
213
214static int
215dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name,
216 void *params, int plen, void *arg, int len, int val_size)
217{
218 int bcmerror = 0;
219 int32 int_val = 0;
220
221 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
222
223 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
224 goto exit;
225
226 if (plen >= (int)sizeof(int_val))
227 bcopy(params, &int_val, sizeof(int_val));
228
229 switch (actionid) {
230 case IOV_GVAL(IOV_VERSION):
231 /* Need to have checked buffer length */
232 strncpy((char*)arg, dhd_version, len);
233 break;
234
235 case IOV_GVAL(IOV_MSGLEVEL):
236 int_val = (int32)dhd_msg_level;
237 bcopy(&int_val, arg, val_size);
238 break;
239
240 case IOV_SVAL(IOV_MSGLEVEL):
241 dhd_msg_level = int_val;
242 break;
243
244 case IOV_GVAL(IOV_BCMERRORSTR):
245 strncpy((char *)arg, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN);
246 ((char *)arg)[BCME_STRLEN - 1] = 0x00;
247 break;
248
249 case IOV_GVAL(IOV_BCMERROR):
250 int_val = (int32)dhd_pub->bcmerror;
251 bcopy(&int_val, arg, val_size);
252 break;
253
254 case IOV_GVAL(IOV_WDTICK):
255 int_val = (int32)dhd_watchdog_ms;
256 bcopy(&int_val, arg, val_size);
257 break;
258
259 case IOV_SVAL(IOV_WDTICK):
260 if (!dhd_pub->up) {
261 bcmerror = BCME_NOTUP;
262 break;
263 }
264 dhd_os_wd_timer(dhd_pub, (uint)int_val);
265 break;
266
267 case IOV_GVAL(IOV_DUMP):
268 bcmerror = dhd_dump(dhd_pub, arg, len);
269 break;
270
271#ifdef DHD_DEBUG
272 case IOV_GVAL(IOV_DCONSOLE_POLL):
273 int_val = (int32)dhd_console_ms;
274 bcopy(&int_val, arg, val_size);
275 break;
276
277 case IOV_SVAL(IOV_DCONSOLE_POLL):
278 dhd_console_ms = (uint)int_val;
279 break;
280
281 case IOV_SVAL(IOV_CONS):
282 if (len > 0)
283 bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
284 break;
285#endif
286
287 case IOV_SVAL(IOV_CLEARCOUNTS):
288 dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
289 dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
290 dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
291 dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
292 dhd_pub->rx_dropped = 0;
293 dhd_pub->rx_readahead_cnt = 0;
294 dhd_pub->tx_realloc = 0;
295 dhd_pub->wd_dpc_sched = 0;
296 memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats));
297 dhd_bus_clearcounts(dhd_pub);
298 break;
299
300
301 case IOV_GVAL(IOV_IOCTLTIMEOUT): {
302 int_val = (int32)dhd_os_get_ioctl_resp_timeout();
303 bcopy(&int_val, arg, sizeof(int_val));
304 break;
305 }
306
307 case IOV_SVAL(IOV_IOCTLTIMEOUT): {
308 if (int_val <= 0)
309 bcmerror = BCME_BADARG;
310 else
311 dhd_os_set_ioctl_resp_timeout((unsigned int)int_val);
312 break;
313 }
314
315
316 default:
317 bcmerror = BCME_UNSUPPORTED;
318 break;
319 }
320
321exit:
322 return bcmerror;
323}
324
325/* Store the status of a connection attempt for later retrieval by an iovar */
326void
327dhd_store_conn_status(uint32 event, uint32 status, uint32 reason)
328{
329 /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID
330 * because an encryption/rsn mismatch results in both events, and
331 * the important information is in the WLC_E_PRUNE.
332 */
333 if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL &&
334 dhd_conn_event == WLC_E_PRUNE)) {
335 dhd_conn_event = event;
336 dhd_conn_status = status;
337 dhd_conn_reason = reason;
338 }
339}
340
341bool
342dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
343{
344 void *p;
345 int eprec = -1; /* precedence to evict from */
346 bool discard_oldest;
347
348 /* Fast case, precedence queue is not full and we are also not
349 * exceeding total queue length
350 */
351 if (!pktq_pfull(q, prec) && !pktq_full(q)) {
352 pktq_penq(q, prec, pkt);
353 return TRUE;
354 }
355
356 /* Determine precedence from which to evict packet, if any */
357 if (pktq_pfull(q, prec))
358 eprec = prec;
359 else if (pktq_full(q)) {
360 p = pktq_peek_tail(q, &eprec);
361 ASSERT(p);
362 if (eprec > prec)
363 return FALSE;
364 }
365
366 /* Evict if needed */
367 if (eprec >= 0) {
368 /* Detect queueing to unconfigured precedence */
369 ASSERT(!pktq_pempty(q, eprec));
370 discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec);
371 if (eprec == prec && !discard_oldest)
372 return FALSE; /* refuse newer (incoming) packet */
373 /* Evict packet according to discard policy */
374 p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec);
375 if (p == NULL) {
376 DHD_ERROR(("%s: pktq_penq() failed, oldest %d.",
377 __FUNCTION__, discard_oldest));
378 ASSERT(p);
379 }
380
381 PKTFREE(dhdp->osh, p, TRUE);
382 }
383
384 /* Enqueue */
385 p = pktq_penq(q, prec, pkt);
386 if (p == NULL) {
387 DHD_ERROR(("%s: pktq_penq() failed.", __FUNCTION__));
388 ASSERT(p);
389 }
390
391 return TRUE;
392}
393
394static int
395dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name,
396 void *params, int plen, void *arg, int len, bool set)
397{
398 int bcmerror = 0;
399 int val_size;
400 const bcm_iovar_t *vi = NULL;
401 uint32 actionid;
402
403 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
404
405 ASSERT(name);
406 ASSERT(len >= 0);
407
408 /* Get MUST have return space */
409 ASSERT(set || (arg && len));
410
411 /* Set does NOT take qualifiers */
412 ASSERT(!set || (!params && !plen));
413
414 if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) {
415 bcmerror = BCME_UNSUPPORTED;
416 goto exit;
417 }
418
419 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
420 name, (set ? "set" : "get"), len, plen));
421
422 /* set up 'params' pointer in case this is a set command so that
423 * the convenience int and bool code can be common to set and get
424 */
425 if (params == NULL) {
426 params = arg;
427 plen = len;
428 }
429
430 if (vi->type == IOVT_VOID)
431 val_size = 0;
432 else if (vi->type == IOVT_BUFFER)
433 val_size = len;
434 else
435 /* all other types are integer sized */
436 val_size = sizeof(int);
437
438 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
439 bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size);
440
441exit:
442 return bcmerror;
443}
444
445int
446dhd_ioctl(dhd_pub_t *dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen)
447{
448 int bcmerror = 0;
449
450 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
451
452 if (!buf) return BCME_BADARG;
453
454 switch (ioc->cmd) {
455 case DHD_GET_MAGIC:
456 if (buflen < sizeof(int))
457 bcmerror = BCME_BUFTOOSHORT;
458 else
459 *(int*)buf = DHD_IOCTL_MAGIC;
460 break;
461
462 case DHD_GET_VERSION:
463 if (buflen < sizeof(int))
464 bcmerror = -BCME_BUFTOOSHORT;
465 else
466 *(int*)buf = DHD_IOCTL_VERSION;
467 break;
468
469 case DHD_GET_VAR:
470 case DHD_SET_VAR: {
471 char *arg;
472 uint arglen;
473
474 /* scan past the name to any arguments */
475 for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--);
476
477 if (*arg) {
478 bcmerror = BCME_BUFTOOSHORT;
479 break;
480 }
481
482 /* account for the NUL terminator */
483 arg++, arglen--;
484
485 /* call with the appropriate arguments */
486 if (ioc->cmd == DHD_GET_VAR)
487 bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen,
488 buf, buflen, IOV_GET);
489 else
490 bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET);
491 if (bcmerror != BCME_UNSUPPORTED)
492 break;
493
494 /* not in generic table, try protocol module */
495 if (ioc->cmd == DHD_GET_VAR)
496 bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg,
497 arglen, buf, buflen, IOV_GET);
498 else
499 bcmerror = dhd_prot_iovar_op(dhd_pub, buf,
500 NULL, 0, arg, arglen, IOV_SET);
501 if (bcmerror != BCME_UNSUPPORTED)
502 break;
503
504 /* if still not found, try bus module */
505 if (ioc->cmd == DHD_GET_VAR)
506 bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
507 arg, arglen, buf, buflen, IOV_GET);
508 else
509 bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
510 NULL, 0, arg, arglen, IOV_SET);
511
512 break;
513 }
514
515 default:
516 bcmerror = BCME_UNSUPPORTED;
517 }
518
519 return bcmerror;
520}
521
522
523#ifdef SHOW_EVENTS
524static void
525wl_show_host_event(wl_event_msg_t *event, void *event_data)
526{
527 uint i, status, reason;
528 bool group = FALSE, flush_txq = FALSE, link = FALSE;
529 char *auth_str, *event_name;
530 uchar *buf;
531 char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
532 static struct {uint event; char *event_name;} event_names[] = {
533 {WLC_E_SET_SSID, "SET_SSID"},
534 {WLC_E_JOIN, "JOIN"},
535 {WLC_E_START, "START"},
536 {WLC_E_AUTH, "AUTH"},
537 {WLC_E_AUTH_IND, "AUTH_IND"},
538 {WLC_E_DEAUTH, "DEAUTH"},
539 {WLC_E_DEAUTH_IND, "DEAUTH_IND"},
540 {WLC_E_ASSOC, "ASSOC"},
541 {WLC_E_ASSOC_IND, "ASSOC_IND"},
542 {WLC_E_REASSOC, "REASSOC"},
543 {WLC_E_REASSOC_IND, "REASSOC_IND"},
544 {WLC_E_DISASSOC, "DISASSOC"},
545 {WLC_E_DISASSOC_IND, "DISASSOC_IND"},
546 {WLC_E_QUIET_START, "START_QUIET"},
547 {WLC_E_QUIET_END, "END_QUIET"},
548 {WLC_E_BEACON_RX, "BEACON_RX"},
549 {WLC_E_LINK, "LINK"},
550 {WLC_E_MIC_ERROR, "MIC_ERROR"},
551 {WLC_E_NDIS_LINK, "NDIS_LINK"},
552 {WLC_E_ROAM, "ROAM"},
553 {WLC_E_TXFAIL, "TXFAIL"},
554 {WLC_E_PMKID_CACHE, "PMKID_CACHE"},
555 {WLC_E_RETROGRADE_TSF, "RETROGRADE_TSF"},
556 {WLC_E_PRUNE, "PRUNE"},
557 {WLC_E_AUTOAUTH, "AUTOAUTH"},
558 {WLC_E_EAPOL_MSG, "EAPOL_MSG"},
559 {WLC_E_SCAN_COMPLETE, "SCAN_COMPLETE"},
560 {WLC_E_ADDTS_IND, "ADDTS_IND"},
561 {WLC_E_DELTS_IND, "DELTS_IND"},
562 {WLC_E_BCNSENT_IND, "BCNSENT_IND"},
563 {WLC_E_BCNRX_MSG, "BCNRX_MSG"},
564 {WLC_E_BCNLOST_MSG, "BCNLOST_MSG"},
565 {WLC_E_ROAM_PREP, "ROAM_PREP"},
566 {WLC_E_PFN_NET_FOUND, "PNO_NET_FOUND"},
567 {WLC_E_PFN_NET_LOST, "PNO_NET_LOST"},
568 {WLC_E_RESET_COMPLETE, "RESET_COMPLETE"},
569 {WLC_E_JOIN_START, "JOIN_START"},
570 {WLC_E_ROAM_START, "ROAM_START"},
571 {WLC_E_ASSOC_START, "ASSOC_START"},
572 {WLC_E_IBSS_ASSOC, "IBSS_ASSOC"},
573 {WLC_E_RADIO, "RADIO"},
574 {WLC_E_PSM_WATCHDOG, "PSM_WATCHDOG"},
575 {WLC_E_PROBREQ_MSG, "PROBREQ_MSG"},
576 {WLC_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"},
577 {WLC_E_PSK_SUP, "PSK_SUP"},
578 {WLC_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"},
579 {WLC_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"},
580 {WLC_E_ICV_ERROR, "ICV_ERROR"},
581 {WLC_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"},
582 {WLC_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"},
583 {WLC_E_TRACE, "TRACE"},
584 {WLC_E_ACTION_FRAME, "ACTION FRAME"},
585 {WLC_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"},
586 {WLC_E_IF, "IF"},
587 {WLC_E_RSSI, "RSSI"},
588 {WLC_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}
589 };
590 uint event_type, flags, auth_type, datalen;
591 event_type = ntoh32(event->event_type);
592 flags = ntoh16(event->flags);
593 status = ntoh32(event->status);
594 reason = ntoh32(event->reason);
595 auth_type = ntoh32(event->auth_type);
596 datalen = ntoh32(event->datalen);
597 /* debug dump of event messages */
598 sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x",
599 (uchar)event->addr.octet[0]&0xff,
600 (uchar)event->addr.octet[1]&0xff,
601 (uchar)event->addr.octet[2]&0xff,
602 (uchar)event->addr.octet[3]&0xff,
603 (uchar)event->addr.octet[4]&0xff,
604 (uchar)event->addr.octet[5]&0xff);
605
606 event_name = "UNKNOWN";
607 for (i = 0; i < ARRAYSIZE(event_names); i++) {
608 if (event_names[i].event == event_type)
609 event_name = event_names[i].event_name;
610 }
611
612 DHD_EVENT(("EVENT: %s, event ID = %d\n", event_name, event_type));
613
614 if (flags & WLC_EVENT_MSG_LINK)
615 link = TRUE;
616 if (flags & WLC_EVENT_MSG_GROUP)
617 group = TRUE;
618 if (flags & WLC_EVENT_MSG_FLUSHTXQ)
619 flush_txq = TRUE;
620
621 switch (event_type) {
622 case WLC_E_START:
623 case WLC_E_DEAUTH:
624 case WLC_E_DISASSOC:
625 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
626 break;
627
628 case WLC_E_ASSOC_IND:
629 case WLC_E_REASSOC_IND:
630 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
631 break;
632
633 case WLC_E_ASSOC:
634 case WLC_E_REASSOC:
635 if (status == WLC_E_STATUS_SUCCESS) {
636 DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf));
637 } else if (status == WLC_E_STATUS_TIMEOUT) {
638 DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf));
639 } else if (status == WLC_E_STATUS_FAIL) {
640 DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
641 event_name, eabuf, (int)reason));
642 } else {
643 DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n",
644 event_name, eabuf, (int)status));
645 }
646 break;
647
648 case WLC_E_DEAUTH_IND:
649 case WLC_E_DISASSOC_IND:
650 DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason));
651 break;
652
653 case WLC_E_AUTH:
654 case WLC_E_AUTH_IND:
655 if (auth_type == DOT11_OPEN_SYSTEM)
656 auth_str = "Open System";
657 else if (auth_type == DOT11_SHARED_KEY)
658 auth_str = "Shared Key";
659 else {
660 sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
661 auth_str = err_msg;
662 }
663 if (event_type == WLC_E_AUTH_IND) {
664 DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str));
665 } else if (status == WLC_E_STATUS_SUCCESS) {
666 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
667 event_name, eabuf, auth_str));
668 } else if (status == WLC_E_STATUS_TIMEOUT) {
669 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
670 event_name, eabuf, auth_str));
671 } else if (status == WLC_E_STATUS_FAIL) {
672 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
673 event_name, eabuf, auth_str, (int)reason));
674 }
675
676 break;
677
678 case WLC_E_JOIN:
679 case WLC_E_ROAM:
680 case WLC_E_SET_SSID:
681 if (status == WLC_E_STATUS_SUCCESS) {
682 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
683 } else if (status == WLC_E_STATUS_FAIL) {
684 DHD_EVENT(("MACEVENT: %s, failed\n", event_name));
685 } else if (status == WLC_E_STATUS_NO_NETWORKS) {
686 DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name));
687 } else {
688 DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
689 event_name, (int)status));
690 }
691 break;
692
693 case WLC_E_BEACON_RX:
694 if (status == WLC_E_STATUS_SUCCESS) {
695 DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
696 } else if (status == WLC_E_STATUS_FAIL) {
697 DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
698 } else {
699 DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status));
700 }
701 break;
702
703 case WLC_E_LINK:
704 DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN"));
705 break;
706
707 case WLC_E_MIC_ERROR:
708 DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
709 event_name, eabuf, group, flush_txq));
710 break;
711
712 case WLC_E_ICV_ERROR:
713 case WLC_E_UNICAST_DECODE_ERROR:
714 case WLC_E_MULTICAST_DECODE_ERROR:
715 DHD_EVENT(("MACEVENT: %s, MAC %s\n",
716 event_name, eabuf));
717 break;
718
719 case WLC_E_TXFAIL:
720 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf));
721 break;
722
723 case WLC_E_SCAN_COMPLETE:
724 case WLC_E_PMKID_CACHE:
725 DHD_EVENT(("MACEVENT: %s\n", event_name));
726 break;
727
728 case WLC_E_PFN_NET_FOUND:
729 case WLC_E_PFN_NET_LOST:
730 case WLC_E_PFN_SCAN_COMPLETE:
731 DHD_EVENT(("PNOEVENT: %s\n", event_name));
732 break;
733
734 case WLC_E_PSK_SUP:
735 case WLC_E_PRUNE:
736 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
737 event_name, (int)status, (int)reason));
738 break;
739
740 case WLC_E_TRACE:
741 {
742 static uint32 seqnum_prev = 0;
743 msgtrace_hdr_t hdr;
744 uint32 nblost;
745 char *s, *p;
746
747 buf = (uchar *) event_data;
748 memcpy(&hdr, buf, MSGTRACE_HDRLEN);
749
750 if (hdr.version != MSGTRACE_VERSION) {
751 printf("\nMACEVENT: %s [unsupported version --> "
752 "dhd version:%d dongle version:%d]\n",
753 event_name, MSGTRACE_VERSION, hdr.version);
754 /* Reset datalen to avoid display below */
755 datalen = 0;
756 break;
757 }
758
759 /* There are 2 bytes available at the end of data */
760 buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0';
761
762 if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) {
763 printf("\nWLC_E_TRACE: [Discarded traces in dongle -->"
764 "discarded_bytes %d discarded_printf %d]\n",
765 ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf));
766 }
767
768 nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1;
769 if (nblost > 0) {
770 printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n",
771 ntoh32(hdr.seqnum), nblost);
772 }
773 seqnum_prev = ntoh32(hdr.seqnum);
774
775 /* Display the trace buffer. Advance from \n to \n to avoid display big
776 * printf (issue with Linux printk )
777 */
778 p = (char *)&buf[MSGTRACE_HDRLEN];
779 while ((s = strstr(p, "\n")) != NULL) {
780 *s = '\0';
781 printf("%s\n", p);
782 p = s + 1;
783 }
784 printf("%s\n", p);
785
786 /* Reset datalen to avoid display below */
787 datalen = 0;
788 }
789 break;
790
791
792 case WLC_E_RSSI:
793 DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))));
794 break;
795
796 default:
797 DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
798 event_name, event_type, eabuf, (int)status, (int)reason,
799 (int)auth_type));
800 break;
801 }
802
803 /* show any appended data */
804 if (datalen) {
805 buf = (uchar *) event_data;
806 DHD_EVENT((" data (%d) : ", datalen));
807 for (i = 0; i < datalen; i++)
808 DHD_EVENT((" 0x%02x ", *buf++));
809 DHD_EVENT(("\n"));
810 }
811}
812#endif /* SHOW_EVENTS */
813
814int
815wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata,
816 wl_event_msg_t *event, void **data_ptr)
817{
818 /* check whether packet is a BRCM event pkt */
819 bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
820 char *event_data;
821 uint32 type, status;
822 uint16 flags;
823 int evlen;
824
825 if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
826 DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__));
827 return (BCME_ERROR);
828 }
829
830 /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
831 if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) {
832 DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__));
833 return (BCME_ERROR);
834 }
835
836 *data_ptr = &pvt_data[1];
837 event_data = *data_ptr;
838
839 /* memcpy since BRCM event pkt may be unaligned. */
840 memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
841
842 type = ntoh32_ua((void *)&event->event_type);
843 flags = ntoh16_ua((void *)&event->flags);
844 status = ntoh32_ua((void *)&event->status);
845 evlen = ntoh32_ua((void *)&event->datalen) + sizeof(bcm_event_t);
846
847 switch (type) {
848 case WLC_E_IF:
849 {
850 dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data;
851 DHD_TRACE(("%s: if event\n", __FUNCTION__));
852
853 if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS)
854 {
855 if (ifevent->action == WLC_E_IF_ADD)
856 dhd_add_if(dhd, ifevent->ifidx,
857 NULL, event->ifname,
858 pvt_data->eth.ether_dhost,
859 ifevent->flags, ifevent->bssidx);
860 else
861 dhd_del_if(dhd, ifevent->ifidx);
862 } else {
863 DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
864 __FUNCTION__, ifevent->ifidx, event->ifname));
865 }
866 }
867 /* send up the if event: btamp user needs it */
868 *ifidx = dhd_ifname2idx(dhd, event->ifname);
869 /* push up to external supp/auth */
870 dhd_event(dhd, (char *)pvt_data, evlen, *ifidx);
871 break;
872
873
874#ifdef P2P
875 case WLC_E_NDIS_LINK:
876 break;
877#endif
878 /* fall through */
879 /* These are what external supplicant/authenticator wants */
880 case WLC_E_LINK:
881 case WLC_E_ASSOC_IND:
882 case WLC_E_REASSOC_IND:
883 case WLC_E_DISASSOC_IND:
884 case WLC_E_MIC_ERROR:
885 default:
886 /* Fall through: this should get _everything_ */
887
888 *ifidx = dhd_ifname2idx(dhd, event->ifname);
889 /* push up to external supp/auth */
890 dhd_event(dhd, (char *)pvt_data, evlen, *ifidx);
891 DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
892 __FUNCTION__, type, flags, status));
893
894 /* put it back to WLC_E_NDIS_LINK */
895 if (type == WLC_E_NDIS_LINK) {
896 uint32 temp;
897
898 temp = ntoh32_ua((void *)&event->event_type);
899 DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp));
900
901 temp = ntoh32(WLC_E_NDIS_LINK);
902 memcpy((void *)(&pvt_data->event.event_type), &temp,
903 sizeof(pvt_data->event.event_type));
904 }
905 break;
906 }
907
908#ifdef SHOW_EVENTS
909 wl_show_host_event(event, event_data);
910#endif /* SHOW_EVENTS */
911
912 return (BCME_OK);
913}
914
915
916void
917wl_event_to_host_order(wl_event_msg_t *evt)
918{
919 /* Event struct members passed from dongle to host are stored in network
920 * byte order. Convert all members to host-order.
921 */
922 evt->event_type = ntoh32(evt->event_type);
923 evt->flags = ntoh16(evt->flags);
924 evt->status = ntoh32(evt->status);
925 evt->reason = ntoh32(evt->reason);
926 evt->auth_type = ntoh32(evt->auth_type);
927 evt->datalen = ntoh32(evt->datalen);
928 evt->version = ntoh16(evt->version);
929}
930
931void print_buf(void *pbuf, int len, int bytes_per_line)
932{
933 int i, j = 0;
934 unsigned char *buf = pbuf;
935
936 if (bytes_per_line == 0) {
937 bytes_per_line = len;
938 }
939
940 for (i = 0; i < len; i++) {
941 printf("%2.2x", *buf++);
942 j++;
943 if (j == bytes_per_line) {
944 printf("\n");
945 j = 0;
946 } else {
947 printf(":");
948 }
949 }
950 printf("\n");
951}
952
953#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
954
955#ifdef PKT_FILTER_SUPPORT
956/* Convert user's input in hex pattern to byte-size mask */
957static int
958wl_pattern_atoh(char *src, char *dst)
959{
960 int i;
961 if (strncmp(src, "0x", 2) != 0 &&
962 strncmp(src, "0X", 2) != 0) {
963 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
964 return -1;
965 }
966 src = src + 2; /* Skip past 0x */
967 if (strlen(src) % 2 != 0) {
968 DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
969 return -1;
970 }
971 for (i = 0; *src != '\0'; i++) {
972 char num[3];
973 strncpy(num, src, 2);
974 num[2] = '\0';
975 dst[i] = (uint8)strtoul(num, NULL, 16);
976 src += 2;
977 }
978 return i;
979}
980
981void
982dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode)
983{
984 char *argv[8];
985 int i = 0;
986 const char *str;
987 int buf_len;
988 int str_len;
989 char *arg_save = 0, *arg_org = 0;
990 int rc;
991 char buf[128];
992 wl_pkt_filter_enable_t enable_parm;
993 wl_pkt_filter_enable_t * pkt_filterp;
994
995 if (!arg)
996 return;
997
998 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
999 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1000 goto fail;
1001 }
1002 arg_org = arg_save;
1003 memcpy(arg_save, arg, strlen(arg) + 1);
1004
1005 argv[i] = bcmstrtok(&arg_save, " ", 0);
1006
1007 i = 0;
1008 if (NULL == argv[i]) {
1009 DHD_ERROR(("No args provided\n"));
1010 goto fail;
1011 }
1012
1013 str = "pkt_filter_enable";
1014 str_len = strlen(str);
1015 strncpy(buf, str, str_len);
1016 buf[str_len] = '\0';
1017 buf_len = str_len + 1;
1018
1019 pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1);
1020
1021 /* Parse packet filter id. */
1022 enable_parm.id = htod32(strtoul(argv[i], NULL, 0));
1023
1024 /* Parse enable/disable value. */
1025 enable_parm.enable = htod32(enable);
1026
1027 buf_len += sizeof(enable_parm);
1028 memcpy((char *)pkt_filterp,
1029 &enable_parm,
1030 sizeof(enable_parm));
1031
1032 /* Enable/disable the specified filter. */
1033 rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
1034 rc = rc >= 0 ? 0 : rc;
1035 if (rc)
1036 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1037 __FUNCTION__, arg, rc));
1038 else
1039 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1040 __FUNCTION__, arg));
1041
1042 /* Contorl the master mode */
1043 bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf));
1044 rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
1045 rc = rc >= 0 ? 0 : rc;
1046 if (rc)
1047 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1048 __FUNCTION__, arg, rc));
1049
1050fail:
1051 if (arg_org)
1052 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
1053}
1054
1055void
1056dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg)
1057{
1058 const char *str;
1059 wl_pkt_filter_t pkt_filter;
1060 wl_pkt_filter_t *pkt_filterp;
1061 int buf_len;
1062 int str_len;
1063 int rc;
1064 uint32 mask_size;
1065 uint32 pattern_size;
1066 char *argv[8], * buf = 0;
1067 int i = 0;
1068 char *arg_save = 0, *arg_org = 0;
1069#define BUF_SIZE 2048
1070
1071 if (!arg)
1072 return;
1073
1074 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
1075 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1076 goto fail;
1077 }
1078
1079 arg_org = arg_save;
1080
1081 if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
1082 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1083 goto fail;
1084 }
1085
1086 memcpy(arg_save, arg, strlen(arg) + 1);
1087
1088 if (strlen(arg) > BUF_SIZE) {
1089 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf)));
1090 goto fail;
1091 }
1092
1093 argv[i] = bcmstrtok(&arg_save, " ", 0);
1094 while (argv[i++])
1095 argv[i] = bcmstrtok(&arg_save, " ", 0);
1096
1097 i = 0;
1098 if (NULL == argv[i]) {
1099 DHD_ERROR(("No args provided\n"));
1100 goto fail;
1101 }
1102
1103 str = "pkt_filter_add";
1104 str_len = strlen(str);
1105 strncpy(buf, str, str_len);
1106 buf[ str_len ] = '\0';
1107 buf_len = str_len + 1;
1108
1109 pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
1110
1111 /* Parse packet filter id. */
1112 pkt_filter.id = htod32(strtoul(argv[i], NULL, 0));
1113
1114 if (NULL == argv[++i]) {
1115 DHD_ERROR(("Polarity not provided\n"));
1116 goto fail;
1117 }
1118
1119 /* Parse filter polarity. */
1120 pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0));
1121
1122 if (NULL == argv[++i]) {
1123 DHD_ERROR(("Filter type not provided\n"));
1124 goto fail;
1125 }
1126
1127 /* Parse filter type. */
1128 pkt_filter.type = htod32(strtoul(argv[i], NULL, 0));
1129
1130 if (NULL == argv[++i]) {
1131 DHD_ERROR(("Offset not provided\n"));
1132 goto fail;
1133 }
1134
1135 /* Parse pattern filter offset. */
1136 pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0));
1137
1138 if (NULL == argv[++i]) {
1139 DHD_ERROR(("Bitmask not provided\n"));
1140 goto fail;
1141 }
1142
1143 /* Parse pattern filter mask. */
1144 mask_size =
1145 htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern));
1146
1147 if (NULL == argv[++i]) {
1148 DHD_ERROR(("Pattern not provided\n"));
1149 goto fail;
1150 }
1151
1152 /* Parse pattern filter pattern. */
1153 pattern_size =
1154 htod32(wl_pattern_atoh(argv[i],
1155 (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
1156
1157 if (mask_size != pattern_size) {
1158 DHD_ERROR(("Mask and pattern not the same size\n"));
1159 goto fail;
1160 }
1161
1162 pkt_filter.u.pattern.size_bytes = mask_size;
1163 buf_len += WL_PKT_FILTER_FIXED_LEN;
1164 buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
1165
1166 /* Keep-alive attributes are set in local variable (keep_alive_pkt), and
1167 ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
1168 ** guarantee that the buffer is properly aligned.
1169 */
1170 memcpy((char *)pkt_filterp,
1171 &pkt_filter,
1172 WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
1173
1174 rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
1175 rc = rc >= 0 ? 0 : rc;
1176
1177 if (rc)
1178 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1179 __FUNCTION__, arg, rc));
1180 else
1181 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1182 __FUNCTION__, arg));
1183
1184fail:
1185 if (arg_org)
1186 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
1187
1188 if (buf)
1189 MFREE(dhd->osh, buf, BUF_SIZE);
1190}
1191#endif
1192
1193#ifdef ARP_OFFLOAD_SUPPORT
1194void
1195dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode)
1196{
1197 char iovbuf[32];
1198 int retcode;
1199
1200 bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
1201 retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1202 retcode = retcode >= 0 ? 0 : retcode;
1203 if (retcode)
1204 DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
1205 __FUNCTION__, arp_mode, retcode));
1206 else
1207 DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
1208 __FUNCTION__, arp_mode));
1209}
1210
1211void
1212dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable)
1213{
1214 char iovbuf[32];
1215 int retcode;
1216
1217 bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
1218 retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1219 retcode = retcode >= 0 ? 0 : retcode;
1220 if (retcode)
1221 DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
1222 __FUNCTION__, arp_enable, retcode));
1223 else
1224 DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
1225 __FUNCTION__, arp_enable));
1226}
1227#endif
1228
1229
1230void dhd_arp_cleanup(dhd_pub_t *dhd)
1231{
1232#ifdef ARP_OFFLOAD_SUPPORT
1233 int ret = 0;
1234 int iov_len = 0;
1235 char iovbuf[128];
1236
1237 if (dhd == NULL) return;
1238
1239 dhd_os_proto_block(dhd);
1240
1241 iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf));
1242 if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, iov_len)) < 0)
1243 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1244
1245 iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf));
1246 if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, iov_len)) < 0)
1247 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1248
1249 dhd_os_proto_unblock(dhd);
1250
1251#endif /* ARP_OFFLOAD_SUPPORT */
1252}
1253
1254void dhd_arp_offload_add_ip(dhd_pub_t *dhd, u32 ipaddr)
1255{
1256#ifdef ARP_OFFLOAD_SUPPORT
1257 int iov_len = 0;
1258 char iovbuf[32];
1259 int retcode;
1260
1261 dhd_os_proto_block(dhd);
1262
1263 iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, 4, iovbuf, sizeof(iovbuf));
1264 retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, iov_len);
1265
1266 dhd_os_proto_unblock(dhd);
1267
1268 if (retcode)
1269 DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n",
1270 __FUNCTION__, retcode));
1271 else
1272 DHD_TRACE(("%s: ARP ipaddr entry added\n",
1273 __FUNCTION__));
1274#endif /* ARP_OFFLOAD_SUPPORT */
1275}
1276
1277
1278int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen)
1279{
1280#ifdef ARP_OFFLOAD_SUPPORT
1281 int retcode;
1282 int iov_len = 0;
1283
1284 if (!buf)
1285 return -1;
1286
1287 dhd_os_proto_block(dhd);
1288
1289 iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen);
1290 retcode = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, buflen);
1291
1292 dhd_os_proto_unblock(dhd);
1293
1294 if (retcode) {
1295 DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n",
1296 __FUNCTION__, retcode));
1297
1298 return -1;
1299 }
1300#endif /* ARP_OFFLOAD_SUPPORT */
1301 return 0;
1302}
1303
1304
1305int
1306dhd_preinit_ioctls(dhd_pub_t *dhd)
1307{
1308 char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
1309 uint up = 0;
1310 char buf[128], *ptr;
1311 uint power_mode = PM_FAST;
1312 uint32 dongle_align = DHD_SDALIGN;
1313 uint32 glom = 0;
1314 uint bcn_timeout = 4;
1315 int scan_assoc_time = 40;
1316 int scan_unassoc_time = 40;
1317 uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */
1318#if defined(SOFTAP)
1319 uint dtim = 1;
1320#endif
1321 int ret = 0;
1322#ifdef GET_CUSTOM_MAC_ENABLE
1323 struct ether_addr ea_addr;
1324#endif /* GET_CUSTOM_MAC_ENABLE */
1325
1326 dhd_os_proto_block(dhd);
1327
1328#ifdef GET_CUSTOM_MAC_ENABLE
1329 /*
1330 ** Read MAC address from external customer place
1331 ** NOTE that default mac address has to be present in otp or nvram file
1332 ** to bring up firmware but unique per board mac address maybe provided
1333 ** by customer code
1334 */
1335 ret = dhd_custom_get_mac_address(ea_addr.octet);
1336 if (!ret) {
1337 bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf));
1338 ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
1339 if (ret < 0) {
1340 DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
1341 } else
1342 memcpy(dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN);
1343 }
1344#endif /* GET_CUSTOM_MAC_ENABLE */
1345
1346#ifdef SET_RANDOM_MAC_SOFTAP
1347 if (strstr(fw_path, "apsta") != NULL) {
1348 uint rand_mac;
1349
1350 srandom32((uint)jiffies);
1351 rand_mac = random32();
1352 iovbuf[0] = 0x02; /* locally administered bit */
1353 iovbuf[1] = 0x1A;
1354 iovbuf[2] = 0x11;
1355 iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0;
1356 iovbuf[4] = (unsigned char)(rand_mac >> 8);
1357 iovbuf[5] = (unsigned char)(rand_mac >> 16);
1358
1359 printk("Broadcom Dongle Host Driver mac=%02x:%02x:%02x:%02x:%02x:%02x\n",
1360 iovbuf[0], iovbuf[1], iovbuf[2], iovbuf[3], iovbuf[4], iovbuf[5]);
1361
1362 bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf));
1363 ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
1364 if (ret < 0) {
1365 DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret));
1366 } else
1367 memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN);
1368 }
1369#endif /* SET_RANDOM_MAC_SOFTAP */
1370
1371 /* Set Country code */
1372 if (dhd->dhd_cspec.ccode[0] != 0) {
1373 bcm_mkiovar("country", (char *)&dhd->dhd_cspec, \
1374 sizeof(wl_country_t), iovbuf, sizeof(iovbuf));
1375 if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0) {
1376 DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__));
1377 }
1378 }
1379
1380 /* Set Listen Interval */
1381 bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf));
1382 if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0)
1383 DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret));
1384
1385 /* query for 'ver' to get version info from firmware */
1386 memset(buf, 0, sizeof(buf));
1387 ptr = buf;
1388 bcm_mkiovar("ver", 0, 0, buf, sizeof(buf));
1389 dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf));
1390 bcmstrtok(&ptr, "\n", 0);
1391 /* Print fw version info */
1392 DHD_ERROR(("Firmware version = %s\n", buf));
1393
1394 /* Set PowerSave mode */
1395 dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode));
1396
1397 /* Match Host and Dongle rx alignment */
1398 bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf));
1399 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1400
1401 /* disable glom option per default */
1402 bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
1403 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1404
1405 /* Setup timeout if Beacons are lost and roam is off to report link down */
1406 bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf));
1407 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1408
1409 /* Enable/Disable build-in roaming to allowed ext supplicant to take of romaing */
1410 bcm_mkiovar("roam_off", (char *)&dhd_roam, 4, iovbuf, sizeof(iovbuf));
1411 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1412
1413#if defined(SOFTAP)
1414 if (ap_fw_loaded == TRUE) {
1415 dhdcdc_set_ioctl(dhd, 0, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim));
1416 }
1417#endif
1418
1419 if (dhd_roam == 0)
1420 {
1421 /* set internal roaming roaming parameters */
1422 int roam_scan_period = 30; /* in sec */
1423 int roam_fullscan_period = 120; /* in sec */
1424 int roam_trigger = -85;
1425 int roam_delta = 15;
1426 int band;
1427 int band_temp_set = WLC_BAND_2G;
1428
1429 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_ROAM_SCAN_PERIOD, \
1430 (char *)&roam_scan_period, sizeof(roam_scan_period)) < 0)
1431 DHD_ERROR(("%s: roam scan setup failed\n", __FUNCTION__));
1432
1433 bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, \
1434 4, iovbuf, sizeof(iovbuf));
1435 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, \
1436 iovbuf, sizeof(iovbuf)) < 0)
1437 DHD_ERROR(("%s: roam fullscan setup failed\n", __FUNCTION__));
1438
1439 if (dhdcdc_query_ioctl(dhd, 0, WLC_GET_BAND, \
1440 (char *)&band, sizeof(band)) < 0)
1441 DHD_ERROR(("%s: roam delta setting failed\n", __FUNCTION__));
1442 else {
1443 if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_ALL))
1444 {
1445 /* temp set band to insert new roams values */
1446 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_BAND, \
1447 (char *)&band_temp_set, sizeof(band_temp_set)) < 0)
1448 DHD_ERROR(("%s: local band seting failed\n", __FUNCTION__));
1449 }
1450 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_ROAM_DELTA, \
1451 (char *)&roam_delta, sizeof(roam_delta)) < 0)
1452 DHD_ERROR(("%s: roam delta setting failed\n", __FUNCTION__));
1453
1454 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_ROAM_TRIGGER, \
1455 (char *)&roam_trigger, sizeof(roam_trigger)) < 0)
1456 DHD_ERROR(("%s: roam trigger setting failed\n", __FUNCTION__));
1457
1458 /* Restore original band settinngs */
1459 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_BAND, \
1460 (char *)&band, sizeof(band)) < 0)
1461 DHD_ERROR(("%s: Original band restore failed\n", __FUNCTION__));
1462 }
1463 }
1464
1465 /* Force STA UP */
1466 if (dhd_radio_up)
1467 dhdcdc_set_ioctl(dhd, 0, WLC_UP, (char *)&up, sizeof(up));
1468
1469 /* Setup event_msgs */
1470 bcm_mkiovar("event_msgs", dhd->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
1471 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1472
1473 dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time,
1474 sizeof(scan_assoc_time));
1475 dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time,
1476 sizeof(scan_unassoc_time));
1477
1478#ifdef ARP_OFFLOAD_SUPPORT
1479 /* Set and enable ARP offload feature */
1480 if (dhd_arp_enable)
1481 dhd_arp_offload_set(dhd, dhd_arp_mode);
1482 dhd_arp_offload_enable(dhd, dhd_arp_enable);
1483#endif /* ARP_OFFLOAD_SUPPORT */
1484
1485#ifdef PKT_FILTER_SUPPORT
1486 {
1487 int i;
1488 /* Set up pkt filter */
1489 if (dhd_pkt_filter_enable) {
1490 for (i = 0; i < dhd->pktfilter_count; i++) {
1491 dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
1492 dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
1493 dhd_pkt_filter_init, dhd_master_mode);
1494 }
1495 }
1496 }
1497#endif /* PKT_FILTER_SUPPORT */
1498
1499#if defined(KEEP_ALIVE)
1500 {
1501 /* Set Keep Alive : be sure to use FW with -keepalive */
1502 int res;
1503
1504 if (ap_fw_loaded == FALSE) {
1505 if ((res = dhd_keep_alive_onoff(dhd, 1)) < 0)
1506 DHD_ERROR(("%s set keeplive failed %d\n", \
1507 __FUNCTION__, res));
1508 }
1509 }
1510#endif
1511
1512 dhd_os_proto_unblock(dhd);
1513
1514 return 0;
1515}
1516
1517#ifdef SIMPLE_ISCAN
1518
1519uint iscan_thread_id;
1520iscan_buf_t * iscan_chain = 0;
1521
1522iscan_buf_t *
1523dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf)
1524{
1525 iscan_buf_t *iscanbuf_alloc = 0;
1526 iscan_buf_t *iscanbuf_head;
1527
1528 dhd_iscan_lock();
1529
1530 iscanbuf_alloc = (iscan_buf_t*)MALLOC(dhd->osh, sizeof(iscan_buf_t));
1531 if (iscanbuf_alloc == NULL)
1532 goto fail;
1533
1534 iscanbuf_alloc->next = NULL;
1535 iscanbuf_head = *iscanbuf;
1536
1537 DHD_ISCAN(("%s: addr of allocated node = 0x%X"
1538 "addr of iscanbuf_head = 0x%X dhd = 0x%X\n",
1539 __FUNCTION__, iscanbuf_alloc, iscanbuf_head, dhd));
1540
1541 if (iscanbuf_head == NULL) {
1542 *iscanbuf = iscanbuf_alloc;
1543 DHD_ISCAN(("%s: Head is allocated\n", __FUNCTION__));
1544 goto fail;
1545 }
1546
1547 while (iscanbuf_head->next)
1548 iscanbuf_head = iscanbuf_head->next;
1549
1550 iscanbuf_head->next = iscanbuf_alloc;
1551
1552fail:
1553 dhd_iscan_unlock();
1554 return iscanbuf_alloc;
1555}
1556
1557void
1558dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete)
1559{
1560 iscan_buf_t *iscanbuf_free = 0;
1561 iscan_buf_t *iscanbuf_prv = 0;
1562 iscan_buf_t *iscanbuf_cur = iscan_chain;
1563 dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1564
1565 dhd_iscan_lock();
1566 /* If iscan_delete is null then delete the entire
1567 * chain or else delete specific one provided
1568 */
1569 if (!iscan_delete) {
1570 while (iscanbuf_cur) {
1571 iscanbuf_free = iscanbuf_cur;
1572 iscanbuf_cur = iscanbuf_cur->next;
1573 iscanbuf_free->next = 0;
1574 MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t));
1575 }
1576 iscan_chain = 0;
1577 } else {
1578 while (iscanbuf_cur) {
1579 if (iscanbuf_cur == iscan_delete)
1580 break;
1581 iscanbuf_prv = iscanbuf_cur;
1582 iscanbuf_cur = iscanbuf_cur->next;
1583 }
1584 if (iscanbuf_prv)
1585 iscanbuf_prv->next = iscan_delete->next;
1586
1587 iscan_delete->next = 0;
1588 MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t));
1589
1590 if (!iscanbuf_prv)
1591 iscan_chain = 0;
1592 }
1593 dhd_iscan_unlock();
1594}
1595
1596iscan_buf_t *
1597dhd_iscan_result_buf(void)
1598{
1599 return iscan_chain;
1600}
1601
1602
1603
1604/*
1605* print scan cache
1606* print partial iscan_skip list differently
1607*/
1608int
1609dhd_iscan_print_cache(iscan_buf_t *iscan_skip)
1610{
1611 int i = 0, l = 0;
1612 iscan_buf_t *iscan_cur;
1613 wl_iscan_results_t *list;
1614 wl_scan_results_t *results;
1615 wl_bss_info_t UNALIGNED *bi;
1616
1617 dhd_iscan_lock();
1618
1619 iscan_cur = dhd_iscan_result_buf();
1620
1621 while (iscan_cur) {
1622 list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
1623 if (!list)
1624 break;
1625
1626 results = (wl_scan_results_t *)&list->results;
1627 if (!results)
1628 break;
1629
1630 if (results->version != WL_BSS_INFO_VERSION) {
1631 DHD_ISCAN(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
1632 __FUNCTION__, results->version));
1633 goto done;
1634 }
1635
1636 bi = results->bss_info;
1637 for (i = 0; i < results->count; i++) {
1638 if (!bi)
1639 break;
1640
1641 DHD_ISCAN(("%s[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n",
1642 iscan_cur != iscan_skip?"BSS":"bss", l, i,
1643 bi->BSSID.octet[0], bi->BSSID.octet[1], bi->BSSID.octet[2],
1644 bi->BSSID.octet[3], bi->BSSID.octet[4], bi->BSSID.octet[5]));
1645
1646 bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
1647 }
1648 iscan_cur = iscan_cur->next;
1649 l++;
1650 }
1651
1652done:
1653 dhd_iscan_unlock();
1654 return 0;
1655}
1656
1657/*
1658* delete disappeared AP from specific scan cache but skip partial list in iscan_skip
1659*/
1660int
1661dhd_iscan_delete_bss(void *dhdp, void *addr, iscan_buf_t *iscan_skip)
1662{
1663 int i = 0, j = 0, l = 0;
1664 iscan_buf_t *iscan_cur;
1665 wl_iscan_results_t *list;
1666 wl_scan_results_t *results;
1667 wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next;
1668
1669 uchar *s_addr = addr;
1670
1671 dhd_iscan_lock();
1672 DHD_ISCAN(("%s: BSS to remove %X:%X:%X:%X:%X:%X\n",
1673 __FUNCTION__, s_addr[0], s_addr[1], s_addr[2],
1674 s_addr[3], s_addr[4], s_addr[5]));
1675
1676 iscan_cur = dhd_iscan_result_buf();
1677
1678 while (iscan_cur) {
1679 if (iscan_cur != iscan_skip) {
1680 list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
1681 if (!list)
1682 break;
1683
1684 results = (wl_scan_results_t *)&list->results;
1685 if (!results)
1686 break;
1687
1688 if (results->version != WL_BSS_INFO_VERSION) {
1689 DHD_ERROR(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
1690 __FUNCTION__, results->version));
1691 goto done;
1692 }
1693
1694 bi = results->bss_info;
1695 for (i = 0; i < results->count; i++) {
1696 if (!bi)
1697 break;
1698
1699 if (!memcmp(bi->BSSID.octet, addr, ETHER_ADDR_LEN)) {
1700 DHD_ISCAN(("%s: Del BSS[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n",
1701 __FUNCTION__, l, i, bi->BSSID.octet[0],
1702 bi->BSSID.octet[1], bi->BSSID.octet[2],
1703 bi->BSSID.octet[3], bi->BSSID.octet[4],
1704 bi->BSSID.octet[5]));
1705
1706 bi_new = bi;
1707 bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
1708/*
1709 if(bi && bi_new) {
1710 bcopy(bi, bi_new, results->buflen -
1711 dtoh32(bi_new->length));
1712 results->buflen -= dtoh32(bi_new->length);
1713 }
1714*/
1715 results->buflen -= dtoh32(bi_new->length);
1716 results->count--;
1717
1718 for (j = i; j < results->count; j++) {
1719 if (bi && bi_new) {
1720 DHD_ISCAN(("%s: Moved up BSS[%2.2d:%2.2d]"
1721 "%X:%X:%X:%X:%X:%X\n",
1722 __FUNCTION__, l, j, bi->BSSID.octet[0],
1723 bi->BSSID.octet[1], bi->BSSID.octet[2],
1724 bi->BSSID.octet[3], bi->BSSID.octet[4],
1725 bi->BSSID.octet[5]));
1726
1727 bi_next = (wl_bss_info_t *)((uintptr)bi +
1728 dtoh32(bi->length));
1729 bcopy(bi, bi_new, dtoh32(bi->length));
1730 bi_new = (wl_bss_info_t *)((uintptr)bi_new +
1731 dtoh32(bi_new->length));
1732 bi = bi_next;
1733 }
1734 }
1735
1736 if (results->count == 0) {
1737 /* Prune now empty partial scan list */
1738 dhd_iscan_free_buf(dhdp, iscan_cur);
1739 goto done;
1740 }
1741 break;
1742 }
1743 bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
1744 }
1745 }
1746 iscan_cur = iscan_cur->next;
1747 l++;
1748 }
1749
1750done:
1751 dhd_iscan_unlock();
1752 return 0;
1753}
1754
1755int
1756dhd_iscan_remove_duplicates(void * dhdp, iscan_buf_t *iscan_cur)
1757{
1758 int i = 0;
1759 wl_iscan_results_t *list;
1760 wl_scan_results_t *results;
1761 wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next;
1762
1763 dhd_iscan_lock();
1764
1765 DHD_ISCAN(("%s: Scan cache before delete\n",
1766 __FUNCTION__));
1767 dhd_iscan_print_cache(iscan_cur);
1768
1769 if (!iscan_cur)
1770 goto done;
1771
1772 list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
1773 if (!list)
1774 goto done;
1775
1776 results = (wl_scan_results_t *)&list->results;
1777 if (!results)
1778 goto done;
1779
1780 if (results->version != WL_BSS_INFO_VERSION) {
1781 DHD_ERROR(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
1782 __FUNCTION__, results->version));
1783 goto done;
1784 }
1785
1786 bi = results->bss_info;
1787 for (i = 0; i < results->count; i++) {
1788 if (!bi)
1789 break;
1790
1791 DHD_ISCAN(("%s: Find dups for BSS[%2.2d] %X:%X:%X:%X:%X:%X\n",
1792 __FUNCTION__, i, bi->BSSID.octet[0], bi->BSSID.octet[1], bi->BSSID.octet[2],
1793 bi->BSSID.octet[3], bi->BSSID.octet[4], bi->BSSID.octet[5]));
1794
1795 dhd_iscan_delete_bss(dhdp, bi->BSSID.octet, iscan_cur);
1796
1797 bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
1798 }
1799
1800done:
1801 DHD_ISCAN(("%s: Scan cache after delete\n", __FUNCTION__));
1802 dhd_iscan_print_cache(iscan_cur);
1803 dhd_iscan_unlock();
1804 return 0;
1805}
1806
1807void
1808dhd_iscan_ind_scan_confirm(void *dhdp, bool status)
1809{
1810
1811 dhd_ind_scan_confirm(dhdp, status);
1812}
1813
1814int
1815dhd_iscan_request(void * dhdp, uint16 action)
1816{
1817 int rc;
1818 wl_iscan_params_t params;
1819 dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1820 char buf[WLC_IOCTL_SMLEN];
1821
1822
1823 memset(&params, 0, sizeof(wl_iscan_params_t));
1824 memcpy(&params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
1825
1826 params.params.bss_type = DOT11_BSSTYPE_ANY;
1827 params.params.scan_type = DOT11_SCANTYPE_ACTIVE;
1828
1829 params.params.nprobes = htod32(-1);
1830 params.params.active_time = htod32(-1);
1831 params.params.passive_time = htod32(-1);
1832 params.params.home_time = htod32(-1);
1833 params.params.channel_num = htod32(0);
1834
1835 params.version = htod32(ISCAN_REQ_VERSION);
1836 params.action = htod16(action);
1837 params.scan_duration = htod16(0);
1838
1839 bcm_mkiovar("iscan", (char *)&params, sizeof(wl_iscan_params_t), buf, WLC_IOCTL_SMLEN);
1840 rc = dhd_wl_ioctl(dhdp, WLC_SET_VAR, buf, WLC_IOCTL_SMLEN);
1841
1842 return rc;
1843}
1844
1845static int
1846dhd_iscan_get_partial_result(void *dhdp, uint *scan_count)
1847{
1848 wl_iscan_results_t *list_buf;
1849 wl_iscan_results_t list;
1850 wl_scan_results_t *results;
1851 iscan_buf_t *iscan_cur;
1852 int status = -1;
1853 dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1854 int rc;
1855
1856
1857 iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain);
1858 if (!iscan_cur) {
1859 DHD_ERROR(("%s: Failed to allocate node\n", __FUNCTION__));
1860 dhd_iscan_free_buf(dhdp, 0);
1861 dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT);
1862 goto fail;
1863 }
1864
1865 dhd_iscan_lock();
1866
1867 memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
1868 list_buf = (wl_iscan_results_t*)iscan_cur->iscan_buf;
1869 results = &list_buf->results;
1870 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
1871 results->version = 0;
1872 results->count = 0;
1873
1874 memset(&list, 0, sizeof(list));
1875 list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
1876 bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE,
1877 iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1878 rc = dhd_wl_ioctl(dhdp, WLC_GET_VAR, iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1879
1880 results->buflen = dtoh32(results->buflen);
1881 results->version = dtoh32(results->version);
1882 *scan_count = results->count = dtoh32(results->count);
1883 status = dtoh32(list_buf->status);
1884
1885 dhd_iscan_unlock();
1886
1887 if (!(*scan_count))
1888 dhd_iscan_free_buf(dhdp, iscan_cur);
1889 else
1890 dhd_iscan_remove_duplicates(dhdp, iscan_cur);
1891
1892
1893fail:
1894 return status;
1895}
1896
1897#endif
1898
1899/* Function to estimate possible DTIM_SKIP value */
1900int dhd_get_dtim_skip(dhd_pub_t *dhd)
1901{
1902 int bcn_li_dtim;
1903 char buf[128];
1904 int ret;
1905 int dtim_assoc = 0;
1906
1907 if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1))
1908 bcn_li_dtim = 3;
1909 else
1910 bcn_li_dtim = dhd->dtim_skip;
1911
1912 /* Read DTIM value if associated */
1913 memset(buf, 0, sizeof(buf));
1914 bcm_mkiovar("dtim_assoc", 0, 0, buf, sizeof(buf));
1915 if ((ret = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf))) < 0) {
1916 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1917 bcn_li_dtim = 1;
1918 goto exit;
1919 }
1920 else
1921 dtim_assoc = dtoh32(*(int *)buf);
1922
1923 DHD_ERROR(("%s bcn_li_dtim=%d DTIM=%d Listen=%d\n", \
1924 __FUNCTION__, bcn_li_dtim, dtim_assoc, LISTEN_INTERVAL));
1925
1926 /* if not assocated just eixt */
1927 if (dtim_assoc == 0) {
1928 goto exit;
1929 }
1930
1931 /* check if sta listen interval fits into AP dtim */
1932 if (dtim_assoc > LISTEN_INTERVAL) {
1933 /* AP DTIM to big for our Listen Interval : no dtim skiping */
1934 bcn_li_dtim = 1;
1935 DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", \
1936 __FUNCTION__, dtim_assoc, LISTEN_INTERVAL));
1937 goto exit;
1938 }
1939
1940 if ((bcn_li_dtim * dtim_assoc) > LISTEN_INTERVAL) {
1941 /* Round up dtim_skip to fit into STAs Listen Interval */
1942 bcn_li_dtim = (int)(LISTEN_INTERVAL / dtim_assoc);
1943 DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim));
1944 }
1945
1946exit:
1947 return bcn_li_dtim;
1948}
1949
1950#ifdef PNO_SUPPORT
1951int dhd_pno_clean(dhd_pub_t *dhd)
1952{
1953 char iovbuf[128];
1954 int pfn_enabled = 0;
1955 int iov_len = 0;
1956 int ret;
1957
1958 /* Disable pfn */
1959 iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf));
1960 if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) >= 0) {
1961 /* clear pfn */
1962 iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf));
1963 if (iov_len) {
1964 if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, iov_len)) < 0) {
1965 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1966 }
1967 }
1968 else {
1969 ret = -1;
1970 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len));
1971 }
1972 }
1973 else
1974 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1975
1976 return ret;
1977}
1978
1979int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
1980{
1981 char iovbuf[128];
1982 uint8 bssid[6];
1983 int ret = -1;
1984
1985 if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) {
1986 DHD_ERROR(("%s error exit\n", __FUNCTION__));
1987 return ret;
1988 }
1989
1990 memset(iovbuf, 0, sizeof(iovbuf));
1991
1992 /* Check if disassoc to enable pno */
1993 if ((pfn_enabled) && \
1994 ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_GET_BSSID, \
1995 (char *)&bssid, ETHER_ADDR_LEN)) == BCME_NOTASSOCIATED)) {
1996 DHD_TRACE(("%s pno enable called in disassoc mode\n", __FUNCTION__));
1997 }
1998 else if (pfn_enabled) {
1999 DHD_ERROR(("%s pno enable called in assoc mode ret=%d\n", \
2000 __FUNCTION__, ret));
2001 return ret;
2002 }
2003
2004 /* Enable/disable PNO */
2005 if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) {
2006 if ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0) {
2007 DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret));
2008 return ret;
2009 }
2010 else {
2011 dhd->pno_enable = pfn_enabled;
2012 DHD_TRACE(("%s set pno as %d\n", __FUNCTION__, dhd->pno_enable));
2013 }
2014 }
2015 else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret));
2016
2017 return ret;
2018}
2019
2020/* Function to execute combined scan */
2021int
2022dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, \
2023 int pno_repeat, int pno_freq_expo_max)
2024{
2025 int err = -1;
2026 char iovbuf[128];
2027 int k, i;
2028 wl_pfn_param_t pfn_param;
2029 wl_pfn_t pfn_element;
2030
2031 DHD_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr));
2032
2033 if ((!dhd) && (!ssids_local)) {
2034 DHD_ERROR(("%s error exit\n", __FUNCTION__));
2035 err = -1;
2036 }
2037
2038 /* Check for broadcast ssid */
2039 for (k = 0; k < nssid; k++) {
2040 if (!ssids_local[k].SSID_len) {
2041 DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k));
2042 return err;
2043 }
2044 }
2045/* #define PNO_DUMP 1 */
2046#ifdef PNO_DUMP
2047 {
2048 int j;
2049 for (j = 0; j < nssid; j++) {
2050 DHD_ERROR(("%d: scan for %s size =%d\n", j,
2051 ssids_local[j].SSID, ssids_local[j].SSID_len));
2052 }
2053 }
2054#endif /* PNO_DUMP */
2055
2056 /* clean up everything */
2057 if ((err = dhd_pno_clean(dhd)) < 0) {
2058 DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err));
2059 return err;
2060 }
2061 memset(&pfn_param, 0, sizeof(pfn_param));
2062 memset(&pfn_element, 0, sizeof(pfn_element));
2063
2064 /* set pfn parameters */
2065 pfn_param.version = htod32(PFN_VERSION);
2066 pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT));
2067
2068 /* check and set extra pno params */
2069 if ((pno_repeat != 0) || (pno_freq_expo_max != 0)) {
2070 pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT);
2071 pfn_param.repeat_scan = htod32(pno_repeat);
2072 pfn_param.max_freq_adjust = htod32(pno_freq_expo_max);
2073 }
2074
2075 /* set up pno scan fr */
2076 if (scan_fr != 0)
2077 pfn_param.scan_freq = htod32(scan_fr);
2078
2079 if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) {
2080 DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC));
2081 return err;
2082 }
2083 if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) {
2084 DHD_ERROR(("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC));
2085 return err;
2086 }
2087
2088 bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf));
2089 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
2090
2091 /* set all pfn ssid */
2092 for (i = 0; i < nssid; i++) {
2093
2094 pfn_element.bss_type = htod32(DOT11_BSSTYPE_INFRASTRUCTURE);
2095 pfn_element.auth = (DOT11_OPEN_SYSTEM);
2096 pfn_element.infra = htod32(1);
2097
2098 memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len);
2099 pfn_element.ssid.SSID_len = ssids_local[i].SSID_len;
2100
2101 if ((err =
2102 bcm_mkiovar("pfn_add", (char *)&pfn_element,
2103 sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) {
2104 if ((err =
2105 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf))) < 0) {
2106 DHD_ERROR(("%s failed for i=%d error=%d\n",
2107 __FUNCTION__, i, err));
2108 return err;
2109 }
2110 else
2111 DHD_ERROR(("%s set OK with PNO time=%d repeat=%d max_adjust=%d\n", \
2112 __FUNCTION__, pfn_param.scan_freq, \
2113 pfn_param.repeat_scan, pfn_param.max_freq_adjust));
2114 }
2115 else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, err));
2116 }
2117
2118 /* Enable PNO */
2119 /* dhd_pno_enable(dhd, 1); */
2120 return err;
2121}
2122
2123int dhd_pno_get_status(dhd_pub_t *dhd)
2124{
2125 int ret = -1;
2126
2127 if (!dhd)
2128 return ret;
2129 else
2130 return (dhd->pno_enable);
2131}
2132
2133#endif /* PNO_SUPPORT */
2134
2135#if defined(KEEP_ALIVE)
2136int dhd_keep_alive_onoff(dhd_pub_t *dhd, int ka_on)
2137{
2138 char buf[256];
2139 char *buf_ptr = buf;
2140 wl_keep_alive_pkt_t keep_alive_pkt;
2141 char * str;
2142 int str_len, buf_len;
2143 int res = 0;
2144 int keep_alive_period = KEEP_ALIVE_PERIOD; /* in ms */
2145
2146 DHD_TRACE(("%s: ka:%d\n", __FUNCTION__, ka_on));
2147
2148 if (ka_on) { /* on suspend */
2149 keep_alive_pkt.period_msec = keep_alive_period;
2150
2151 } else {
2152 /* on resume, turn off keep_alive packets */
2153 keep_alive_pkt.period_msec = 0;
2154 }
2155
2156 /* IOC var name */
2157 str = "keep_alive";
2158 str_len = strlen(str);
2159 strncpy(buf, str, str_len);
2160 buf[str_len] = '\0';
2161 buf_len = str_len + 1;
2162
2163 /* set ptr to IOCTL payload after the var name */
2164 buf_ptr += buf_len; /* include term Z */
2165
2166 /* copy Keep-alive attributes from local var keep_alive_pkt */
2167 str = NULL_PKT_STR;
2168 keep_alive_pkt.len_bytes = strlen(str);
2169
2170 memcpy(buf_ptr, &keep_alive_pkt, WL_KEEP_ALIVE_FIXED_LEN);
2171 buf_ptr += WL_KEEP_ALIVE_FIXED_LEN;
2172
2173 /* copy packet data */
2174 memcpy(buf_ptr, str, keep_alive_pkt.len_bytes);
2175 buf_len += (WL_KEEP_ALIVE_FIXED_LEN + keep_alive_pkt.len_bytes);
2176
2177 res = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
2178 return res;
2179}
2180#endif /* defined(KEEP_ALIVE) */
2181
2182#if defined(CSCAN)
2183
2184/* Androd ComboSCAN support */
2185/*
2186 * data parsing from ComboScan tlv list
2187*/
2188int
2189wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token,
2190 int input_size, int *bytes_left)
2191{
2192 char* str = *list_str;
2193 uint16 short_temp;
2194 uint32 int_temp;
2195
2196 if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) {
2197 DHD_ERROR(("%s error paramters\n", __FUNCTION__));
2198 return -1;
2199 }
2200
2201 /* Clean all dest bytes */
2202 memset(dst, 0, dst_size);
2203 while (*bytes_left > 0) {
2204
2205 if (str[0] != token) {
2206 DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n",
2207 __FUNCTION__, token, str[0], *bytes_left));
2208 return -1;
2209 }
2210
2211 *bytes_left -= 1;
2212 str += 1;
2213
2214 if (input_size == 1) {
2215 memcpy(dst, str, input_size);
2216 }
2217 else if (input_size == 2) {
2218 memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)),
2219 input_size);
2220 }
2221 else if (input_size == 4) {
2222 memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)),
2223 input_size);
2224 }
2225
2226 *bytes_left -= input_size;
2227 str += input_size;
2228 *list_str = str;
2229 return 1;
2230 }
2231 return 1;
2232}
2233
2234/*
2235 * channel list parsing from cscan tlv list
2236*/
2237int
2238wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list,
2239 int channel_num, int *bytes_left)
2240{
2241 char* str = *list_str;
2242 int idx = 0;
2243
2244 if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) {
2245 DHD_ERROR(("%s error paramters\n", __FUNCTION__));
2246 return -1;
2247 }
2248
2249 while (*bytes_left > 0) {
2250
2251 if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) {
2252 *list_str = str;
2253 DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
2254 return idx;
2255 }
2256 /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */
2257 *bytes_left -= 1;
2258 str += 1;
2259
2260 if (str[0] == 0) {
2261 /* All channels */
2262 channel_list[idx] = 0x0;
2263 }
2264 else {
2265 channel_list[idx] = (uint16)str[0];
2266 DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx]));
2267 }
2268 *bytes_left -= 1;
2269 str += 1;
2270
2271 if (idx++ > 255) {
2272 DHD_ERROR(("%s Too many channels \n", __FUNCTION__));
2273 return -1;
2274 }
2275 }
2276
2277 *list_str = str;
2278 return idx;
2279}
2280
2281/*
2282 * SSIDs list parsing from cscan tlv list
2283 */
2284int
2285wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left)
2286{
2287 char* str = *list_str;
2288 int idx = 0;
2289
2290 if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) {
2291 DHD_ERROR(("%s error paramters\n", __FUNCTION__));
2292 return -1;
2293 }
2294
2295 while (*bytes_left > 0) {
2296
2297 if (str[0] != CSCAN_TLV_TYPE_SSID_IE) {
2298 *list_str = str;
2299 DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
2300 return idx;
2301 }
2302
2303 /* Get proper CSCAN_TLV_TYPE_SSID_IE */
2304 *bytes_left -= 1;
2305 str += 1;
2306
2307 if (str[0] == 0) {
2308 /* Broadcast SSID */
2309 ssid[idx].SSID_len = 0;
2310 memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN);
2311 *bytes_left -= 1;
2312 str += 1;
2313
2314 DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left));
2315 }
2316 else if (str[0] <= DOT11_MAX_SSID_LEN) {
2317 /* Get proper SSID size */
2318 ssid[idx].SSID_len = str[0];
2319 *bytes_left -= 1;
2320 str += 1;
2321
2322 /* Get SSID */
2323 if (ssid[idx].SSID_len > *bytes_left) {
2324 DHD_ERROR(("%s out of memory range len=%d but left=%d\n",
2325 __FUNCTION__, ssid[idx].SSID_len, *bytes_left));
2326 return -1;
2327 }
2328
2329 memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len);
2330
2331 *bytes_left -= ssid[idx].SSID_len;
2332 str += ssid[idx].SSID_len;
2333
2334 DHD_TRACE(("%s :size=%d left=%d\n",
2335 (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left));
2336 }
2337 else {
2338 DHD_ERROR(("### SSID size more that %d\n", str[0]));
2339 return -1;
2340 }
2341
2342 if (idx++ > max) {
2343 DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx));
2344 return -1;
2345 }
2346 }
2347
2348 *list_str = str;
2349 return idx;
2350}
2351
2352/* Parse a comma-separated list from list_str into ssid array, starting
2353 * at index idx. Max specifies size of the ssid array. Parses ssids
2354 * and returns updated idx; if idx >= max not all fit, the excess have
2355 * not been copied. Returns -1 on empty string, or on ssid too long.
2356 */
2357int
2358wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max)
2359{
2360 char* str, *ptr;
2361
2362 if ((list_str == NULL) || (*list_str == NULL))
2363 return -1;
2364
2365 for (str = *list_str; str != NULL; str = ptr) {
2366
2367 /* check for next TAG */
2368 if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) {
2369 *list_str = str + strlen(GET_CHANNEL);
2370 return idx;
2371 }
2372
2373 if ((ptr = strchr(str, ',')) != NULL) {
2374 *ptr++ = '\0';
2375 }
2376
2377 if (strlen(str) > DOT11_MAX_SSID_LEN) {
2378 DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN));
2379 return -1;
2380 }
2381
2382 if (strlen(str) == 0)
2383 ssid[idx].SSID_len = 0;
2384
2385 if (idx < max) {
2386 strcpy((char*)ssid[idx].SSID, str);
2387 ssid[idx].SSID_len = strlen(str);
2388 }
2389 idx++;
2390 }
2391 return idx;
2392}
2393
2394/*
2395 * Parse channel list from iwpriv CSCAN
2396 */
2397int
2398wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num)
2399{
2400 int num;
2401 int val;
2402 char* str;
2403 char* endptr = NULL;
2404
2405 if ((list_str == NULL)||(*list_str == NULL))
2406 return -1;
2407
2408 str = *list_str;
2409 num = 0;
2410 while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) {
2411 val = (int)strtoul(str, &endptr, 0);
2412 if (endptr == str) {
2413 printf("could not parse channel number starting at"
2414 " substring \"%s\" in list:\n%s\n",
2415 str, *list_str);
2416 return -1;
2417 }
2418 str = endptr + strspn(endptr, " ,");
2419
2420 if (num == channel_num) {
2421 DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n",
2422 channel_num, *list_str));
2423 return -1;
2424 }
2425
2426 channel_list[num++] = (uint16)val;
2427 }
2428 *list_str = str;
2429 return num;
2430}
2431
2432#endif
diff --git a/drivers/net/wireless/bcm4329/dhd_custom_gpio.c b/drivers/net/wireless/bcm4329/dhd_custom_gpio.c
new file mode 100644
index 00000000000..4d32863e298
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/dhd_custom_gpio.c
@@ -0,0 +1,272 @@
1/*
2* Customer code to add GPIO control during WLAN start/stop
3* Copyright (C) 1999-2010, 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.1.4.8.4.4 2011/01/20 20:23:09 Exp $
24*/
25
26
27#include <typedefs.h>
28#include <linuxver.h>
29#include <osl.h>
30#include <bcmutils.h>
31
32#include <dngl_stats.h>
33#include <dhd.h>
34
35#include <wlioctl.h>
36#include <wl_iw.h>
37
38#define WL_ERROR(x) printf x
39#define WL_TRACE(x)
40
41#ifdef CUSTOMER_HW
42extern void bcm_wlan_power_off(int);
43extern void bcm_wlan_power_on(int);
44#endif /* CUSTOMER_HW */
45#ifdef CUSTOMER_HW2
46int wifi_set_carddetect(int on);
47int wifi_set_power(int on, unsigned long msec);
48int wifi_get_irq_number(unsigned long *irq_flags_ptr);
49int wifi_get_mac_addr(unsigned char *buf);
50void *wifi_get_country_code(char *ccode);
51#endif
52
53#if defined(OOB_INTR_ONLY)
54
55#if defined(BCMLXSDMMC)
56extern int sdioh_mmc_irq(int irq);
57#endif /* (BCMLXSDMMC) */
58
59#ifdef CUSTOMER_HW3
60#include <mach/gpio.h>
61#endif
62
63/* Customer specific Host GPIO defintion */
64static int dhd_oob_gpio_num = -1; /* GG 19 */
65
66module_param(dhd_oob_gpio_num, int, 0644);
67MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number");
68
69int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr)
70{
71 int host_oob_irq = 0;
72
73#ifdef CUSTOMER_HW2
74 host_oob_irq = wifi_get_irq_number(irq_flags_ptr);
75
76#else /* for NOT CUSTOMER_HW2 */
77#if defined(CUSTOM_OOB_GPIO_NUM)
78 if (dhd_oob_gpio_num < 0) {
79 dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM;
80 }
81#endif
82
83 if (dhd_oob_gpio_num < 0) {
84 WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n",
85 __FUNCTION__));
86 return (dhd_oob_gpio_num);
87 }
88
89 WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n",
90 __FUNCTION__, dhd_oob_gpio_num));
91
92#if defined CUSTOMER_HW
93 host_oob_irq = MSM_GPIO_TO_INT(dhd_oob_gpio_num);
94#elif defined CUSTOMER_HW3
95 gpio_request(dhd_oob_gpio_num, "oob irq");
96 host_oob_irq = gpio_to_irq(dhd_oob_gpio_num);
97 gpio_direction_input(dhd_oob_gpio_num);
98#endif /* CUSTOMER_HW */
99#endif /* CUSTOMER_HW2 */
100
101 return (host_oob_irq);
102}
103#endif /* defined(OOB_INTR_ONLY) */
104
105/* Customer function to control hw specific wlan gpios */
106void
107dhd_customer_gpio_wlan_ctrl(int onoff)
108{
109 switch (onoff) {
110 case WLAN_RESET_OFF:
111 WL_TRACE(("%s: call customer specific GPIO to insert WLAN RESET\n",
112 __FUNCTION__));
113#ifdef CUSTOMER_HW
114 bcm_wlan_power_off(2);
115#endif /* CUSTOMER_HW */
116#ifdef CUSTOMER_HW2
117 wifi_set_power(0, 0);
118#endif
119 WL_ERROR(("=========== WLAN placed in RESET ========\n"));
120 break;
121
122 case WLAN_RESET_ON:
123 WL_TRACE(("%s: callc customer specific GPIO to remove WLAN RESET\n",
124 __FUNCTION__));
125#ifdef CUSTOMER_HW
126 bcm_wlan_power_on(2);
127#endif /* CUSTOMER_HW */
128#ifdef CUSTOMER_HW2
129 wifi_set_power(1, 0);
130#endif
131 WL_ERROR(("=========== WLAN going back to live ========\n"));
132 break;
133
134 case WLAN_POWER_OFF:
135 WL_TRACE(("%s: call customer specific GPIO to turn off WL_REG_ON\n",
136 __FUNCTION__));
137#ifdef CUSTOMER_HW
138 bcm_wlan_power_off(1);
139#endif /* CUSTOMER_HW */
140 break;
141
142 case WLAN_POWER_ON:
143 WL_TRACE(("%s: call customer specific GPIO to turn on WL_REG_ON\n",
144 __FUNCTION__));
145#ifdef CUSTOMER_HW
146 bcm_wlan_power_on(1);
147 /* Lets customer power to get stable */
148 OSL_DELAY(50);
149#endif /* CUSTOMER_HW */
150 break;
151 }
152}
153
154#ifdef GET_CUSTOM_MAC_ENABLE
155/* Function to get custom MAC address */
156int
157dhd_custom_get_mac_address(unsigned char *buf)
158{
159 int ret = 0;
160
161 WL_TRACE(("%s Enter\n", __FUNCTION__));
162 if (!buf)
163 return -EINVAL;
164
165 /* Customer access to MAC address stored outside of DHD driver */
166#ifdef CUSTOMER_HW2
167 ret = wifi_get_mac_addr(buf);
168#endif
169
170#ifdef EXAMPLE_GET_MAC
171 /* EXAMPLE code */
172 {
173 struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}};
174 bcopy((char *)&ea_example, buf, sizeof(struct ether_addr));
175 }
176#endif /* EXAMPLE_GET_MAC */
177
178 return ret;
179}
180#endif /* GET_CUSTOM_MAC_ENABLE */
181
182/* Customized Locale table : OPTIONAL feature */
183const struct cntry_locales_custom translate_custom_table[] = {
184/* Table should be filled out based on custom platform regulatory requirement */
185#ifdef EXAMPLE_TABLE
186 {"", "XY", 4}, /* universal */
187 {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */
188 {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */
189 {"EU", "EU", 5}, /* European union countries */
190 {"AT", "EU", 5},
191 {"BE", "EU", 5},
192 {"BG", "EU", 5},
193 {"CY", "EU", 5},
194 {"CZ", "EU", 5},
195 {"DK", "EU", 5},
196 {"EE", "EU", 5},
197 {"FI", "EU", 5},
198 {"FR", "EU", 5},
199 {"DE", "EU", 5},
200 {"GR", "EU", 5},
201 {"HU", "EU", 5},
202 {"IE", "EU", 5},
203 {"IT", "EU", 5},
204 {"LV", "EU", 5},
205 {"LI", "EU", 5},
206 {"LT", "EU", 5},
207 {"LU", "EU", 5},
208 {"MT", "EU", 5},
209 {"NL", "EU", 5},
210 {"PL", "EU", 5},
211 {"PT", "EU", 5},
212 {"RO", "EU", 5},
213 {"SK", "EU", 5},
214 {"SI", "EU", 5},
215 {"ES", "EU", 5},
216 {"SE", "EU", 5},
217 {"GB", "EU", 5}, /* input ISO "GB" to : EU regrev 05 */
218 {"IL", "IL", 0},
219 {"CH", "CH", 0},
220 {"TR", "TR", 0},
221 {"NO", "NO", 0},
222 {"KR", "XY", 3},
223 {"AU", "XY", 3},
224 {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */
225 {"TW", "XY", 3},
226 {"AR", "XY", 3},
227 {"MX", "XY", 3}
228#endif /* EXAMPLE_TABLE */
229};
230
231
232/* Customized Locale convertor
233* input : ISO 3166-1 country abbreviation
234* output: customized cspec
235*/
236void get_customized_country_code(char *country_iso_code, wl_country_t *cspec)
237{
238#ifdef CUSTOMER_HW2
239 struct cntry_locales_custom *cloc_ptr;
240
241 if (!cspec)
242 return;
243
244 cloc_ptr = wifi_get_country_code(country_iso_code);
245 if (cloc_ptr) {
246 strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ);
247 cspec->rev = cloc_ptr->custom_locale_rev;
248 }
249 return;
250#else
251 int size, i;
252
253 size = ARRAYSIZE(translate_custom_table);
254
255 if (cspec == 0)
256 return;
257
258 if (size == 0)
259 return;
260
261 for (i = 0; i < size; i++) {
262 if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) {
263 memcpy(cspec->ccode, translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ);
264 cspec->rev = translate_custom_table[i].custom_locale_rev;
265 return;
266 }
267 }
268 memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ);
269 cspec->rev = translate_custom_table[0].custom_locale_rev;
270 return;
271#endif
272}
diff --git a/drivers/net/wireless/bcm4329/dhd_dbg.h b/drivers/net/wireless/bcm4329/dhd_dbg.h
new file mode 100644
index 00000000000..b48c1d70f14
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/dhd_dbg.h
@@ -0,0 +1,100 @@
1/*
2 * Debug/trace/assert driver definitions for Dongle Host Driver.
3 *
4 * Copyright (C) 1999-2010, 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,v 1.5.6.2.4.2.14.10 2010/05/21 21:49:38 Exp $
25 */
26
27#ifndef _dhd_dbg_
28#define _dhd_dbg_
29
30#ifdef 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
47#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL)
48#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL)
49#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL)
50#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL)
51#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL)
52#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL)
53#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL)
54#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL)
55#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL)
56#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL)
57#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL)
58#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL)
59#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL)
60
61#else /* DHD_DEBUG */
62
63#define DHD_ERROR(args) do {if (net_ratelimit()) printf args;} while (0)
64#define DHD_TRACE(args)
65#define DHD_INFO(args)
66#define DHD_DATA(args)
67#define DHD_CTL(args)
68#define DHD_TIMER(args)
69#define DHD_HDRS(args)
70#define DHD_BYTES(args)
71#define DHD_INTR(args)
72#define DHD_GLOM(args)
73#define DHD_EVENT(args)
74#define DHD_BTA(args)
75#define DHD_ISCAN(args)
76
77#define DHD_ERROR_ON() 0
78#define DHD_TRACE_ON() 0
79#define DHD_INFO_ON() 0
80#define DHD_DATA_ON() 0
81#define DHD_CTL_ON() 0
82#define DHD_TIMER_ON() 0
83#define DHD_HDRS_ON() 0
84#define DHD_BYTES_ON() 0
85#define DHD_INTR_ON() 0
86#define DHD_GLOM_ON() 0
87#define DHD_EVENT_ON() 0
88#define DHD_BTA_ON() 0
89#define DHD_ISCAN_ON() 0
90#endif /* DHD_DEBUG */
91
92#define DHD_LOG(args)
93
94#define DHD_NONE(args)
95extern int dhd_msg_level;
96
97/* Defines msg bits */
98#include <dhdioctl.h>
99
100#endif /* _dhd_dbg_ */
diff --git a/drivers/net/wireless/bcm4329/dhd_linux.c b/drivers/net/wireless/bcm4329/dhd_linux.c
new file mode 100644
index 00000000000..2327ad5fa40
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/dhd_linux.c
@@ -0,0 +1,3451 @@
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-2010, 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,v 1.65.4.9.2.12.2.104.4.40 2011/02/03 19:55:18 Exp $
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/etherdevice.h>
38#include <linux/random.h>
39#include <linux/spinlock.h>
40#include <linux/ethtool.h>
41#include <linux/fcntl.h>
42#include <linux/fs.h>
43#include <linux/inetdevice.h>
44#include <linux/mutex.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#include <wl_iw.h>
61#ifdef CONFIG_HAS_WAKELOCK
62#include <linux/wakelock.h>
63#endif
64#ifdef CUSTOMER_HW2
65#include <linux/platform_device.h>
66#ifdef CONFIG_WIFI_CONTROL_FUNC
67#include <linux/wlan_plat.h>
68static struct wifi_platform_data *wifi_control_data = NULL;
69#endif
70struct semaphore wifi_control_sem;
71
72static struct resource *wifi_irqres = NULL;
73
74int wifi_get_irq_number(unsigned long *irq_flags_ptr)
75{
76 if (wifi_irqres) {
77 *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK;
78 return (int)wifi_irqres->start;
79 }
80#ifdef CUSTOM_OOB_GPIO_NUM
81 return CUSTOM_OOB_GPIO_NUM;
82#else
83 return -1;
84#endif
85}
86
87int wifi_set_carddetect(int on)
88{
89 printk("%s = %d\n", __FUNCTION__, on);
90#ifdef CONFIG_WIFI_CONTROL_FUNC
91 if (wifi_control_data && wifi_control_data->set_carddetect) {
92 wifi_control_data->set_carddetect(on);
93 }
94#endif
95 return 0;
96}
97
98int wifi_set_power(int on, unsigned long msec)
99{
100 printk("%s = %d\n", __FUNCTION__, on);
101#ifdef CONFIG_WIFI_CONTROL_FUNC
102 if (wifi_control_data && wifi_control_data->set_power) {
103 wifi_control_data->set_power(on);
104 }
105#endif
106 if (msec)
107 mdelay(msec);
108 return 0;
109}
110
111int wifi_set_reset(int on, unsigned long msec)
112{
113 DHD_TRACE(("%s = %d\n", __FUNCTION__, on));
114#ifdef CONFIG_WIFI_CONTROL_FUNC
115 if (wifi_control_data && wifi_control_data->set_reset) {
116 wifi_control_data->set_reset(on);
117 }
118#endif
119 if (msec)
120 mdelay(msec);
121 return 0;
122}
123
124int wifi_get_mac_addr(unsigned char *buf)
125{
126 DHD_TRACE(("%s\n", __FUNCTION__));
127 if (!buf)
128 return -EINVAL;
129#ifdef CONFIG_WIFI_CONTROL_FUNC
130 if (wifi_control_data && wifi_control_data->get_mac_addr) {
131 return wifi_control_data->get_mac_addr(buf);
132 }
133#endif
134 return -EOPNOTSUPP;
135}
136
137void *wifi_get_country_code(char *ccode)
138{
139 DHD_TRACE(("%s\n", __FUNCTION__));
140#ifdef CONFIG_WIFI_CONTROL_FUNC
141 if (!ccode)
142 return NULL;
143 if (wifi_control_data && wifi_control_data->get_country_code) {
144 return wifi_control_data->get_country_code(ccode);
145 }
146#endif
147 return NULL;
148}
149
150static int wifi_probe(struct platform_device *pdev)
151{
152#ifdef CONFIG_WIFI_CONTROL_FUNC
153 struct wifi_platform_data *wifi_ctrl =
154 (struct wifi_platform_data *)(pdev->dev.platform_data);
155
156 wifi_control_data = wifi_ctrl;
157#endif
158
159 DHD_TRACE(("## %s\n", __FUNCTION__));
160 wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcm4329_wlan_irq");
161
162 wifi_set_power(1, 0); /* Power On */
163 wifi_set_carddetect(1); /* CardDetect (0->1) */
164
165 up(&wifi_control_sem);
166 return 0;
167}
168
169static int wifi_remove(struct platform_device *pdev)
170{
171#ifdef CONFIG_WIFI_CONTROL_FUNC
172 struct wifi_platform_data *wifi_ctrl =
173 (struct wifi_platform_data *)(pdev->dev.platform_data);
174
175 wifi_control_data = wifi_ctrl;
176#endif
177 DHD_TRACE(("## %s\n", __FUNCTION__));
178 wifi_set_power(0, 0); /* Power Off */
179 wifi_set_carddetect(0); /* CardDetect (1->0) */
180
181 up(&wifi_control_sem);
182 return 0;
183}
184
185static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
186{
187 DHD_TRACE(("##> %s\n", __FUNCTION__));
188#if defined(OOB_INTR_ONLY)
189 bcmsdh_oob_intr_set(0);
190#endif /* (OOB_INTR_ONLY) */
191 return 0;
192}
193static int wifi_resume(struct platform_device *pdev)
194{
195 DHD_TRACE(("##> %s\n", __FUNCTION__));
196#if defined(OOB_INTR_ONLY)
197 bcmsdh_oob_intr_set(1);
198#endif /* (OOB_INTR_ONLY) */
199 return 0;
200}
201
202static struct platform_driver wifi_device = {
203 .probe = wifi_probe,
204 .remove = wifi_remove,
205 .suspend = wifi_suspend,
206 .resume = wifi_resume,
207 .driver = {
208 .name = "bcm4329_wlan",
209 }
210};
211
212int wifi_add_dev(void)
213{
214 DHD_TRACE(("## Calling platform_driver_register\n"));
215 return platform_driver_register(&wifi_device);
216}
217
218void wifi_del_dev(void)
219{
220 DHD_TRACE(("## Unregister platform_driver_register\n"));
221 platform_driver_unregister(&wifi_device);
222}
223#endif /* defined(CUSTOMER_HW2) */
224
225static int dhd_device_event(struct notifier_block *this, unsigned long event,
226 void *ptr);
227
228static struct notifier_block dhd_notifier = {
229 .notifier_call = dhd_device_event
230};
231
232#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
233#include <linux/suspend.h>
234volatile bool dhd_mmc_suspend = FALSE;
235DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait);
236#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
237
238#if defined(OOB_INTR_ONLY)
239extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable);
240#endif /* defined(OOB_INTR_ONLY) */
241#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
242MODULE_LICENSE("GPL v2");
243#endif /* LinuxVer */
244
245#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15)
246const char *
247print_tainted()
248{
249 return "";
250}
251#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */
252
253/* Linux wireless extension support */
254#if defined(CONFIG_WIRELESS_EXT)
255#include <wl_iw.h>
256#endif /* defined(CONFIG_WIRELESS_EXT) */
257
258extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
259
260#if defined(CONFIG_HAS_EARLYSUSPEND)
261#include <linux/earlysuspend.h>
262#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
263
264#ifdef PKT_FILTER_SUPPORT
265extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg);
266extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode);
267#endif
268
269/* Interface control information */
270typedef struct dhd_if {
271 struct dhd_info *info; /* back pointer to dhd_info */
272 /* OS/stack specifics */
273 struct net_device *net;
274 struct net_device_stats stats;
275 int idx; /* iface idx in dongle */
276 int state; /* interface state */
277 uint subunit; /* subunit */
278 uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */
279 bool attached; /* Delayed attachment when unset */
280 bool txflowcontrol; /* Per interface flow control indicator */
281 char name[IFNAMSIZ+1]; /* linux interface name */
282} dhd_if_t;
283
284/* Local private structure (extension of pub) */
285typedef struct dhd_info {
286#if defined(CONFIG_WIRELESS_EXT)
287 wl_iw_t iw; /* wireless extensions state (must be first) */
288#endif /* defined(CONFIG_WIRELESS_EXT) */
289
290 dhd_pub_t pub;
291
292 /* OS/stack specifics */
293 dhd_if_t *iflist[DHD_MAX_IFS];
294
295 struct mutex proto_sem;
296 wait_queue_head_t ioctl_resp_wait;
297 struct timer_list timer;
298 bool wd_timer_valid;
299 struct tasklet_struct tasklet;
300 spinlock_t sdlock;
301 spinlock_t txqlock;
302 spinlock_t dhd_lock;
303
304 /* Thread based operation */
305 bool threads_only;
306 struct mutex sdsem;
307 long watchdog_pid;
308 struct semaphore watchdog_sem;
309 struct completion watchdog_exited;
310 long dpc_pid;
311 struct semaphore dpc_sem;
312 struct completion dpc_exited;
313
314 /* Wakelocks */
315#ifdef CONFIG_HAS_WAKELOCK
316 struct wake_lock wl_wifi; /* Wifi wakelock */
317 struct wake_lock wl_rxwake; /* Wifi rx wakelock */
318#endif
319 spinlock_t wl_lock;
320 int wl_count;
321 int wl_packet;
322
323#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
324 struct mutex wl_start_lock; /* mutex when START called to prevent any other Linux calls */
325#endif
326 /* Thread to issue ioctl for multicast */
327 long sysioc_pid;
328 struct semaphore sysioc_sem;
329 struct completion sysioc_exited;
330 bool set_multicast;
331 bool set_macaddress;
332 struct ether_addr macvalue;
333 wait_queue_head_t ctrl_wait;
334 atomic_t pend_8021x_cnt;
335
336#ifdef CONFIG_HAS_EARLYSUSPEND
337 struct early_suspend early_suspend;
338#endif /* CONFIG_HAS_EARLYSUSPEND */
339} dhd_info_t;
340
341/* Definitions to provide path to the firmware and nvram
342 * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt"
343 */
344char firmware_path[MOD_PARAM_PATHLEN];
345char nvram_path[MOD_PARAM_PATHLEN];
346
347#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
348struct semaphore dhd_registration_sem;
349#define DHD_REGISTRATION_TIMEOUT 24000 /* msec : allowed time to finished dhd registration */
350#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
351/* load firmware and/or nvram values from the filesystem */
352module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0);
353module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0);
354
355/* Error bits */
356module_param(dhd_msg_level, int, 0);
357
358/* Spawn a thread for system ioctls (set mac, set mcast) */
359uint dhd_sysioc = TRUE;
360module_param(dhd_sysioc, uint, 0);
361
362/* Watchdog interval */
363uint dhd_watchdog_ms = 10;
364module_param(dhd_watchdog_ms, uint, 0);
365
366#ifdef DHD_DEBUG
367/* Console poll interval */
368uint dhd_console_ms = 0;
369module_param(dhd_console_ms, uint, 0);
370#endif /* DHD_DEBUG */
371
372/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */
373uint dhd_arp_mode = 0xb;
374module_param(dhd_arp_mode, uint, 0);
375
376/* ARP offload enable */
377uint dhd_arp_enable = TRUE;
378module_param(dhd_arp_enable, uint, 0);
379
380/* Global Pkt filter enable control */
381uint dhd_pkt_filter_enable = TRUE;
382module_param(dhd_pkt_filter_enable, uint, 0);
383
384/* Pkt filter init setup */
385uint dhd_pkt_filter_init = 0;
386module_param(dhd_pkt_filter_init, uint, 0);
387
388/* Pkt filter mode control */
389uint dhd_master_mode = TRUE;
390module_param(dhd_master_mode, uint, 1);
391
392/* Watchdog thread priority, -1 to use kernel timer */
393int dhd_watchdog_prio = 97;
394module_param(dhd_watchdog_prio, int, 0);
395
396/* DPC thread priority, -1 to use tasklet */
397int dhd_dpc_prio = 98;
398module_param(dhd_dpc_prio, int, 0);
399
400/* DPC thread priority, -1 to use tasklet */
401extern int dhd_dongle_memsize;
402module_param(dhd_dongle_memsize, int, 0);
403
404/* Control fw roaming */
405#ifdef CUSTOMER_HW2
406uint dhd_roam = 0;
407#else
408uint dhd_roam = 1;
409#endif
410
411/* Control radio state */
412uint dhd_radio_up = 1;
413
414/* Network inteface name */
415char iface_name[IFNAMSIZ];
416module_param_string(iface_name, iface_name, IFNAMSIZ, 0);
417
418#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
419#define DAEMONIZE(a) daemonize(a); \
420 allow_signal(SIGKILL); \
421 allow_signal(SIGTERM);
422#else /* Linux 2.4 (w/o preemption patch) */
423#define RAISE_RX_SOFTIRQ() \
424 cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
425#define DAEMONIZE(a) daemonize(); \
426 do { if (a) \
427 strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
428 } while (0);
429#endif /* LINUX_VERSION_CODE */
430
431#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
432#define BLOCKABLE() (!in_atomic())
433#else
434#define BLOCKABLE() (!in_interrupt())
435#endif
436
437/* The following are specific to the SDIO dongle */
438
439/* IOCTL response timeout */
440int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT;
441
442/* Idle timeout for backplane clock */
443int dhd_idletime = DHD_IDLETIME_TICKS;
444module_param(dhd_idletime, int, 0);
445
446/* Use polling */
447uint dhd_poll = FALSE;
448module_param(dhd_poll, uint, 0);
449
450/* Use interrupts */
451uint dhd_intr = TRUE;
452module_param(dhd_intr, uint, 0);
453
454/* SDIO Drive Strength (in milliamps) */
455uint dhd_sdiod_drive_strength = 6;
456module_param(dhd_sdiod_drive_strength, uint, 0);
457
458/* Tx/Rx bounds */
459extern uint dhd_txbound;
460extern uint dhd_rxbound;
461module_param(dhd_txbound, uint, 0);
462module_param(dhd_rxbound, uint, 0);
463
464/* Deferred transmits */
465extern uint dhd_deferred_tx;
466module_param(dhd_deferred_tx, uint, 0);
467
468
469
470#ifdef SDTEST
471/* Echo packet generator (pkts/s) */
472uint dhd_pktgen = 0;
473module_param(dhd_pktgen, uint, 0);
474
475/* Echo packet len (0 => sawtooth, max 2040) */
476uint dhd_pktgen_len = 0;
477module_param(dhd_pktgen_len, uint, 0);
478#endif
479
480/* Version string to report */
481#ifdef DHD_DEBUG
482#ifndef SRCBASE
483#define SRCBASE "drivers/net/wireless/bcm4329"
484#endif
485#define DHD_COMPILED "\nCompiled in " SRCBASE
486#else
487#define DHD_COMPILED
488#endif
489
490static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
491#ifdef DHD_DEBUG
492"\nCompiled in " SRCBASE " on " __DATE__ " at " __TIME__
493#endif
494;
495
496
497#if defined(CONFIG_WIRELESS_EXT)
498struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
499#endif /* defined(CONFIG_WIRELESS_EXT) */
500
501static void dhd_dpc(ulong data);
502/* forward decl */
503extern int dhd_wait_pend8021x(struct net_device *dev);
504
505#ifdef TOE
506#ifndef BDC
507#error TOE requires BDC
508#endif /* !BDC */
509static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol);
510static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol);
511#endif /* TOE */
512
513static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
514 wl_event_msg_t *event_ptr, void **data_ptr);
515
516#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
517static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored)
518{
519 int ret = NOTIFY_DONE;
520
521 switch (action) {
522 case PM_HIBERNATION_PREPARE:
523 case PM_SUSPEND_PREPARE:
524 dhd_mmc_suspend = TRUE;
525 ret = NOTIFY_OK;
526 break;
527 case PM_POST_HIBERNATION:
528 case PM_POST_SUSPEND:
529 dhd_mmc_suspend = FALSE;
530 ret = NOTIFY_OK;
531 break;
532 }
533 smp_mb();
534 return ret;
535}
536
537static struct notifier_block dhd_sleep_pm_notifier = {
538 .notifier_call = dhd_sleep_pm_callback,
539 .priority = 0
540};
541extern int register_pm_notifier(struct notifier_block *nb);
542extern int unregister_pm_notifier(struct notifier_block *nb);
543#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
544
545static void dhd_set_packet_filter(int value, dhd_pub_t *dhd)
546{
547#ifdef PKT_FILTER_SUPPORT
548 DHD_TRACE(("%s: %d\n", __FUNCTION__, value));
549 /* 1 - Enable packet filter, only allow unicast packet to send up */
550 /* 0 - Disable packet filter */
551 if (dhd_pkt_filter_enable) {
552 int i;
553
554 for (i = 0; i < dhd->pktfilter_count; i++) {
555 dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]);
556 dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i],
557 value, dhd_master_mode);
558 }
559 }
560#endif
561}
562
563
564
565#if defined(CONFIG_HAS_EARLYSUSPEND)
566static int dhd_set_suspend(int value, dhd_pub_t *dhd)
567{
568 int power_mode = PM_MAX;
569 /* wl_pkt_filter_enable_t enable_parm; */
570 char iovbuf[32];
571 int bcn_li_dtim = 3;
572#ifdef CUSTOMER_HW2
573 uint roamvar = 1;
574#endif /* CUSTOMER_HW2 */
575
576 DHD_TRACE(("%s: enter, value = %d in_suspend = %d\n",
577 __FUNCTION__, value, dhd->in_suspend));
578
579 if (dhd && dhd->up) {
580 if (value && dhd->in_suspend) {
581
582 /* Kernel suspended */
583 DHD_TRACE(("%s: force extra Suspend setting \n", __FUNCTION__));
584
585 dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM,
586 (char *)&power_mode, sizeof(power_mode));
587
588 /* Enable packet filter, only allow unicast packet to send up */
589 dhd_set_packet_filter(1, dhd);
590
591 /* if dtim skip setup as default force it to wake each thrid dtim
592 * for better power saving.
593 * Note that side effect is chance to miss BC/MC packet
594 */
595 bcn_li_dtim = dhd_get_dtim_skip(dhd);
596 bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
597 4, iovbuf, sizeof(iovbuf));
598 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
599#ifdef CUSTOMER_HW2
600 /* Disable build-in roaming during suspend */
601 bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
602 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
603#endif /* CUSTOMER_HW2 */
604
605 } else {
606
607 /* Kernel resumed */
608 DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__));
609
610 power_mode = PM_FAST;
611 dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode,
612 sizeof(power_mode));
613
614 /* disable pkt filter */
615 dhd_set_packet_filter(0, dhd);
616
617 /* restore pre-suspend setting for dtim_skip */
618 bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip,
619 4, iovbuf, sizeof(iovbuf));
620
621 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
622#ifdef CUSTOMER_HW2
623 roamvar = dhd_roam;
624 bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf));
625 dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
626#endif /* CUSTOMER_HW2 */
627 }
628 }
629
630 return 0;
631}
632
633static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val)
634{
635 dhd_pub_t *dhdp = &dhd->pub;
636
637 dhd_os_wake_lock(dhdp);
638 dhd_os_proto_block(dhdp);
639 /* Set flag when early suspend was called */
640 dhdp->in_suspend = val;
641 if (!dhdp->suspend_disable_flag)
642 dhd_set_suspend(val, dhdp);
643 dhd_os_proto_unblock(dhdp);
644 dhd_os_wake_unlock(dhdp);
645}
646
647static void dhd_early_suspend(struct early_suspend *h)
648{
649 struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
650
651 DHD_TRACE(("%s: enter\n", __FUNCTION__));
652
653 if (dhd)
654 dhd_suspend_resume_helper(dhd, 1);
655}
656
657static void dhd_late_resume(struct early_suspend *h)
658{
659 struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend);
660
661 DHD_TRACE(("%s: enter\n", __FUNCTION__));
662
663 if (dhd)
664 dhd_suspend_resume_helper(dhd, 0);
665}
666#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
667
668/*
669 * Generalized timeout mechanism. Uses spin sleep with exponential back-off until
670 * the sleep time reaches one jiffy, then switches over to task delay. Usage:
671 *
672 * dhd_timeout_start(&tmo, usec);
673 * while (!dhd_timeout_expired(&tmo))
674 * if (poll_something())
675 * break;
676 * if (dhd_timeout_expired(&tmo))
677 * fatal();
678 */
679
680void
681dhd_timeout_start(dhd_timeout_t *tmo, uint usec)
682{
683 tmo->limit = usec;
684 tmo->increment = 0;
685 tmo->elapsed = 0;
686 tmo->tick = 1000000 / HZ;
687}
688
689int
690dhd_timeout_expired(dhd_timeout_t *tmo)
691{
692 /* Does nothing the first call */
693 if (tmo->increment == 0) {
694 tmo->increment = 1;
695 return 0;
696 }
697
698 if (tmo->elapsed >= tmo->limit)
699 return 1;
700
701 /* Add the delay that's about to take place */
702 tmo->elapsed += tmo->increment;
703
704 if (tmo->increment < tmo->tick) {
705 OSL_DELAY(tmo->increment);
706 tmo->increment *= 2;
707 if (tmo->increment > tmo->tick)
708 tmo->increment = tmo->tick;
709 } else {
710 wait_queue_head_t delay_wait;
711 DECLARE_WAITQUEUE(wait, current);
712 int pending;
713 init_waitqueue_head(&delay_wait);
714 add_wait_queue(&delay_wait, &wait);
715 set_current_state(TASK_INTERRUPTIBLE);
716 schedule_timeout(1);
717 pending = signal_pending(current);
718 remove_wait_queue(&delay_wait, &wait);
719 set_current_state(TASK_RUNNING);
720 if (pending)
721 return 1; /* Interrupted */
722 }
723
724 return 0;
725}
726
727static int
728dhd_net2idx(dhd_info_t *dhd, struct net_device *net)
729{
730 int i = 0;
731
732 ASSERT(dhd);
733 while (i < DHD_MAX_IFS) {
734 if (dhd->iflist[i] && (dhd->iflist[i]->net == net))
735 return i;
736 i++;
737 }
738
739 return DHD_BAD_IF;
740}
741
742int
743dhd_ifname2idx(dhd_info_t *dhd, char *name)
744{
745 int i = DHD_MAX_IFS;
746
747 ASSERT(dhd);
748
749 if (name == NULL || *name == '\0')
750 return 0;
751
752 while (--i > 0)
753 if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ))
754 break;
755
756 DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name));
757
758 return i; /* default - the primary interface */
759}
760
761char *
762dhd_ifname(dhd_pub_t *dhdp, int ifidx)
763{
764 dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
765
766 ASSERT(dhd);
767
768 if (ifidx < 0 || ifidx >= DHD_MAX_IFS) {
769 DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx));
770 return "<if_bad>";
771 }
772
773 if (dhd->iflist[ifidx] == NULL) {
774 DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx));
775 return "<if_null>";
776 }
777
778 if (dhd->iflist[ifidx]->net)
779 return dhd->iflist[ifidx]->net->name;
780
781 return "<if_none>";
782}
783
784static void
785_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx)
786{
787 struct net_device *dev;
788#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
789 struct netdev_hw_addr *ha;
790#else
791 struct dev_mc_list *mclist;
792#endif
793 uint32 allmulti, cnt;
794
795 wl_ioctl_t ioc;
796 char *buf, *bufp;
797 uint buflen;
798 int ret;
799
800 ASSERT(dhd && dhd->iflist[ifidx]);
801 dev = dhd->iflist[ifidx]->net;
802
803 NETIF_ADDR_LOCK(dev);
804#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
805 cnt = netdev_mc_count(dev);
806#else
807 cnt = dev->mc_count;
808#endif
809 NETIF_ADDR_UNLOCK(dev);
810
811 /* Determine initial value of allmulti flag */
812 allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE;
813
814 /* Send down the multicast list first. */
815 buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN);
816 if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) {
817 DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n",
818 dhd_ifname(&dhd->pub, ifidx), cnt));
819 return;
820 }
821
822 strcpy(bufp, "mcast_list");
823 bufp += strlen("mcast_list") + 1;
824
825 cnt = htol32(cnt);
826 memcpy(bufp, &cnt, sizeof(cnt));
827 bufp += sizeof(cnt);
828
829 NETIF_ADDR_LOCK(dev);
830#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
831 netdev_for_each_mc_addr(ha, dev) {
832 if (!cnt)
833 break;
834 memcpy(bufp, ha->addr, ETHER_ADDR_LEN);
835 bufp += ETHER_ADDR_LEN;
836 cnt--;
837 }
838#else
839 for (mclist = dev->mc_list; (mclist && (cnt > 0)); cnt--, mclist = mclist->next) {
840 memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN);
841 bufp += ETHER_ADDR_LEN;
842 }
843#endif
844 NETIF_ADDR_UNLOCK(dev);
845
846 memset(&ioc, 0, sizeof(ioc));
847 ioc.cmd = WLC_SET_VAR;
848 ioc.buf = buf;
849 ioc.len = buflen;
850 ioc.set = TRUE;
851
852 ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
853 if (ret < 0) {
854 DHD_ERROR(("%s: set mcast_list failed, cnt %d\n",
855 dhd_ifname(&dhd->pub, ifidx), cnt));
856 allmulti = cnt ? TRUE : allmulti;
857 }
858
859 MFREE(dhd->pub.osh, buf, buflen);
860
861 /* Now send the allmulti setting. This is based on the setting in the
862 * net_device flags, but might be modified above to be turned on if we
863 * were trying to set some addresses and dongle rejected it...
864 */
865
866 buflen = sizeof("allmulti") + sizeof(allmulti);
867 if (!(buf = MALLOC(dhd->pub.osh, buflen))) {
868 DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx)));
869 return;
870 }
871 allmulti = htol32(allmulti);
872
873 if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) {
874 DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
875 dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen));
876 MFREE(dhd->pub.osh, buf, buflen);
877 return;
878 }
879
880
881 memset(&ioc, 0, sizeof(ioc));
882 ioc.cmd = WLC_SET_VAR;
883 ioc.buf = buf;
884 ioc.len = buflen;
885 ioc.set = TRUE;
886
887 ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
888 if (ret < 0) {
889 DHD_ERROR(("%s: set allmulti %d failed\n",
890 dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
891 }
892
893 MFREE(dhd->pub.osh, buf, buflen);
894
895 /* Finally, pick up the PROMISC flag as well, like the NIC driver does */
896
897 allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE;
898 allmulti = htol32(allmulti);
899
900 memset(&ioc, 0, sizeof(ioc));
901 ioc.cmd = WLC_SET_PROMISC;
902 ioc.buf = &allmulti;
903 ioc.len = sizeof(allmulti);
904 ioc.set = TRUE;
905
906 ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
907 if (ret < 0) {
908 DHD_ERROR(("%s: set promisc %d failed\n",
909 dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti)));
910 }
911}
912
913static int
914_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr)
915{
916 char buf[32];
917 wl_ioctl_t ioc;
918 int ret;
919
920 DHD_TRACE(("%s enter\n", __FUNCTION__));
921 if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) {
922 DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx)));
923 return -1;
924 }
925 memset(&ioc, 0, sizeof(ioc));
926 ioc.cmd = WLC_SET_VAR;
927 ioc.buf = buf;
928 ioc.len = 32;
929 ioc.set = TRUE;
930
931 ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len);
932 if (ret < 0) {
933 DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx)));
934 } else {
935 memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN);
936 }
937
938 return ret;
939}
940
941#ifdef SOFTAP
942extern struct net_device *ap_net_dev;
943/* semaphore that the soft AP CODE waits on */
944extern struct semaphore ap_eth_sema;
945#endif
946
947static void
948dhd_op_if(dhd_if_t *ifp)
949{
950 dhd_info_t *dhd;
951 int ret = 0, err = 0;
952#ifdef SOFTAP
953 unsigned long flags;
954#endif
955
956 ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */
957
958 dhd = ifp->info;
959
960 DHD_TRACE(("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state));
961
962 switch (ifp->state) {
963 case WLC_E_IF_ADD:
964 /*
965 * Delete the existing interface before overwriting it
966 * in case we missed the WLC_E_IF_DEL event.
967 */
968 if (ifp->net != NULL) {
969 DHD_ERROR(("%s: ERROR: netdev:%s already exists, try free & unregister \n",
970 __FUNCTION__, ifp->net->name));
971 netif_stop_queue(ifp->net);
972 unregister_netdev(ifp->net);
973 free_netdev(ifp->net);
974 }
975 /* Allocate etherdev, including space for private structure */
976 if (!(ifp->net = alloc_etherdev(sizeof(dhd)))) {
977 DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
978 ret = -ENOMEM;
979 }
980 if (ret == 0) {
981 strcpy(ifp->net->name, ifp->name);
982 memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd));
983 if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) {
984 DHD_ERROR(("%s: dhd_net_attach failed, err %d\n",
985 __FUNCTION__, err));
986 ret = -EOPNOTSUPP;
987 } else {
988#ifdef SOFTAP
989 flags = dhd_os_spin_lock(&dhd->pub);
990 /* save ptr to wl0.1 netdev for use in wl_iw.c */
991 ap_net_dev = ifp->net;
992 /* signal to the SOFTAP 'sleeper' thread, wl0.1 is ready */
993 up(&ap_eth_sema);
994 dhd_os_spin_unlock(&dhd->pub, flags);
995#endif
996 DHD_TRACE(("\n ==== pid:%x, net_device for if:%s created ===\n\n",
997 current->pid, ifp->net->name));
998 ifp->state = 0;
999 }
1000 }
1001 break;
1002 case WLC_E_IF_DEL:
1003 if (ifp->net != NULL) {
1004 DHD_TRACE(("\n%s: got 'WLC_E_IF_DEL' state\n", __FUNCTION__));
1005 netif_stop_queue(ifp->net);
1006 unregister_netdev(ifp->net);
1007 ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */
1008 }
1009 break;
1010 default:
1011 DHD_ERROR(("%s: bad op %d\n", __FUNCTION__, ifp->state));
1012 ASSERT(!ifp->state);
1013 break;
1014 }
1015
1016 if (ret < 0) {
1017 if (ifp->net) {
1018 free_netdev(ifp->net);
1019 }
1020 dhd->iflist[ifp->idx] = NULL;
1021 MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
1022#ifdef SOFTAP
1023 flags = dhd_os_spin_lock(&dhd->pub);
1024 if (ifp->net == ap_net_dev)
1025 ap_net_dev = NULL; /* NULL SOFTAP global as well */
1026 dhd_os_spin_unlock(&dhd->pub, flags);
1027#endif /* SOFTAP */
1028 }
1029}
1030
1031static int
1032_dhd_sysioc_thread(void *data)
1033{
1034 dhd_info_t *dhd = (dhd_info_t *)data;
1035 int i;
1036#ifdef SOFTAP
1037 bool in_ap = FALSE;
1038 unsigned long flags;
1039#endif
1040
1041 DAEMONIZE("dhd_sysioc");
1042
1043 while (down_interruptible(&dhd->sysioc_sem) == 0) {
1044 dhd_os_start_lock(&dhd->pub);
1045 dhd_os_wake_lock(&dhd->pub);
1046 for (i = 0; i < DHD_MAX_IFS; i++) {
1047 if (dhd->iflist[i]) {
1048 DHD_TRACE(("%s: interface %d\n",__FUNCTION__, i));
1049#ifdef SOFTAP
1050 flags = dhd_os_spin_lock(&dhd->pub);
1051 in_ap = (ap_net_dev != NULL);
1052 dhd_os_spin_unlock(&dhd->pub, flags);
1053#endif /* SOFTAP */
1054 if (dhd->iflist[i]->state)
1055 dhd_op_if(dhd->iflist[i]);
1056#ifdef SOFTAP
1057 if (dhd->iflist[i] == NULL) {
1058 DHD_TRACE(("%s: interface %d just been removed!\n\n", __FUNCTION__, i));
1059 continue;
1060 }
1061
1062 if (in_ap && dhd->set_macaddress) {
1063 DHD_TRACE(("attempt to set MAC for %s in AP Mode blocked.\n", dhd->iflist[i]->net->name));
1064 dhd->set_macaddress = FALSE;
1065 continue;
1066 }
1067
1068 if (in_ap && dhd->set_multicast) {
1069 DHD_TRACE(("attempt to set MULTICAST list for %s in AP Mode blocked.\n", dhd->iflist[i]->net->name));
1070 dhd->set_multicast = FALSE;
1071 continue;
1072 }
1073#endif /* SOFTAP */
1074 if (dhd->set_multicast) {
1075 dhd->set_multicast = FALSE;
1076 _dhd_set_multicast_list(dhd, i);
1077 }
1078 if (dhd->set_macaddress) {
1079 dhd->set_macaddress = FALSE;
1080 _dhd_set_mac_address(dhd, i, &dhd->macvalue);
1081 }
1082 }
1083 }
1084 dhd_os_wake_unlock(&dhd->pub);
1085 dhd_os_start_unlock(&dhd->pub);
1086 }
1087 DHD_TRACE(("%s: stopped\n",__FUNCTION__));
1088 complete_and_exit(&dhd->sysioc_exited, 0);
1089}
1090
1091static int
1092dhd_set_mac_address(struct net_device *dev, void *addr)
1093{
1094 int ret = 0;
1095
1096 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
1097 struct sockaddr *sa = (struct sockaddr *)addr;
1098 int ifidx;
1099
1100 DHD_TRACE(("%s: Enter\n",__FUNCTION__));
1101 ifidx = dhd_net2idx(dhd, dev);
1102 if (ifidx == DHD_BAD_IF)
1103 return -1;
1104
1105 ASSERT(dhd->sysioc_pid >= 0);
1106 memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN);
1107 dhd->set_macaddress = TRUE;
1108 up(&dhd->sysioc_sem);
1109
1110 return ret;
1111}
1112
1113static void
1114dhd_set_multicast_list(struct net_device *dev)
1115{
1116 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
1117 int ifidx;
1118
1119 DHD_TRACE(("%s: Enter\n",__FUNCTION__));
1120 ifidx = dhd_net2idx(dhd, dev);
1121 if (ifidx == DHD_BAD_IF)
1122 return;
1123
1124 ASSERT(dhd->sysioc_pid >= 0);
1125 dhd->set_multicast = TRUE;
1126 up(&dhd->sysioc_sem);
1127}
1128
1129int
1130dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf)
1131{
1132 int ret;
1133 dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
1134
1135 /* Reject if down */
1136 if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) {
1137 return -ENODEV;
1138 }
1139
1140 /* Update multicast statistic */
1141 if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_ADDR_LEN) {
1142 uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf);
1143 struct ether_header *eh = (struct ether_header *)pktdata;
1144
1145 if (ETHER_ISMULTI(eh->ether_dhost))
1146 dhdp->tx_multicast++;
1147 if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X)
1148 atomic_inc(&dhd->pend_8021x_cnt);
1149 }
1150
1151 /* Look into the packet and update the packet priority */
1152 if ((PKTPRIO(pktbuf) == 0))
1153 pktsetprio(pktbuf, FALSE);
1154
1155 /* If the protocol uses a data header, apply it */
1156 dhd_prot_hdrpush(dhdp, ifidx, pktbuf);
1157
1158 /* Use bus module to send data frame */
1159#ifdef BCMDBUS
1160 ret = dbus_send_pkt(dhdp->dbus, pktbuf, NULL /* pktinfo */);
1161#else
1162 ret = dhd_bus_txdata(dhdp->bus, pktbuf);
1163#endif /* BCMDBUS */
1164
1165 return ret;
1166}
1167
1168static int
1169dhd_start_xmit(struct sk_buff *skb, struct net_device *net)
1170{
1171 int ret;
1172 void *pktbuf;
1173 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
1174 int ifidx;
1175
1176 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1177
1178 dhd_os_wake_lock(&dhd->pub);
1179
1180 /* Reject if down */
1181 if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) {
1182 DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d\n",
1183 __FUNCTION__, dhd->pub.up, dhd->pub.busstate));
1184 netif_stop_queue(net);
1185 /* Send Event when bus down detected during data session */
1186 if (dhd->pub.busstate == DHD_BUS_DOWN) {
1187 DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__));
1188 net_os_send_hang_message(net);
1189 }
1190 dhd_os_wake_unlock(&dhd->pub);
1191 return -ENODEV;
1192 }
1193
1194 ifidx = dhd_net2idx(dhd, net);
1195 if (ifidx == DHD_BAD_IF) {
1196 DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx));
1197 netif_stop_queue(net);
1198 dhd_os_wake_unlock(&dhd->pub);
1199 return -ENODEV;
1200 }
1201
1202 /* Make sure there's enough room for any header */
1203 if (skb_headroom(skb) < dhd->pub.hdrlen) {
1204 struct sk_buff *skb2;
1205
1206 DHD_INFO(("%s: insufficient headroom\n",
1207 dhd_ifname(&dhd->pub, ifidx)));
1208 dhd->pub.tx_realloc++;
1209 skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen);
1210 dev_kfree_skb(skb);
1211 if ((skb = skb2) == NULL) {
1212 DHD_ERROR(("%s: skb_realloc_headroom failed\n",
1213 dhd_ifname(&dhd->pub, ifidx)));
1214 ret = -ENOMEM;
1215 goto done;
1216 }
1217 }
1218
1219 /* Convert to packet */
1220 if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) {
1221 DHD_ERROR(("%s: PKTFRMNATIVE failed\n",
1222 dhd_ifname(&dhd->pub, ifidx)));
1223 dev_kfree_skb_any(skb);
1224 ret = -ENOMEM;
1225 goto done;
1226 }
1227
1228 ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf);
1229
1230done:
1231 if (ret)
1232 dhd->pub.dstats.tx_dropped++;
1233 else
1234 dhd->pub.tx_packets++;
1235
1236 dhd_os_wake_unlock(&dhd->pub);
1237
1238 /* Return ok: we always eat the packet */
1239 return 0;
1240}
1241
1242void
1243dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state)
1244{
1245 struct net_device *net;
1246 dhd_info_t *dhd = dhdp->info;
1247
1248 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1249
1250 dhdp->txoff = state;
1251 ASSERT(dhd && dhd->iflist[ifidx]);
1252 net = dhd->iflist[ifidx]->net;
1253 if (state == ON)
1254 netif_stop_queue(net);
1255 else
1256 netif_wake_queue(net);
1257}
1258
1259void
1260dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt)
1261{
1262 dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
1263 struct sk_buff *skb;
1264 uchar *eth;
1265 uint len;
1266 void * data, *pnext, *save_pktbuf;
1267 int i;
1268 dhd_if_t *ifp;
1269 wl_event_msg_t event;
1270
1271 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1272
1273 save_pktbuf = pktbuf;
1274
1275 for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) {
1276
1277 pnext = PKTNEXT(dhdp->osh, pktbuf);
1278 PKTSETNEXT(wl->sh.osh, pktbuf, NULL);
1279
1280
1281 skb = PKTTONATIVE(dhdp->osh, pktbuf);
1282
1283 /* Get the protocol, maintain skb around eth_type_trans()
1284 * The main reason for this hack is for the limitation of
1285 * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len'
1286 * to perform skb_pull inside vs ETH_HLEN. Since to avoid
1287 * coping of the packet coming from the network stack to add
1288 * BDC, Hardware header etc, during network interface registration
1289 * we set the 'net->hard_header_len' to ETH_HLEN + extra space required
1290 * for BDC, Hardware header etc. and not just the ETH_HLEN
1291 */
1292 eth = skb->data;
1293 len = skb->len;
1294
1295 ifp = dhd->iflist[ifidx];
1296 if (ifp == NULL)
1297 ifp = dhd->iflist[0];
1298
1299 ASSERT(ifp);
1300 skb->dev = ifp->net;
1301 skb->protocol = eth_type_trans(skb, skb->dev);
1302
1303 if (skb->pkt_type == PACKET_MULTICAST) {
1304 dhd->pub.rx_multicast++;
1305 }
1306
1307 skb->data = eth;
1308 skb->len = len;
1309
1310 /* Strip header, count, deliver upward */
1311 skb_pull(skb, ETH_HLEN);
1312
1313 /* Process special event packets and then discard them */
1314 if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM)
1315 dhd_wl_host_event(dhd, &ifidx,
1316#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1317 skb->mac_header,
1318#else
1319 skb->mac.raw,
1320#endif
1321 &event,
1322 &data);
1323
1324 ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]);
1325 if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state)
1326 ifp = dhd->iflist[ifidx];
1327
1328 if (ifp->net)
1329 ifp->net->last_rx = jiffies;
1330
1331 dhdp->dstats.rx_bytes += skb->len;
1332 dhdp->rx_packets++; /* Local count */
1333
1334 if (in_interrupt()) {
1335 netif_rx(skb);
1336 } else {
1337 /* If the receive is not processed inside an ISR,
1338 * the softirqd must be woken explicitly to service
1339 * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled
1340 * by netif_rx_ni(), but in earlier kernels, we need
1341 * to do it manually.
1342 */
1343#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1344 netif_rx_ni(skb);
1345#else
1346 ulong flags;
1347 netif_rx(skb);
1348 local_irq_save(flags);
1349 RAISE_RX_SOFTIRQ();
1350 local_irq_restore(flags);
1351#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */
1352 }
1353 }
1354 dhd_os_wake_lock_timeout_enable(dhdp);
1355}
1356
1357void
1358dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx)
1359{
1360 /* Linux version has nothing to do */
1361 return;
1362}
1363
1364void
1365dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success)
1366{
1367 uint ifidx;
1368 dhd_info_t *dhd = (dhd_info_t *)(dhdp->info);
1369 struct ether_header *eh;
1370 uint16 type;
1371
1372 dhd_prot_hdrpull(dhdp, &ifidx, txp);
1373
1374 eh = (struct ether_header *)PKTDATA(dhdp->osh, txp);
1375 type = ntoh16(eh->ether_type);
1376
1377 if (type == ETHER_TYPE_802_1X)
1378 atomic_dec(&dhd->pend_8021x_cnt);
1379
1380}
1381
1382static struct net_device_stats *
1383dhd_get_stats(struct net_device *net)
1384{
1385 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
1386 dhd_if_t *ifp;
1387 int ifidx;
1388
1389 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1390
1391 ifidx = dhd_net2idx(dhd, net);
1392 if (ifidx == DHD_BAD_IF)
1393 return NULL;
1394
1395 ifp = dhd->iflist[ifidx];
1396 ASSERT(dhd && ifp);
1397
1398 if (dhd->pub.up) {
1399 /* Use the protocol to get dongle stats */
1400 dhd_prot_dstats(&dhd->pub);
1401 }
1402
1403 /* Copy dongle stats to net device stats */
1404 ifp->stats.rx_packets = dhd->pub.dstats.rx_packets;
1405 ifp->stats.tx_packets = dhd->pub.dstats.tx_packets;
1406 ifp->stats.rx_bytes = dhd->pub.dstats.rx_bytes;
1407 ifp->stats.tx_bytes = dhd->pub.dstats.tx_bytes;
1408 ifp->stats.rx_errors = dhd->pub.dstats.rx_errors;
1409 ifp->stats.tx_errors = dhd->pub.dstats.tx_errors;
1410 ifp->stats.rx_dropped = dhd->pub.dstats.rx_dropped;
1411 ifp->stats.tx_dropped = dhd->pub.dstats.tx_dropped;
1412 ifp->stats.multicast = dhd->pub.dstats.multicast;
1413
1414 return &ifp->stats;
1415}
1416
1417static int
1418dhd_watchdog_thread(void *data)
1419{
1420 dhd_info_t *dhd = (dhd_info_t *)data;
1421
1422 /* This thread doesn't need any user-level access,
1423 * so get rid of all our resources
1424 */
1425#ifdef DHD_SCHED
1426 if (dhd_watchdog_prio > 0) {
1427 struct sched_param param;
1428 param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)?
1429 dhd_watchdog_prio:(MAX_RT_PRIO-1);
1430 setScheduler(current, SCHED_FIFO, &param);
1431 }
1432#endif /* DHD_SCHED */
1433
1434 DAEMONIZE("dhd_watchdog");
1435
1436 /* Run until signal received */
1437 while (1) {
1438 if (down_interruptible (&dhd->watchdog_sem) == 0) {
1439 dhd_os_sdlock(&dhd->pub);
1440 if (dhd->pub.dongle_reset == FALSE) {
1441 DHD_TIMER(("%s:\n", __FUNCTION__));
1442 /* Call the bus module watchdog */
1443 dhd_bus_watchdog(&dhd->pub);
1444
1445 /* Count the tick for reference */
1446 dhd->pub.tickcnt++;
1447
1448 /* Reschedule the watchdog */
1449 if (dhd->wd_timer_valid)
1450 mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
1451 }
1452 dhd_os_sdunlock(&dhd->pub);
1453 dhd_os_wake_unlock(&dhd->pub);
1454 } else {
1455 break;
1456 }
1457 }
1458
1459 complete_and_exit(&dhd->watchdog_exited, 0);
1460}
1461
1462static void
1463dhd_watchdog(ulong data)
1464{
1465 dhd_info_t *dhd = (dhd_info_t *)data;
1466
1467 dhd_os_wake_lock(&dhd->pub);
1468 if (dhd->pub.dongle_reset) {
1469 dhd_os_wake_unlock(&dhd->pub);
1470 return;
1471 }
1472
1473 if (dhd->watchdog_pid >= 0) {
1474 up(&dhd->watchdog_sem);
1475 return;
1476 }
1477
1478 dhd_os_sdlock(&dhd->pub);
1479 /* Call the bus module watchdog */
1480 dhd_bus_watchdog(&dhd->pub);
1481
1482 /* Count the tick for reference */
1483 dhd->pub.tickcnt++;
1484
1485 /* Reschedule the watchdog */
1486 if (dhd->wd_timer_valid)
1487 mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
1488 dhd_os_sdunlock(&dhd->pub);
1489 dhd_os_wake_unlock(&dhd->pub);
1490}
1491
1492static int
1493dhd_dpc_thread(void *data)
1494{
1495 dhd_info_t *dhd = (dhd_info_t *)data;
1496
1497 /* This thread doesn't need any user-level access,
1498 * so get rid of all our resources
1499 */
1500#ifdef DHD_SCHED
1501 if (dhd_dpc_prio > 0)
1502 {
1503 struct sched_param param;
1504 param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1);
1505 setScheduler(current, SCHED_FIFO, &param);
1506 }
1507#endif /* DHD_SCHED */
1508
1509 DAEMONIZE("dhd_dpc");
1510
1511 /* Run until signal received */
1512 while (1) {
1513 if (down_interruptible(&dhd->dpc_sem) == 0) {
1514 /* Call bus dpc unless it indicated down (then clean stop) */
1515 if (dhd->pub.busstate != DHD_BUS_DOWN) {
1516 if (dhd_bus_dpc(dhd->pub.bus)) {
1517 up(&dhd->dpc_sem);
1518 }
1519 else {
1520 dhd_os_wake_unlock(&dhd->pub);
1521 }
1522 } else {
1523 if (dhd->pub.up)
1524 dhd_bus_stop(dhd->pub.bus, TRUE);
1525 dhd_os_wake_unlock(&dhd->pub);
1526 }
1527 }
1528 else
1529 break;
1530 }
1531
1532 complete_and_exit(&dhd->dpc_exited, 0);
1533}
1534
1535static void
1536dhd_dpc(ulong data)
1537{
1538 dhd_info_t *dhd;
1539
1540 dhd = (dhd_info_t *)data;
1541
1542 /* Call bus dpc unless it indicated down (then clean stop) */
1543 if (dhd->pub.busstate != DHD_BUS_DOWN) {
1544 if (dhd_bus_dpc(dhd->pub.bus))
1545 tasklet_schedule(&dhd->tasklet);
1546 } else {
1547 dhd_bus_stop(dhd->pub.bus, TRUE);
1548 }
1549}
1550
1551void
1552dhd_sched_dpc(dhd_pub_t *dhdp)
1553{
1554 dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
1555
1556 dhd_os_wake_lock(dhdp);
1557 if (dhd->dpc_pid >= 0) {
1558 up(&dhd->dpc_sem);
1559 return;
1560 }
1561
1562 tasklet_schedule(&dhd->tasklet);
1563}
1564
1565#ifdef TOE
1566/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */
1567static int
1568dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol)
1569{
1570 wl_ioctl_t ioc;
1571 char buf[32];
1572 int ret;
1573
1574 memset(&ioc, 0, sizeof(ioc));
1575
1576 ioc.cmd = WLC_GET_VAR;
1577 ioc.buf = buf;
1578 ioc.len = (uint)sizeof(buf);
1579 ioc.set = FALSE;
1580
1581 strcpy(buf, "toe_ol");
1582 if ((ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
1583 /* Check for older dongle image that doesn't support toe_ol */
1584 if (ret == -EIO) {
1585 DHD_ERROR(("%s: toe not supported by device\n",
1586 dhd_ifname(&dhd->pub, ifidx)));
1587 return -EOPNOTSUPP;
1588 }
1589
1590 DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
1591 return ret;
1592 }
1593
1594 memcpy(toe_ol, buf, sizeof(uint32));
1595 return 0;
1596}
1597
1598/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */
1599static int
1600dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol)
1601{
1602 wl_ioctl_t ioc;
1603 char buf[32];
1604 int toe, ret;
1605
1606 memset(&ioc, 0, sizeof(ioc));
1607
1608 ioc.cmd = WLC_SET_VAR;
1609 ioc.buf = buf;
1610 ioc.len = (uint)sizeof(buf);
1611 ioc.set = TRUE;
1612
1613 /* Set toe_ol as requested */
1614
1615 strcpy(buf, "toe_ol");
1616 memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32));
1617
1618 if ((ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
1619 DHD_ERROR(("%s: could not set toe_ol: ret=%d\n",
1620 dhd_ifname(&dhd->pub, ifidx), ret));
1621 return ret;
1622 }
1623
1624 /* Enable toe globally only if any components are enabled. */
1625
1626 toe = (toe_ol != 0);
1627
1628 strcpy(buf, "toe");
1629 memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32));
1630
1631 if ((ret = dhd_prot_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) {
1632 DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret));
1633 return ret;
1634 }
1635
1636 return 0;
1637}
1638#endif /* TOE */
1639
1640#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1641static void dhd_ethtool_get_drvinfo(struct net_device *net,
1642 struct ethtool_drvinfo *info)
1643{
1644 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
1645
1646 sprintf(info->driver, "wl");
1647 sprintf(info->version, "%lu", dhd->pub.drv_version);
1648}
1649
1650struct ethtool_ops dhd_ethtool_ops = {
1651 .get_drvinfo = dhd_ethtool_get_drvinfo
1652};
1653#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
1654
1655
1656#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
1657static int
1658dhd_ethtool(dhd_info_t *dhd, void *uaddr)
1659{
1660 struct ethtool_drvinfo info;
1661 char drvname[sizeof(info.driver)];
1662 uint32 cmd;
1663#ifdef TOE
1664 struct ethtool_value edata;
1665 uint32 toe_cmpnt, csum_dir;
1666 int ret;
1667#endif
1668
1669 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1670
1671 /* all ethtool calls start with a cmd word */
1672 if (copy_from_user(&cmd, uaddr, sizeof (uint32)))
1673 return -EFAULT;
1674
1675 switch (cmd) {
1676 case ETHTOOL_GDRVINFO:
1677 /* Copy out any request driver name */
1678 if (copy_from_user(&info, uaddr, sizeof(info)))
1679 return -EFAULT;
1680 strncpy(drvname, info.driver, sizeof(info.driver));
1681 drvname[sizeof(info.driver)-1] = '\0';
1682
1683 /* clear struct for return */
1684 memset(&info, 0, sizeof(info));
1685 info.cmd = cmd;
1686
1687 /* if dhd requested, identify ourselves */
1688 if (strcmp(drvname, "?dhd") == 0) {
1689 sprintf(info.driver, "dhd");
1690 strcpy(info.version, EPI_VERSION_STR);
1691 }
1692
1693 /* otherwise, require dongle to be up */
1694 else if (!dhd->pub.up) {
1695 DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__));
1696 return -ENODEV;
1697 }
1698
1699 /* finally, report dongle driver type */
1700 else if (dhd->pub.iswl)
1701 sprintf(info.driver, "wl");
1702 else
1703 sprintf(info.driver, "xx");
1704
1705 sprintf(info.version, "%lu", dhd->pub.drv_version);
1706 if (copy_to_user(uaddr, &info, sizeof(info)))
1707 return -EFAULT;
1708 DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__,
1709 (int)sizeof(drvname), drvname, info.driver));
1710 break;
1711
1712#ifdef TOE
1713 /* Get toe offload components from dongle */
1714 case ETHTOOL_GRXCSUM:
1715 case ETHTOOL_GTXCSUM:
1716 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
1717 return ret;
1718
1719 csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
1720
1721 edata.cmd = cmd;
1722 edata.data = (toe_cmpnt & csum_dir) ? 1 : 0;
1723
1724 if (copy_to_user(uaddr, &edata, sizeof(edata)))
1725 return -EFAULT;
1726 break;
1727
1728 /* Set toe offload components in dongle */
1729 case ETHTOOL_SRXCSUM:
1730 case ETHTOOL_STXCSUM:
1731 if (copy_from_user(&edata, uaddr, sizeof(edata)))
1732 return -EFAULT;
1733
1734 /* Read the current settings, update and write back */
1735 if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0)
1736 return ret;
1737
1738 csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL;
1739
1740 if (edata.data != 0)
1741 toe_cmpnt |= csum_dir;
1742 else
1743 toe_cmpnt &= ~csum_dir;
1744
1745 if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0)
1746 return ret;
1747
1748 /* If setting TX checksum mode, tell Linux the new mode */
1749 if (cmd == ETHTOOL_STXCSUM) {
1750 if (edata.data)
1751 dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM;
1752 else
1753 dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM;
1754 }
1755
1756 break;
1757#endif /* TOE */
1758
1759 default:
1760 return -EOPNOTSUPP;
1761 }
1762
1763 return 0;
1764}
1765#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
1766
1767static int
1768dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd)
1769{
1770 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
1771 dhd_ioctl_t ioc;
1772 int bcmerror = 0;
1773 int buflen = 0;
1774 void *buf = NULL;
1775 uint driver = 0;
1776 int ifidx;
1777 bool is_set_key_cmd;
1778 int ret;
1779
1780 dhd_os_wake_lock(&dhd->pub);
1781
1782 /* send to dongle only if we are not waiting for reload already */
1783 if (dhd->pub.hang_was_sent) {
1784 DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__));
1785 dhd_os_wake_lock_timeout_enable(&dhd->pub);
1786 dhd_os_wake_unlock(&dhd->pub);
1787 return OSL_ERROR(BCME_DONGLE_DOWN);
1788 }
1789
1790 ifidx = dhd_net2idx(dhd, net);
1791 DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd));
1792
1793 if (ifidx == DHD_BAD_IF) {
1794 dhd_os_wake_unlock(&dhd->pub);
1795 return -1;
1796 }
1797
1798#if defined(CONFIG_WIRELESS_EXT)
1799 /* linux wireless extensions */
1800 if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) {
1801 /* may recurse, do NOT lock */
1802 ret = wl_iw_ioctl(net, ifr, cmd);
1803 dhd_os_wake_unlock(&dhd->pub);
1804 return ret;
1805 }
1806#endif /* defined(CONFIG_WIRELESS_EXT) */
1807
1808#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2)
1809 if (cmd == SIOCETHTOOL) {
1810 ret = dhd_ethtool(dhd, (void*)ifr->ifr_data);
1811 dhd_os_wake_unlock(&dhd->pub);
1812 return ret;
1813 }
1814#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */
1815
1816 if (cmd != SIOCDEVPRIVATE) {
1817 dhd_os_wake_unlock(&dhd->pub);
1818 return -EOPNOTSUPP;
1819 }
1820
1821 memset(&ioc, 0, sizeof(ioc));
1822
1823 /* Copy the ioc control structure part of ioctl request */
1824 if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) {
1825 bcmerror = -BCME_BADADDR;
1826 goto done;
1827 }
1828
1829 /* Copy out any buffer passed */
1830 if (ioc.buf) {
1831 buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN);
1832 /* optimization for direct ioctl calls from kernel */
1833 /*
1834 if (segment_eq(get_fs(), KERNEL_DS)) {
1835 buf = ioc.buf;
1836 } else {
1837 */
1838 {
1839 if (!(buf = (char*)MALLOC(dhd->pub.osh, buflen))) {
1840 bcmerror = -BCME_NOMEM;
1841 goto done;
1842 }
1843 if (copy_from_user(buf, ioc.buf, buflen)) {
1844 bcmerror = -BCME_BADADDR;
1845 goto done;
1846 }
1847 }
1848 }
1849
1850 /* To differentiate between wl and dhd read 4 more byes */
1851 if ((copy_from_user(&driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t),
1852 sizeof(uint)) != 0)) {
1853 bcmerror = -BCME_BADADDR;
1854 goto done;
1855 }
1856
1857 if (!capable(CAP_NET_ADMIN)) {
1858 bcmerror = -BCME_EPERM;
1859 goto done;
1860 }
1861
1862 /* check for local dhd ioctl and handle it */
1863 if (driver == DHD_IOCTL_MAGIC) {
1864 bcmerror = dhd_ioctl((void *)&dhd->pub, &ioc, buf, buflen);
1865 if (bcmerror)
1866 dhd->pub.bcmerror = bcmerror;
1867 goto done;
1868 }
1869
1870 /* send to dongle (must be up, and wl) */
1871 if (dhd->pub.busstate != DHD_BUS_DATA) {
1872 DHD_ERROR(("%s DONGLE_DOWN\n", __FUNCTION__));
1873 bcmerror = BCME_DONGLE_DOWN;
1874 goto done;
1875 }
1876
1877 if (!dhd->pub.iswl) {
1878 bcmerror = BCME_DONGLE_DOWN;
1879 goto done;
1880 }
1881
1882 /* Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to
1883 * prevent M4 encryption.
1884 */
1885 is_set_key_cmd = ((ioc.cmd == WLC_SET_KEY) ||
1886 ((ioc.cmd == WLC_SET_VAR) &&
1887 !(strncmp("wsec_key", ioc.buf, 9))) ||
1888 ((ioc.cmd == WLC_SET_VAR) &&
1889 !(strncmp("bsscfg:wsec_key", ioc.buf, 15))));
1890 if (is_set_key_cmd) {
1891 dhd_wait_pend8021x(net);
1892 }
1893
1894 bcmerror = dhd_prot_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen);
1895
1896done:
1897 if ((bcmerror == -ETIMEDOUT) || ((dhd->pub.busstate == DHD_BUS_DOWN) &&
1898 (!dhd->pub.dongle_reset))) {
1899 DHD_ERROR(("%s: Event HANG send up\n", __FUNCTION__));
1900 net_os_send_hang_message(net);
1901 }
1902
1903 if (!bcmerror && buf && ioc.buf) {
1904 if (copy_to_user(ioc.buf, buf, buflen))
1905 bcmerror = -EFAULT;
1906 }
1907
1908 if (buf)
1909 MFREE(dhd->pub.osh, buf, buflen);
1910
1911 dhd_os_wake_unlock(&dhd->pub);
1912
1913 return OSL_ERROR(bcmerror);
1914}
1915
1916static int
1917dhd_stop(struct net_device *net)
1918{
1919#if !defined(IGNORE_ETH0_DOWN)
1920 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
1921
1922 DHD_TRACE(("%s: Enter %s\n", __FUNCTION__, net->name));
1923 if (dhd->pub.up == 0) {
1924 return 0;
1925 }
1926
1927 /* Set state and stop OS transmissions */
1928 dhd->pub.up = 0;
1929 netif_stop_queue(net);
1930#else
1931 DHD_ERROR(("BYPASS %s:due to BRCM compilation : under investigation ...\n", __FUNCTION__));
1932#endif /* !defined(IGNORE_ETH0_DOWN) */
1933 dhd->pub.hang_was_sent = 0;
1934 OLD_MOD_DEC_USE_COUNT;
1935 return 0;
1936}
1937
1938static int
1939dhd_open(struct net_device *net)
1940{
1941 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net);
1942#ifdef TOE
1943 uint32 toe_ol;
1944#endif
1945 int ifidx;
1946
1947 /* Force start if ifconfig_up gets called before START command */
1948 wl_control_wl_start(net);
1949
1950 ifidx = dhd_net2idx(dhd, net);
1951 DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
1952
1953 if (ifidx == DHD_BAD_IF)
1954 return -1;
1955
1956 if ((dhd->iflist[ifidx]) && (dhd->iflist[ifidx]->state == WLC_E_IF_DEL)) {
1957 DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__));
1958 return -1;
1959 }
1960
1961 if (ifidx == 0) { /* do it only for primary eth0 */
1962
1963 atomic_set(&dhd->pend_8021x_cnt, 0);
1964
1965 memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
1966
1967#ifdef TOE
1968 /* Get current TOE mode from dongle */
1969 if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0)
1970 dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM;
1971 else
1972 dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM;
1973#endif
1974 }
1975 /* Allow transmit calls */
1976 netif_start_queue(net);
1977 dhd->pub.up = 1;
1978
1979 OLD_MOD_INC_USE_COUNT;
1980 return 0;
1981}
1982
1983osl_t *
1984dhd_osl_attach(void *pdev, uint bustype)
1985{
1986 return osl_attach(pdev, bustype, TRUE);
1987}
1988
1989void
1990dhd_osl_detach(osl_t *osh)
1991{
1992 if (MALLOCED(osh)) {
1993 DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh)));
1994 }
1995 osl_detach(osh);
1996#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1
1997 up(&dhd_registration_sem);
1998#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
1999}
2000
2001int
2002dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name,
2003 uint8 *mac_addr, uint32 flags, uint8 bssidx)
2004{
2005 dhd_if_t *ifp;
2006
2007 DHD_TRACE(("%s: idx %d, handle->%p\n", __FUNCTION__, ifidx, handle));
2008
2009 ASSERT(dhd && (ifidx < DHD_MAX_IFS));
2010
2011 ifp = dhd->iflist[ifidx];
2012 if (!ifp && !(ifp = MALLOC(dhd->pub.osh, sizeof(dhd_if_t)))) {
2013 DHD_ERROR(("%s: OOM - dhd_if_t\n", __FUNCTION__));
2014 return -ENOMEM;
2015 }
2016
2017 memset(ifp, 0, sizeof(dhd_if_t));
2018 ifp->info = dhd;
2019 dhd->iflist[ifidx] = ifp;
2020 strncpy(ifp->name, name, IFNAMSIZ);
2021 ifp->name[IFNAMSIZ] = '\0';
2022 if (mac_addr != NULL)
2023 memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN);
2024
2025 if (handle == NULL) {
2026 ifp->state = WLC_E_IF_ADD;
2027 ifp->idx = ifidx;
2028 ASSERT(dhd->sysioc_pid >= 0);
2029 up(&dhd->sysioc_sem);
2030 } else
2031 ifp->net = (struct net_device *)handle;
2032
2033 return 0;
2034}
2035
2036void
2037dhd_del_if(dhd_info_t *dhd, int ifidx)
2038{
2039 dhd_if_t *ifp;
2040
2041 DHD_TRACE(("%s: idx %d\n", __FUNCTION__, ifidx));
2042
2043 ASSERT(dhd && ifidx && (ifidx < DHD_MAX_IFS));
2044 ifp = dhd->iflist[ifidx];
2045 if (!ifp) {
2046 DHD_ERROR(("%s: Null interface\n", __FUNCTION__));
2047 return;
2048 }
2049
2050 ifp->state = WLC_E_IF_DEL;
2051 ifp->idx = ifidx;
2052 ASSERT(dhd->sysioc_pid >= 0);
2053 up(&dhd->sysioc_sem);
2054}
2055
2056
2057dhd_pub_t *
2058dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev)
2059{
2060 dhd_info_t *dhd = NULL;
2061 struct net_device *net;
2062
2063 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2064 /* updates firmware nvram path if it was provided as module paramters */
2065 if ((firmware_path != NULL) && (firmware_path[0] != '\0'))
2066 strcpy(fw_path, firmware_path);
2067 if ((nvram_path != NULL) && (nvram_path[0] != '\0'))
2068 strcpy(nv_path, nvram_path);
2069
2070 /* Allocate etherdev, including space for private structure */
2071 if (!(net = alloc_etherdev(sizeof(dhd)))) {
2072 DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__));
2073 goto fail;
2074 }
2075 SET_NETDEV_DEV(net, (struct device *)dev);
2076 /* Allocate primary dhd_info */
2077 if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) {
2078 DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__));
2079 goto fail;
2080 }
2081
2082 memset(dhd, 0, sizeof(dhd_info_t));
2083
2084 /*
2085 * Save the dhd_info into the priv
2086 */
2087 memcpy(netdev_priv(net), &dhd, sizeof(dhd));
2088 dhd->pub.osh = osh;
2089
2090 /* Set network interface name if it was provided as module parameter */
2091 if (iface_name[0]) {
2092 int len;
2093 char ch;
2094 strncpy(net->name, iface_name, IFNAMSIZ);
2095 net->name[IFNAMSIZ - 1] = 0;
2096 len = strlen(net->name);
2097 ch = net->name[len - 1];
2098 if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2))
2099 strcat(net->name, "%d");
2100 }
2101
2102 if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF)
2103 goto fail;
2104
2105#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
2106 net->open = NULL;
2107#else
2108 net->netdev_ops = NULL;
2109#endif
2110
2111 mutex_init(&dhd->proto_sem);
2112 /* Initialize other structure content */
2113 init_waitqueue_head(&dhd->ioctl_resp_wait);
2114 init_waitqueue_head(&dhd->ctrl_wait);
2115
2116 /* Initialize the spinlocks */
2117 spin_lock_init(&dhd->sdlock);
2118 spin_lock_init(&dhd->txqlock);
2119 spin_lock_init(&dhd->dhd_lock);
2120
2121 /* Initialize Wakelock stuff */
2122 spin_lock_init(&dhd->wl_lock);
2123 dhd->wl_count = 0;
2124 dhd->wl_packet = 0;
2125#ifdef CONFIG_HAS_WAKELOCK
2126 wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake");
2127 wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake");
2128#endif
2129#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
2130 mutex_init(&dhd->wl_start_lock);
2131#endif
2132 /* Link to info module */
2133 dhd->pub.info = dhd;
2134
2135 /* Link to bus module */
2136 dhd->pub.bus = bus;
2137 dhd->pub.hdrlen = bus_hdrlen;
2138
2139 /* Attach and link in the protocol */
2140 if (dhd_prot_attach(&dhd->pub) != 0) {
2141 DHD_ERROR(("dhd_prot_attach failed\n"));
2142 goto fail;
2143 }
2144#if defined(CONFIG_WIRELESS_EXT)
2145 /* Attach and link in the iw */
2146 if (wl_iw_attach(net, (void *)&dhd->pub) != 0) {
2147 DHD_ERROR(("wl_iw_attach failed\n"));
2148 goto fail;
2149 }
2150#endif /* defined(CONFIG_WIRELESS_EXT) */
2151
2152 /* Set up the watchdog timer */
2153 init_timer(&dhd->timer);
2154 dhd->timer.data = (ulong)dhd;
2155 dhd->timer.function = dhd_watchdog;
2156
2157 /* Initialize thread based operation and lock */
2158 mutex_init(&dhd->sdsem);
2159 if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0)) {
2160 dhd->threads_only = TRUE;
2161 }
2162 else {
2163 dhd->threads_only = FALSE;
2164 }
2165
2166 if (dhd_dpc_prio >= 0) {
2167 /* Initialize watchdog thread */
2168 sema_init(&dhd->watchdog_sem, 0);
2169 init_completion(&dhd->watchdog_exited);
2170 dhd->watchdog_pid = kernel_thread(dhd_watchdog_thread, dhd, 0);
2171 } else {
2172 dhd->watchdog_pid = -1;
2173 }
2174
2175 /* Set up the bottom half handler */
2176 if (dhd_dpc_prio >= 0) {
2177 /* Initialize DPC thread */
2178 sema_init(&dhd->dpc_sem, 0);
2179 init_completion(&dhd->dpc_exited);
2180 dhd->dpc_pid = kernel_thread(dhd_dpc_thread, dhd, 0);
2181 } else {
2182 tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd);
2183 dhd->dpc_pid = -1;
2184 }
2185
2186 if (dhd_sysioc) {
2187 sema_init(&dhd->sysioc_sem, 0);
2188 init_completion(&dhd->sysioc_exited);
2189 dhd->sysioc_pid = kernel_thread(_dhd_sysioc_thread, dhd, 0);
2190 } else {
2191 dhd->sysioc_pid = -1;
2192 }
2193
2194 /*
2195 * Save the dhd_info into the priv
2196 */
2197 memcpy(netdev_priv(net), &dhd, sizeof(dhd));
2198
2199#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
2200 register_pm_notifier(&dhd_sleep_pm_notifier);
2201#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
2202
2203#ifdef CONFIG_HAS_WAKELOCK
2204 wake_lock_init(&dhd->pub.wow_wakelock, WAKE_LOCK_SUSPEND, "wow_wake_lock");
2205#endif
2206
2207#ifdef CONFIG_HAS_EARLYSUSPEND
2208 dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20;
2209 dhd->early_suspend.suspend = dhd_early_suspend;
2210 dhd->early_suspend.resume = dhd_late_resume;
2211 register_early_suspend(&dhd->early_suspend);
2212#endif
2213
2214 register_inetaddr_notifier(&dhd_notifier);
2215
2216 return &dhd->pub;
2217
2218fail:
2219 if (net)
2220 free_netdev(net);
2221 if (dhd)
2222 dhd_detach(&dhd->pub);
2223
2224 return NULL;
2225}
2226
2227
2228int
2229dhd_bus_start(dhd_pub_t *dhdp)
2230{
2231 int ret = -1;
2232 dhd_info_t *dhd = (dhd_info_t*)dhdp->info;
2233#ifdef EMBEDDED_PLATFORM
2234 char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */
2235#endif /* EMBEDDED_PLATFORM */
2236
2237 ASSERT(dhd);
2238
2239 DHD_TRACE(("%s: \n", __FUNCTION__));
2240
2241 dhd_os_sdlock(dhdp);
2242
2243 /* try to download image and nvram to the dongle */
2244 if (dhd->pub.busstate == DHD_BUS_DOWN) {
2245 if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh,
2246 fw_path, nv_path))) {
2247 DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n",
2248 __FUNCTION__, fw_path, nv_path));
2249 dhd_os_sdunlock(dhdp);
2250 return -1;
2251 }
2252 }
2253
2254 /* Start the watchdog timer */
2255 dhd->pub.tickcnt = 0;
2256 dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms);
2257
2258 /* Bring up the bus */
2259 if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) {
2260 DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret));
2261 dhd_os_sdunlock(dhdp);
2262 return ret;
2263 }
2264#if defined(OOB_INTR_ONLY)
2265 /* Host registration for OOB interrupt */
2266 if (bcmsdh_register_oob_intr(dhdp)) {
2267 dhd->wd_timer_valid = FALSE;
2268 del_timer_sync(&dhd->timer);
2269 DHD_ERROR(("%s Host failed to resgister for OOB\n", __FUNCTION__));
2270 dhd_os_sdunlock(dhdp);
2271 return -ENODEV;
2272 }
2273
2274 /* Enable oob at firmware */
2275 dhd_enable_oob_intr(dhd->pub.bus, TRUE);
2276#endif /* defined(OOB_INTR_ONLY) */
2277
2278 /* If bus is not ready, can't come up */
2279 if (dhd->pub.busstate != DHD_BUS_DATA) {
2280 dhd->wd_timer_valid = FALSE;
2281 del_timer_sync(&dhd->timer);
2282 DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__));
2283 dhd_os_sdunlock(dhdp);
2284 return -ENODEV;
2285 }
2286
2287 dhd_os_sdunlock(dhdp);
2288
2289#ifdef EMBEDDED_PLATFORM
2290 bcm_mkiovar("event_msgs", dhdp->eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf));
2291 dhdcdc_query_ioctl(dhdp, 0, WLC_GET_VAR, iovbuf, sizeof(iovbuf));
2292 bcopy(iovbuf, dhdp->eventmask, WL_EVENTING_MASK_LEN);
2293
2294 setbit(dhdp->eventmask, WLC_E_SET_SSID);
2295 setbit(dhdp->eventmask, WLC_E_PRUNE);
2296 setbit(dhdp->eventmask, WLC_E_AUTH);
2297 setbit(dhdp->eventmask, WLC_E_REASSOC);
2298 setbit(dhdp->eventmask, WLC_E_REASSOC_IND);
2299 setbit(dhdp->eventmask, WLC_E_DEAUTH_IND);
2300 setbit(dhdp->eventmask, WLC_E_DISASSOC_IND);
2301 setbit(dhdp->eventmask, WLC_E_DISASSOC);
2302 setbit(dhdp->eventmask, WLC_E_JOIN);
2303 setbit(dhdp->eventmask, WLC_E_ASSOC_IND);
2304 setbit(dhdp->eventmask, WLC_E_PSK_SUP);
2305 setbit(dhdp->eventmask, WLC_E_LINK);
2306 setbit(dhdp->eventmask, WLC_E_NDIS_LINK);
2307 setbit(dhdp->eventmask, WLC_E_MIC_ERROR);
2308 setbit(dhdp->eventmask, WLC_E_PMKID_CACHE);
2309 setbit(dhdp->eventmask, WLC_E_TXFAIL);
2310 setbit(dhdp->eventmask, WLC_E_JOIN_START);
2311 setbit(dhdp->eventmask, WLC_E_SCAN_COMPLETE);
2312 setbit(dhdp->eventmask, WLC_E_RELOAD);
2313#ifdef PNO_SUPPORT
2314 setbit(dhdp->eventmask, WLC_E_PFN_NET_FOUND);
2315#endif /* PNO_SUPPORT */
2316
2317/* enable dongle roaming event */
2318 setbit(dhdp->eventmask, WLC_E_ROAM);
2319
2320 dhdp->pktfilter_count = 4;
2321 /* Setup filter to allow only unicast */
2322 dhdp->pktfilter[0] = "100 0 0 0 0x01 0x00";
2323 dhdp->pktfilter[1] = NULL;
2324 dhdp->pktfilter[2] = NULL;
2325 dhdp->pktfilter[3] = NULL;
2326#endif /* EMBEDDED_PLATFORM */
2327
2328 /* Bus is ready, do any protocol initialization */
2329 if ((ret = dhd_prot_init(&dhd->pub)) < 0)
2330 return ret;
2331
2332 return 0;
2333}
2334
2335int
2336dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set)
2337{
2338 char buf[strlen(name) + 1 + cmd_len];
2339 int len = sizeof(buf);
2340 wl_ioctl_t ioc;
2341 int ret;
2342
2343 len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len);
2344
2345 memset(&ioc, 0, sizeof(ioc));
2346
2347 ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR;
2348 ioc.buf = buf;
2349 ioc.len = len;
2350 ioc.set = set;
2351
2352 ret = dhd_prot_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len);
2353 if (!set && ret >= 0)
2354 memcpy(cmd_buf, buf, cmd_len);
2355
2356 return ret;
2357}
2358
2359#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31))
2360static struct net_device_ops dhd_ops_pri = {
2361 .ndo_open = dhd_open,
2362 .ndo_stop = dhd_stop,
2363 .ndo_get_stats = dhd_get_stats,
2364 .ndo_do_ioctl = dhd_ioctl_entry,
2365 .ndo_start_xmit = dhd_start_xmit,
2366 .ndo_set_mac_address = dhd_set_mac_address,
2367 .ndo_set_multicast_list = dhd_set_multicast_list,
2368};
2369
2370static struct net_device_ops dhd_ops_virt = {
2371 .ndo_get_stats = dhd_get_stats,
2372 .ndo_do_ioctl = dhd_ioctl_entry,
2373 .ndo_start_xmit = dhd_start_xmit,
2374 .ndo_set_mac_address = dhd_set_mac_address,
2375 .ndo_set_multicast_list = dhd_set_multicast_list,
2376};
2377#endif
2378
2379static int dhd_device_event(struct notifier_block *this, unsigned long event,
2380 void *ptr)
2381{
2382 struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
2383 dhd_info_t *dhd;
2384 dhd_pub_t *dhd_pub;
2385
2386 if (!ifa)
2387 return NOTIFY_DONE;
2388
2389 dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev);
2390 dhd_pub = &dhd->pub;
2391
2392#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31))
2393 if (ifa->ifa_dev->dev->netdev_ops == &dhd_ops_pri) {
2394#else
2395 if (ifa->ifa_dev->dev->open == &dhd_open) {
2396#endif
2397 switch (event) {
2398 case NETDEV_UP:
2399 DHD_TRACE(("%s: [%s] Up IP: 0x%x\n",
2400 __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
2401
2402 dhd_arp_cleanup(dhd_pub);
2403 break;
2404
2405 case NETDEV_DOWN:
2406 DHD_TRACE(("%s: [%s] Down IP: 0x%x\n",
2407 __FUNCTION__, ifa->ifa_label, ifa->ifa_address));
2408
2409 dhd_arp_cleanup(dhd_pub);
2410 break;
2411
2412 default:
2413 DHD_TRACE(("%s: [%s] Event: %lu\n",
2414 __FUNCTION__, ifa->ifa_label, event));
2415 break;
2416 }
2417 }
2418 return NOTIFY_DONE;
2419}
2420
2421int
2422dhd_net_attach(dhd_pub_t *dhdp, int ifidx)
2423{
2424 dhd_info_t *dhd = (dhd_info_t *)dhdp->info;
2425 struct net_device *net;
2426 uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 };
2427
2428 DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx));
2429
2430 ASSERT(dhd && dhd->iflist[ifidx]);
2431 net = dhd->iflist[ifidx]->net;
2432
2433 ASSERT(net);
2434#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
2435 ASSERT(!net->open);
2436 net->get_stats = dhd_get_stats;
2437 net->do_ioctl = dhd_ioctl_entry;
2438 net->hard_start_xmit = dhd_start_xmit;
2439 net->set_mac_address = dhd_set_mac_address;
2440 net->set_multicast_list = dhd_set_multicast_list;
2441 net->open = net->stop = NULL;
2442#else
2443 ASSERT(!net->netdev_ops);
2444 net->netdev_ops = &dhd_ops_virt;
2445#endif
2446
2447#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
2448 net->open = dhd_open;
2449 net->stop = dhd_stop;
2450#else
2451 net->netdev_ops = &dhd_ops_pri;
2452#endif
2453
2454 /*
2455 * We have to use the primary MAC for virtual interfaces
2456 */
2457 if (ifidx != 0) {
2458 /* for virtual interfaces use the primary MAC */
2459 memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN);
2460 }
2461
2462 if (ifidx == 1) {
2463 DHD_TRACE(("%s ACCESS POINT MAC: \n", __FUNCTION__));
2464 /* ACCESSPOINT INTERFACE CASE */
2465 temp_addr[0] |= 0x02; /* set bit 2 , - Locally Administered address */
2466 }
2467 net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen;
2468#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
2469 net->ethtool_ops = &dhd_ethtool_ops;
2470#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */
2471
2472#if defined(CONFIG_WIRELESS_EXT)
2473#if WIRELESS_EXT < 19
2474 net->get_wireless_stats = dhd_get_wireless_stats;
2475#endif /* WIRELESS_EXT < 19 */
2476#if WIRELESS_EXT > 12
2477 net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def;
2478#endif /* WIRELESS_EXT > 12 */
2479#endif /* defined(CONFIG_WIRELESS_EXT) */
2480
2481 dhd->pub.rxsz = net->mtu + net->hard_header_len + dhd->pub.hdrlen;
2482
2483 memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN);
2484
2485 if (register_netdev(net) != 0) {
2486 DHD_ERROR(("%s: couldn't register the net device\n", __FUNCTION__));
2487 goto fail;
2488 }
2489
2490 printf("%s: Broadcom Dongle Host Driver mac=%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", net->name,
2491 dhd->pub.mac.octet[0], dhd->pub.mac.octet[1], dhd->pub.mac.octet[2],
2492 dhd->pub.mac.octet[3], dhd->pub.mac.octet[4], dhd->pub.mac.octet[5]);
2493
2494
2495#if defined(CONFIG_WIRELESS_EXT)
2496#if defined(CONFIG_FIRST_SCAN)
2497#ifdef SOFTAP
2498 if (ifidx == 0)
2499 /* Don't call for SOFTAP Interface in SOFTAP MODE */
2500 wl_iw_iscan_set_scan_broadcast_prep(net, 1);
2501#else
2502 wl_iw_iscan_set_scan_broadcast_prep(net, 1);
2503#endif /* SOFTAP */
2504#endif /* CONFIG_FIRST_SCAN */
2505#endif /* CONFIG_WIRELESS_EXT */
2506
2507#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
2508 up(&dhd_registration_sem);
2509#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */
2510 return 0;
2511
2512fail:
2513#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
2514 net->open = NULL;
2515#else
2516 net->netdev_ops = NULL;
2517#endif
2518 return BCME_ERROR;
2519}
2520
2521void
2522dhd_bus_detach(dhd_pub_t *dhdp)
2523{
2524 dhd_info_t *dhd;
2525
2526 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2527
2528 if (dhdp) {
2529 dhd = (dhd_info_t *)dhdp->info;
2530 if (dhd) {
2531 /* Stop the protocol module */
2532 dhd_prot_stop(&dhd->pub);
2533
2534 /* Stop the bus module */
2535 dhd_bus_stop(dhd->pub.bus, TRUE);
2536#if defined(OOB_INTR_ONLY)
2537 bcmsdh_unregister_oob_intr();
2538#endif /* defined(OOB_INTR_ONLY) */
2539
2540 /* Clear the watchdog timer */
2541 dhd->wd_timer_valid = FALSE;
2542 del_timer_sync(&dhd->timer);
2543 }
2544 }
2545}
2546
2547void
2548dhd_detach(dhd_pub_t *dhdp)
2549{
2550 dhd_info_t *dhd;
2551
2552 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2553
2554 if (dhdp) {
2555 dhd = (dhd_info_t *)dhdp->info;
2556 if (dhd) {
2557 dhd_if_t *ifp;
2558 int i;
2559
2560 unregister_inetaddr_notifier(&dhd_notifier);
2561
2562#if defined(CONFIG_HAS_EARLYSUSPEND)
2563 if (dhd->early_suspend.suspend)
2564 unregister_early_suspend(&dhd->early_suspend);
2565#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
2566#if defined(CONFIG_WIRELESS_EXT)
2567 /* Attach and link in the iw */
2568 wl_iw_detach();
2569#endif
2570 if (dhd->sysioc_pid >= 0) {
2571 KILL_PROC(dhd->sysioc_pid, SIGTERM);
2572 wait_for_completion(&dhd->sysioc_exited);
2573 }
2574
2575 for (i = 1; i < DHD_MAX_IFS; i++)
2576 if (dhd->iflist[i]) {
2577 dhd->iflist[i]->state = WLC_E_IF_DEL;
2578 dhd->iflist[i]->idx = i;
2579 dhd_op_if(dhd->iflist[i]);
2580 }
2581
2582 ifp = dhd->iflist[0];
2583 ASSERT(ifp);
2584#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
2585 if (ifp->net->open) {
2586#else
2587 if (ifp->net->netdev_ops == &dhd_ops_pri) {
2588#endif
2589 dhd_stop(ifp->net);
2590 unregister_netdev(ifp->net);
2591 }
2592
2593 if (dhd->watchdog_pid >= 0)
2594 {
2595 KILL_PROC(dhd->watchdog_pid, SIGTERM);
2596 wait_for_completion(&dhd->watchdog_exited);
2597 }
2598
2599 if (dhd->dpc_pid >= 0)
2600 {
2601 KILL_PROC(dhd->dpc_pid, SIGTERM);
2602 wait_for_completion(&dhd->dpc_exited);
2603 }
2604 else
2605 tasklet_kill(&dhd->tasklet);
2606
2607 dhd_bus_detach(dhdp);
2608
2609 if (dhdp->prot)
2610 dhd_prot_detach(dhdp);
2611
2612#ifdef CONFIG_HAS_WAKELOCK
2613 wake_lock_destroy(&dhdp->wow_wakelock);
2614#endif
2615
2616#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP)
2617 unregister_pm_notifier(&dhd_sleep_pm_notifier);
2618#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */
2619 free_netdev(ifp->net);
2620#ifdef CONFIG_HAS_WAKELOCK
2621 wake_lock_destroy(&dhd->wl_wifi);
2622 wake_lock_destroy(&dhd->wl_rxwake);
2623#endif
2624 MFREE(dhd->pub.osh, ifp, sizeof(*ifp));
2625 MFREE(dhd->pub.osh, dhd, sizeof(*dhd));
2626 }
2627 }
2628}
2629
2630static void __exit
2631dhd_module_cleanup(void)
2632{
2633 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2634
2635 dhd_bus_unregister();
2636#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC)
2637 wifi_del_dev();
2638#endif
2639 /* Call customer gpio to turn off power with WL_REG_ON signal */
2640 dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
2641}
2642
2643static int __init
2644dhd_module_init(void)
2645{
2646 int error;
2647
2648 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2649
2650 /* Sanity check on the module parameters */
2651 do {
2652 /* Both watchdog and DPC as tasklets are ok */
2653 if ((dhd_watchdog_prio < 0) && (dhd_dpc_prio < 0))
2654 break;
2655
2656 /* If both watchdog and DPC are threads, TX must be deferred */
2657 if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0) && dhd_deferred_tx)
2658 break;
2659
2660 DHD_ERROR(("Invalid module parameters.\n"));
2661 return -EINVAL;
2662 } while (0);
2663
2664 /* Call customer gpio to turn on power with WL_REG_ON signal */
2665 dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON);
2666
2667#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC)
2668 sema_init(&wifi_control_sem, 0);
2669
2670 error = wifi_add_dev();
2671 if (error) {
2672 DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__));
2673 goto fail_0;
2674 }
2675
2676 /* Waiting callback after platform_driver_register is done or exit with error */
2677 if (down_timeout(&wifi_control_sem, msecs_to_jiffies(5000)) != 0) {
2678 error = -EINVAL;
2679 DHD_ERROR(("%s: platform_driver_register timeout\n", __FUNCTION__));
2680 goto fail_1;
2681 }
2682#endif /* #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */
2683
2684#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
2685 sema_init(&dhd_registration_sem, 0);
2686#endif
2687
2688 error = dhd_bus_register();
2689
2690 if (!error)
2691 printf("\n%s\n", dhd_version);
2692 else {
2693 DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__));
2694 goto fail_1;
2695 }
2696#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
2697 /*
2698 * Wait till MMC sdio_register_driver callback called and made driver attach.
2699 * It's needed to make sync up exit from dhd insmod and
2700 * Kernel MMC sdio device callback registration
2701 */
2702 if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) {
2703 error = -EINVAL;
2704 DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__));
2705 goto fail_2;
2706 }
2707#endif
2708 return error;
2709#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
2710fail_2:
2711 dhd_bus_unregister();
2712#endif
2713fail_1:
2714#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC)
2715 wifi_del_dev();
2716fail_0:
2717#endif /* defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */
2718
2719 /* Call customer gpio to turn off power with WL_REG_ON signal */
2720 dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF);
2721
2722 return error;
2723}
2724
2725module_init(dhd_module_init);
2726module_exit(dhd_module_cleanup);
2727
2728/*
2729 * OS specific functions required to implement DHD driver in OS independent way
2730 */
2731int
2732dhd_os_proto_block(dhd_pub_t *pub)
2733{
2734 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
2735
2736 if (dhd) {
2737 mutex_lock(&dhd->proto_sem);
2738 return 1;
2739 }
2740
2741 return 0;
2742}
2743
2744int
2745dhd_os_proto_unblock(dhd_pub_t *pub)
2746{
2747 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
2748
2749 if (dhd) {
2750 mutex_unlock(&dhd->proto_sem);
2751 return 1;
2752 }
2753
2754 return 0;
2755}
2756
2757unsigned int
2758dhd_os_get_ioctl_resp_timeout(void)
2759{
2760 return ((unsigned int)dhd_ioctl_timeout_msec);
2761}
2762
2763void
2764dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec)
2765{
2766 dhd_ioctl_timeout_msec = (int)timeout_msec;
2767}
2768
2769int
2770dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending)
2771{
2772 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
2773 DECLARE_WAITQUEUE(wait, current);
2774 int timeout = dhd_ioctl_timeout_msec;
2775
2776 /* Convert timeout in millsecond to jiffies */
2777 /* timeout = timeout * HZ / 1000; */
2778 timeout = msecs_to_jiffies(timeout);
2779
2780 /* Wait until control frame is available */
2781 add_wait_queue(&dhd->ioctl_resp_wait, &wait);
2782 set_current_state(TASK_INTERRUPTIBLE);
2783 smp_mb();
2784 while (!(*condition) && (!signal_pending(current) && timeout)) {
2785 timeout = schedule_timeout(timeout);
2786 smp_mb();
2787 }
2788
2789 if (signal_pending(current))
2790 *pending = TRUE;
2791
2792 set_current_state(TASK_RUNNING);
2793 remove_wait_queue(&dhd->ioctl_resp_wait, &wait);
2794
2795 return timeout;
2796}
2797
2798int
2799dhd_os_ioctl_resp_wake(dhd_pub_t *pub)
2800{
2801 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
2802
2803 if (waitqueue_active(&dhd->ioctl_resp_wait)) {
2804 wake_up_interruptible(&dhd->ioctl_resp_wait);
2805 }
2806
2807 return 0;
2808}
2809
2810void
2811dhd_os_wd_timer(void *bus, uint wdtick)
2812{
2813 dhd_pub_t *pub = bus;
2814 dhd_info_t *dhd = (dhd_info_t *)pub->info;
2815 unsigned long flags;
2816 int del_timer_flag = FALSE;
2817
2818 flags = dhd_os_spin_lock(pub);
2819
2820 /* don't start the wd until fw is loaded */
2821 if (pub->busstate != DHD_BUS_DOWN) {
2822 if (wdtick) {
2823 dhd_watchdog_ms = (uint)wdtick;
2824 dhd->wd_timer_valid = TRUE;
2825 /* Re arm the timer, at last watchdog period */
2826 mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000);
2827 } else if (dhd->wd_timer_valid == TRUE) {
2828 /* Totally stop the timer */
2829 dhd->wd_timer_valid = FALSE;
2830 del_timer_flag = TRUE;
2831 }
2832 }
2833 dhd_os_spin_unlock(pub, flags);
2834 if (del_timer_flag) {
2835 del_timer_sync(&dhd->timer);
2836 }
2837}
2838
2839void *
2840dhd_os_open_image(char *filename)
2841{
2842 struct file *fp;
2843
2844 fp = filp_open(filename, O_RDONLY, 0);
2845 /*
2846 * 2.6.11 (FC4) supports filp_open() but later revs don't?
2847 * Alternative:
2848 * fp = open_namei(AT_FDCWD, filename, O_RD, 0);
2849 * ???
2850 */
2851 if (IS_ERR(fp))
2852 fp = NULL;
2853
2854 return fp;
2855}
2856
2857int
2858dhd_os_get_image_block(char *buf, int len, void *image)
2859{
2860 struct file *fp = (struct file *)image;
2861 int rdlen;
2862
2863 if (!image)
2864 return 0;
2865
2866 rdlen = kernel_read(fp, fp->f_pos, buf, len);
2867 if (rdlen > 0)
2868 fp->f_pos += rdlen;
2869
2870 return rdlen;
2871}
2872
2873void
2874dhd_os_close_image(void *image)
2875{
2876 if (image)
2877 filp_close((struct file *)image, NULL);
2878}
2879
2880
2881void
2882dhd_os_sdlock(dhd_pub_t *pub)
2883{
2884 dhd_info_t *dhd;
2885
2886 dhd = (dhd_info_t *)(pub->info);
2887
2888 if (dhd->threads_only)
2889 mutex_lock(&dhd->sdsem);
2890 else
2891 spin_lock_bh(&dhd->sdlock);
2892}
2893
2894void
2895dhd_os_sdunlock(dhd_pub_t *pub)
2896{
2897 dhd_info_t *dhd;
2898
2899 dhd = (dhd_info_t *)(pub->info);
2900
2901 if (dhd->threads_only)
2902 mutex_unlock(&dhd->sdsem);
2903 else
2904 spin_unlock_bh(&dhd->sdlock);
2905}
2906
2907void
2908dhd_os_sdlock_txq(dhd_pub_t *pub)
2909{
2910 dhd_info_t *dhd;
2911
2912 dhd = (dhd_info_t *)(pub->info);
2913 spin_lock_bh(&dhd->txqlock);
2914}
2915
2916void
2917dhd_os_sdunlock_txq(dhd_pub_t *pub)
2918{
2919 dhd_info_t *dhd;
2920
2921 dhd = (dhd_info_t *)(pub->info);
2922 spin_unlock_bh(&dhd->txqlock);
2923}
2924void
2925dhd_os_sdlock_rxq(dhd_pub_t *pub)
2926{
2927}
2928void
2929dhd_os_sdunlock_rxq(dhd_pub_t *pub)
2930{
2931}
2932
2933void
2934dhd_os_sdtxlock(dhd_pub_t *pub)
2935{
2936 dhd_os_sdlock(pub);
2937}
2938
2939void
2940dhd_os_sdtxunlock(dhd_pub_t *pub)
2941{
2942 dhd_os_sdunlock(pub);
2943}
2944
2945#ifdef DHD_USE_STATIC_BUF
2946void * dhd_os_prealloc(int section, unsigned long size)
2947{
2948#if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC)
2949 void *alloc_ptr = NULL;
2950 if (wifi_control_data && wifi_control_data->mem_prealloc)
2951 {
2952 alloc_ptr = wifi_control_data->mem_prealloc(section, size);
2953 if (alloc_ptr)
2954 {
2955 DHD_INFO(("success alloc section %d\n", section));
2956 bzero(alloc_ptr, size);
2957 return alloc_ptr;
2958 }
2959 }
2960
2961 DHD_ERROR(("can't alloc section %d\n", section));
2962 return 0;
2963#else
2964return MALLOC(0, size);
2965#endif /* #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) */
2966}
2967#endif /* DHD_USE_STATIC_BUF */
2968#if defined(CONFIG_WIRELESS_EXT)
2969struct iw_statistics *
2970dhd_get_wireless_stats(struct net_device *dev)
2971{
2972 int res = 0;
2973 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
2974
2975 res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats);
2976
2977 if (res == 0)
2978 return &dhd->iw.wstats;
2979 else
2980 return NULL;
2981}
2982#endif /* defined(CONFIG_WIRELESS_EXT) */
2983
2984static int
2985dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata,
2986 wl_event_msg_t *event, void **data)
2987{
2988 int bcmerror = 0;
2989
2990 ASSERT(dhd != NULL);
2991
2992 bcmerror = wl_host_event(dhd, ifidx, pktdata, event, data);
2993 if (bcmerror != BCME_OK)
2994 return (bcmerror);
2995
2996#if defined(CONFIG_WIRELESS_EXT)
2997 ASSERT(dhd->iflist[*ifidx] != NULL);
2998
2999 if (ntoh32(event->event_type) == WLC_E_IF) {
3000 DHD_INFO(("<0> interface:%d OP:%d don't pass to wext,"
3001 "net_device might not be created yet\n",
3002 *ifidx, ntoh32(event->event_type)));
3003 return bcmerror;
3004 }
3005
3006 ASSERT(dhd->iflist[*ifidx]->net != NULL);
3007
3008 if (dhd->iflist[*ifidx]->net)
3009 wl_iw_event(dhd->iflist[*ifidx]->net, event, *data);
3010#endif /* defined(CONFIG_WIRELESS_EXT) */
3011
3012 return (bcmerror);
3013}
3014
3015/* send up locally generated event */
3016void
3017dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
3018{
3019 switch (ntoh32(event->event_type)) {
3020 default:
3021 break;
3022 }
3023}
3024
3025void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar)
3026{
3027#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
3028 struct dhd_info *dhdinfo = dhd->info;
3029 dhd_os_sdunlock(dhd);
3030 wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 2);
3031 dhd_os_sdlock(dhd);
3032#endif
3033 return;
3034}
3035
3036void dhd_wait_event_wakeup(dhd_pub_t *dhd)
3037{
3038#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
3039 struct dhd_info *dhdinfo = dhd->info;
3040 if (waitqueue_active(&dhdinfo->ctrl_wait))
3041 wake_up_interruptible(&dhdinfo->ctrl_wait);
3042#endif
3043 return;
3044}
3045
3046int
3047dhd_dev_reset(struct net_device *dev, uint8 flag)
3048{
3049 int ret;
3050
3051 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3052
3053 ret = dhd_bus_devreset(&dhd->pub, flag);
3054 if (ret) {
3055 DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret));
3056 return ret;
3057 }
3058 DHD_ERROR(("%s: WLAN %s DONE\n", __FUNCTION__, flag ? "OFF" : "ON"));
3059
3060 return ret;
3061}
3062
3063int net_os_set_suspend_disable(struct net_device *dev, int val)
3064{
3065 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3066 int ret = 0;
3067
3068 if (dhd) {
3069 ret = dhd->pub.suspend_disable_flag;
3070 dhd->pub.suspend_disable_flag = val;
3071 }
3072 return ret;
3073}
3074
3075int net_os_set_suspend(struct net_device *dev, int val)
3076{
3077 int ret = 0;
3078#if defined(CONFIG_HAS_EARLYSUSPEND)
3079 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3080
3081 if (dhd) {
3082 dhd_os_proto_block(&dhd->pub);
3083 ret = dhd_set_suspend(val, &dhd->pub);
3084 dhd_os_proto_unblock(&dhd->pub);
3085 }
3086#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */
3087 return ret;
3088}
3089
3090int net_os_set_dtim_skip(struct net_device *dev, int val)
3091{
3092 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3093
3094 if (dhd)
3095 dhd->pub.dtim_skip = val;
3096
3097 return 0;
3098}
3099
3100int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num)
3101{
3102 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3103 char *filterp = NULL;
3104 int ret = 0;
3105
3106 if (!dhd || (num == DHD_UNICAST_FILTER_NUM))
3107 return ret;
3108 if (num >= dhd->pub.pktfilter_count)
3109 return -EINVAL;
3110 if (add_remove) {
3111 switch (num) {
3112 case DHD_BROADCAST_FILTER_NUM:
3113 filterp = "101 0 0 0 0xFFFFFFFFFFFF 0xFFFFFFFFFFFF";
3114 break;
3115 case DHD_MULTICAST4_FILTER_NUM:
3116 filterp = "102 0 0 0 0xFFFFFF 0x01005E";
3117 break;
3118 case DHD_MULTICAST6_FILTER_NUM:
3119 filterp = "103 0 0 0 0xFFFF 0x3333";
3120 break;
3121 default:
3122 return -EINVAL;
3123 }
3124 }
3125 dhd->pub.pktfilter[num] = filterp;
3126 return ret;
3127}
3128
3129int net_os_set_packet_filter(struct net_device *dev, int val)
3130{
3131 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3132 int ret = 0;
3133
3134 /* Packet filtering is set only if we still in early-suspend and
3135 * we need either to turn it ON or turn it OFF
3136 * We can always turn it OFF in case of early-suspend, but we turn it
3137 * back ON only if suspend_disable_flag was not set
3138 */
3139 if (dhd && dhd->pub.up) {
3140 dhd_os_proto_block(&dhd->pub);
3141 if (dhd->pub.in_suspend) {
3142 if (!val || (val && !dhd->pub.suspend_disable_flag))
3143 dhd_set_packet_filter(val, &dhd->pub);
3144 }
3145 dhd_os_proto_unblock(&dhd->pub);
3146 }
3147 return ret;
3148}
3149
3150
3151void
3152dhd_dev_init_ioctl(struct net_device *dev)
3153{
3154 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3155
3156 dhd_preinit_ioctls(&dhd->pub);
3157}
3158
3159#ifdef PNO_SUPPORT
3160/* Linux wrapper to call common dhd_pno_clean */
3161int
3162dhd_dev_pno_reset(struct net_device *dev)
3163{
3164 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3165
3166 return (dhd_pno_clean(&dhd->pub));
3167}
3168
3169
3170/* Linux wrapper to call common dhd_pno_enable */
3171int
3172dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled)
3173{
3174 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3175
3176 return (dhd_pno_enable(&dhd->pub, pfn_enabled));
3177}
3178
3179
3180/* Linux wrapper to call common dhd_pno_set */
3181int
3182dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid,
3183 ushort scan_fr, int pno_repeat, int pno_freq_expo_max)
3184{
3185 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3186
3187 return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max));
3188}
3189
3190/* Linux wrapper to get pno status */
3191int
3192dhd_dev_get_pno_status(struct net_device *dev)
3193{
3194 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3195
3196 return (dhd_pno_get_status(&dhd->pub));
3197}
3198
3199#endif /* PNO_SUPPORT */
3200
3201int net_os_send_hang_message(struct net_device *dev)
3202{
3203 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3204 int ret = 0;
3205
3206 if (dhd) {
3207 if (!dhd->pub.hang_was_sent) {
3208 dhd->pub.hang_was_sent = 1;
3209 ret = wl_iw_send_priv_event(dev, "HANG");
3210 }
3211 }
3212 return ret;
3213}
3214
3215void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec)
3216{
3217 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3218
3219 if (dhd && dhd->pub.up)
3220 memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t));
3221}
3222
3223char *dhd_bus_country_get(struct net_device *dev)
3224{
3225 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3226
3227 if (dhd && (dhd->pub.dhd_cspec.ccode[0] != 0))
3228 return dhd->pub.dhd_cspec.ccode;
3229 return NULL;
3230}
3231
3232void dhd_os_start_lock(dhd_pub_t *pub)
3233{
3234#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
3235 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
3236
3237 if (dhd)
3238 mutex_lock(&dhd->wl_start_lock);
3239#endif
3240}
3241
3242void dhd_os_start_unlock(dhd_pub_t *pub)
3243{
3244#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25))
3245 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
3246
3247 if (dhd)
3248 mutex_unlock(&dhd->wl_start_lock);
3249#endif
3250}
3251
3252static int
3253dhd_get_pend_8021x_cnt(dhd_info_t *dhd)
3254{
3255 return (atomic_read(&dhd->pend_8021x_cnt));
3256}
3257
3258#define MAX_WAIT_FOR_8021X_TX 10
3259
3260int
3261dhd_wait_pend8021x(struct net_device *dev)
3262{
3263 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3264 int timeout = 10 * HZ / 1000;
3265 int ntimes = MAX_WAIT_FOR_8021X_TX;
3266 int pend = dhd_get_pend_8021x_cnt(dhd);
3267
3268 while (ntimes && pend) {
3269 if (pend) {
3270 set_current_state(TASK_INTERRUPTIBLE);
3271 schedule_timeout(timeout);
3272 set_current_state(TASK_RUNNING);
3273 ntimes--;
3274 }
3275 pend = dhd_get_pend_8021x_cnt(dhd);
3276 }
3277 return pend;
3278}
3279
3280#ifdef DHD_DEBUG
3281int
3282write_to_file(dhd_pub_t *dhd, uint8 *buf, int size)
3283{
3284 int ret = 0;
3285 struct file *fp;
3286 mm_segment_t old_fs;
3287 loff_t pos = 0;
3288
3289 /* change to KERNEL_DS address limit */
3290 old_fs = get_fs();
3291 set_fs(KERNEL_DS);
3292
3293 /* open file to write */
3294 fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640);
3295 if (!fp) {
3296 printf("%s: open file error\n", __FUNCTION__);
3297 ret = -1;
3298 goto exit;
3299 }
3300
3301 /* Write buf to file */
3302 fp->f_op->write(fp, buf, size, &pos);
3303
3304exit:
3305 /* free buf before return */
3306 MFREE(dhd->osh, buf, size);
3307 /* close file before return */
3308 if (fp)
3309 filp_close(fp, current->files);
3310 /* restore previous address limit */
3311 set_fs(old_fs);
3312
3313 return ret;
3314}
3315#endif /* DHD_DEBUG */
3316
3317int dhd_os_wake_lock_timeout(dhd_pub_t *pub)
3318{
3319 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
3320 unsigned long flags;
3321 int ret = 0;
3322
3323 if (dhd) {
3324 spin_lock_irqsave(&dhd->wl_lock, flags);
3325 ret = dhd->wl_packet;
3326#ifdef CONFIG_HAS_WAKELOCK
3327 if (dhd->wl_packet)
3328 wake_lock_timeout(&dhd->wl_rxwake, HZ);
3329#endif
3330 dhd->wl_packet = 0;
3331 spin_unlock_irqrestore(&dhd->wl_lock, flags);
3332 }
3333 /* printk("%s: %d\n", __FUNCTION__, ret); */
3334 return ret;
3335}
3336
3337int net_os_wake_lock_timeout(struct net_device *dev)
3338{
3339 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3340 int ret = 0;
3341
3342 if (dhd)
3343 ret = dhd_os_wake_lock_timeout(&dhd->pub);
3344 return ret;
3345}
3346
3347int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub)
3348{
3349 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
3350 unsigned long flags;
3351
3352 if (dhd) {
3353 spin_lock_irqsave(&dhd->wl_lock, flags);
3354 dhd->wl_packet = 1;
3355 spin_unlock_irqrestore(&dhd->wl_lock, flags);
3356 }
3357 /* printk("%s\n",__func__); */
3358 return 0;
3359}
3360
3361int net_os_wake_lock_timeout_enable(struct net_device *dev)
3362{
3363 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3364 int ret = 0;
3365
3366 if (dhd)
3367 ret = dhd_os_wake_lock_timeout_enable(&dhd->pub);
3368 return ret;
3369}
3370
3371int dhd_os_wake_lock(dhd_pub_t *pub)
3372{
3373 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
3374 unsigned long flags;
3375 int ret = 0;
3376
3377 if (dhd) {
3378 spin_lock_irqsave(&dhd->wl_lock, flags);
3379#ifdef CONFIG_HAS_WAKELOCK
3380 if (!dhd->wl_count)
3381 wake_lock(&dhd->wl_wifi);
3382#endif
3383 dhd->wl_count++;
3384 ret = dhd->wl_count;
3385 spin_unlock_irqrestore(&dhd->wl_lock, flags);
3386 }
3387 /* printk("%s: %d\n", __FUNCTION__, ret); */
3388 return ret;
3389}
3390
3391int net_os_wake_lock(struct net_device *dev)
3392{
3393 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3394 int ret = 0;
3395
3396 if (dhd)
3397 ret = dhd_os_wake_lock(&dhd->pub);
3398 return ret;
3399}
3400
3401int dhd_os_wake_unlock(dhd_pub_t *pub)
3402{
3403 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
3404 unsigned long flags;
3405 int ret = 0;
3406
3407 dhd_os_wake_lock_timeout(pub);
3408 if (dhd) {
3409 spin_lock_irqsave(&dhd->wl_lock, flags);
3410 if (dhd->wl_count) {
3411 dhd->wl_count--;
3412#ifdef CONFIG_HAS_WAKELOCK
3413 if (!dhd->wl_count)
3414 wake_unlock(&dhd->wl_wifi);
3415#endif
3416 ret = dhd->wl_count;
3417 }
3418 spin_unlock_irqrestore(&dhd->wl_lock, flags);
3419 }
3420 /* printk("%s: %d\n", __FUNCTION__, ret); */
3421 return ret;
3422}
3423
3424int net_os_wake_unlock(struct net_device *dev)
3425{
3426 dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev);
3427 int ret = 0;
3428
3429 if (dhd)
3430 ret = dhd_os_wake_unlock(&dhd->pub);
3431 return ret;
3432}
3433
3434unsigned long dhd_os_spin_lock(dhd_pub_t *pub)
3435{
3436 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
3437 unsigned long flags = 0;
3438
3439 if (dhd)
3440 spin_lock_irqsave(&dhd->dhd_lock, flags);
3441
3442 return flags;
3443}
3444
3445void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags)
3446{
3447 dhd_info_t *dhd = (dhd_info_t *)(pub->info);
3448
3449 if (dhd)
3450 spin_unlock_irqrestore(&dhd->dhd_lock, flags);
3451}
diff --git a/drivers/net/wireless/bcm4329/dhd_linux_sched.c b/drivers/net/wireless/bcm4329/dhd_linux_sched.c
new file mode 100644
index 00000000000..480b416657e
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/dhd_linux_sched.c
@@ -0,0 +1,38 @@
1/*
2 * Expose some of the kernel scheduler routines
3 *
4 * Copyright (C) 1999-2010, 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.1.34.1.6.1 2009/01/16 01:17:40 Exp $
25 */
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/sched.h>
29#include <linuxver.h>
30
31int setScheduler(struct task_struct *p, int policy, struct sched_param *param)
32{
33 int rc = 0;
34#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
35 rc = sched_setscheduler(p, policy, param);
36#endif /* LinuxVer */
37 return rc;
38}
diff --git a/drivers/net/wireless/bcm4329/dhd_proto.h b/drivers/net/wireless/bcm4329/dhd_proto.h
new file mode 100644
index 00000000000..7ef6929a5bf
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/dhd_proto.h
@@ -0,0 +1,102 @@
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-2010, 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.2.82.1.4.1.16.7 2010/05/10 12:54:59 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 3000 /* In milli second */
38#endif
39
40#ifndef IOCTL_CHIP_ACTIVE_TIMEOUT
41#define IOCTL_CHIP_ACTIVE_TIMEOUT 10 /* In milli second */
42#endif
43
44/*
45 * Exported from the dhd protocol module (dhd_cdc, dhd_rndis)
46 */
47
48/* Linkage, sets prot link and updates hdrlen in pub */
49extern int dhd_prot_attach(dhd_pub_t *dhdp);
50
51/* Unlink, frees allocated protocol memory (including dhd_prot) */
52extern void dhd_prot_detach(dhd_pub_t *dhdp);
53
54/* Initialize protocol: sync w/dongle state.
55 * Sets dongle media info (iswl, drv_version, mac address).
56 */
57extern int dhd_prot_init(dhd_pub_t *dhdp);
58
59/* Stop protocol: sync w/dongle state. */
60extern void dhd_prot_stop(dhd_pub_t *dhdp);
61
62extern bool dhd_proto_fcinfo(dhd_pub_t *dhd, void *pktbuf, uint8 *fcbits);
63
64/* Add any protocol-specific data header.
65 * Caller must reserve prot_hdrlen prepend space.
66 */
67extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp);
68
69/* Remove any protocol-specific data header. */
70extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp);
71
72/* Use protocol to issue ioctl to dongle */
73extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len);
74
75/* Check for and handle local prot-specific iovar commands */
76extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
77 void *params, int plen, void *arg, int len, bool set);
78
79/* Add prot dump output to a buffer */
80extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
81
82/* Update local copy of dongle statistics */
83extern void dhd_prot_dstats(dhd_pub_t *dhdp);
84
85extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen);
86
87extern int dhd_preinit_ioctls(dhd_pub_t *dhd);
88
89/********************************
90 * For version-string expansion *
91 */
92#if defined(BDC)
93#define DHD_PROTOCOL "bdc"
94#elif defined(CDC)
95#define DHD_PROTOCOL "cdc"
96#elif defined(RNDIS)
97#define DHD_PROTOCOL "rndis"
98#else
99#define DHD_PROTOCOL "unknown"
100#endif /* proto */
101
102#endif /* _dhd_proto_h_ */
diff --git a/drivers/net/wireless/bcm4329/dhd_sdio.c b/drivers/net/wireless/bcm4329/dhd_sdio.c
new file mode 100644
index 00000000000..446eb4a458d
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/dhd_sdio.c
@@ -0,0 +1,5841 @@
1/*
2 * DHD Bus Module for SDIO
3 *
4 * Copyright (C) 1999-2010, 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,v 1.157.2.27.2.33.2.129.4.1 2010/09/02 23:13:16 Exp $
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#include <siutils.h>
40#include <hndpmu.h>
41#include <hndsoc.h>
42#include <sbchipc.h>
43#include <sbhnddma.h>
44#include <sdio.h>
45#include <sbsdio.h>
46#include <sbsdpcmdev.h>
47#include <bcmsdpcm.h>
48
49#include <proto/ethernet.h>
50#include <proto/802.1d.h>
51#include <proto/802.11.h>
52
53#include <dngl_stats.h>
54#include <dhd.h>
55#include <dhd_bus.h>
56#include <dhd_proto.h>
57#include <dhd_dbg.h>
58#include <dhdioctl.h>
59#include <sdiovar.h>
60
61#ifdef CONFIG_HAS_WAKELOCK
62#include <linux/wakelock.h>
63#endif
64
65#ifdef DHD_DEBUG
66#include <hndrte_cons.h>
67#endif /* DHD_DEBUG */
68#ifdef DHD_DEBUG_TRAP
69#include <hndrte_armtrap.h>
70#endif /* DHD_DEBUG_TRAP */
71
72#define QLEN 2048 /* bulk rx and tx queue lengths */
73#define FCHI (QLEN - 256)
74#define FCLOW (FCHI -256)
75#define PRIOMASK 7
76
77#define TXRETRIES 2 /* # of retries for tx frames */
78
79#if defined(CONFIG_MACH_SANDGATE2G)
80#define DHD_RXBOUND 250 /* Default for max rx frames in one scheduling */
81#else
82#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */
83#endif /* defined(CONFIG_MACH_SANDGATE2G) */
84
85#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */
86
87#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */
88
89#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */
90#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */
91
92/* Packet alignment for most efficient SDIO (can change based on platform) */
93#ifndef DHD_SDALIGN
94#define DHD_SDALIGN 32
95#endif
96#if !ISPOWEROF2(DHD_SDALIGN)
97#error DHD_SDALIGN is not a power of 2!
98#endif
99
100#ifndef DHD_FIRSTREAD
101#define DHD_FIRSTREAD 32
102#endif
103#if !ISPOWEROF2(DHD_FIRSTREAD)
104#error DHD_FIRSTREAD is not a power of 2!
105#endif
106
107/* Total length of frame header for dongle protocol */
108#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN)
109#ifdef SDTEST
110#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN)
111#else
112#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN)
113#endif
114
115/* Space for header read, limit for data packets */
116#ifndef MAX_HDR_READ
117#define MAX_HDR_READ 32
118#endif
119#if !ISPOWEROF2(MAX_HDR_READ)
120#error MAX_HDR_READ is not a power of 2!
121#endif
122
123#define MAX_RX_DATASZ 2048
124
125/* Maximum milliseconds to wait for F2 to come up */
126#define DHD_WAIT_F2RDY 3000
127
128/* Bump up limit on waiting for HT to account for first startup;
129 * if the image is doing a CRC calculation before programming the PMU
130 * for HT availability, it could take a couple hundred ms more, so
131 * max out at a 1 second (1000000us).
132 */
133#if (PMU_MAX_TRANSITION_DLY < 1000000)
134#undef PMU_MAX_TRANSITION_DLY
135#define PMU_MAX_TRANSITION_DLY 1000000
136#endif
137
138/* Value for ChipClockCSR during initial setup */
139#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ)
140#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP)
141
142/* Flags for SDH calls */
143#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
144
145/* Packet free applicable unconditionally for sdio and sdspi. Conditional if
146 * bufpool was present for gspi bus.
147 */
148#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \
149 PKTFREE(bus->dhd->osh, pkt, FALSE);
150DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep);
151extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len);
152
153extern void bcmsdh_set_irq(int flag);
154
155#ifdef DHD_DEBUG
156/* Device console log buffer state */
157typedef struct dhd_console {
158 uint count; /* Poll interval msec counter */
159 uint log_addr; /* Log struct address (fixed) */
160 hndrte_log_t log; /* Log struct (host copy) */
161 uint bufsize; /* Size of log buffer */
162 uint8 *buf; /* Log buffer (host copy) */
163 uint last; /* Last buffer read index */
164} dhd_console_t;
165#endif /* DHD_DEBUG */
166
167/* Private data for SDIO bus interaction */
168typedef struct dhd_bus {
169 dhd_pub_t *dhd;
170
171 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
172 si_t *sih; /* Handle for SI calls */
173 char *vars; /* Variables (from CIS and/or other) */
174 uint varsz; /* Size of variables buffer */
175 uint32 sbaddr; /* Current SB window pointer (-1, invalid) */
176
177 sdpcmd_regs_t *regs; /* Registers for SDIO core */
178 uint sdpcmrev; /* SDIO core revision */
179 uint armrev; /* CPU core revision */
180 uint ramrev; /* SOCRAM core revision */
181 uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */
182 uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */
183
184 uint32 bus; /* gSPI or SDIO bus */
185 uint32 hostintmask; /* Copy of Host Interrupt Mask */
186 uint32 intstatus; /* Intstatus bits (events) pending */
187 bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */
188 bool fcstate; /* State of dongle flow-control */
189
190 uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */
191 char *fw_path; /* module_param: path to firmware image */
192 char *nv_path; /* module_param: path to nvram vars file */
193 const char *nvram_params; /* user specified nvram params. */
194
195 uint blocksize; /* Block size of SDIO transfers */
196 uint roundup; /* Max roundup limit */
197
198 struct pktq txq; /* Queue length used for flow-control */
199 uint8 flowcontrol; /* per prio flow control bitmask */
200 uint8 tx_seq; /* Transmit sequence number (next) */
201 uint8 tx_max; /* Maximum transmit sequence allowed */
202
203 uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN];
204 uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */
205 uint16 nextlen; /* Next Read Len from last header */
206 uint8 rx_seq; /* Receive sequence number (expected) */
207 bool rxskip; /* Skip receive (awaiting NAK ACK) */
208
209 void *glomd; /* Packet containing glomming descriptor */
210 void *glom; /* Packet chain for glommed superframe */
211 uint glomerr; /* Glom packet read errors */
212
213 uint8 *rxbuf; /* Buffer for receiving control packets */
214 uint rxblen; /* Allocated length of rxbuf */
215 uint8 *rxctl; /* Aligned pointer into rxbuf */
216 uint8 *databuf; /* Buffer for receiving big glom packet */
217 uint8 *dataptr; /* Aligned pointer into databuf */
218 uint rxlen; /* Length of valid data in buffer */
219
220 uint8 sdpcm_ver; /* Bus protocol reported by dongle */
221
222 bool intr; /* Use interrupts */
223 bool poll; /* Use polling */
224 bool ipend; /* Device interrupt is pending */
225 bool intdis; /* Interrupts disabled by isr */
226 uint intrcount; /* Count of device interrupt callbacks */
227 uint lastintrs; /* Count as of last watchdog timer */
228 uint spurious; /* Count of spurious interrupts */
229 uint pollrate; /* Ticks between device polls */
230 uint polltick; /* Tick counter */
231 uint pollcnt; /* Count of active polls */
232
233#ifdef DHD_DEBUG
234 dhd_console_t console; /* Console output polling support */
235 uint console_addr; /* Console address from shared struct */
236#endif /* DHD_DEBUG */
237
238 uint regfails; /* Count of R_REG/W_REG failures */
239
240 uint clkstate; /* State of sd and backplane clock(s) */
241 bool activity; /* Activity flag for clock down */
242 int32 idletime; /* Control for activity timeout */
243 int32 idlecount; /* Activity timeout counter */
244 int32 idleclock; /* How to set bus driver when idle */
245 int32 sd_divisor; /* Speed control to bus driver */
246 int32 sd_mode; /* Mode control to bus driver */
247 int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */
248 bool use_rxchain; /* If dhd should use PKT chains */
249 bool sleeping; /* Is SDIO bus sleeping? */
250 bool rxflow_mode; /* Rx flow control mode */
251 bool rxflow; /* Is rx flow control on */
252 uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */
253 bool alp_only; /* Don't use HT clock (ALP only) */
254 /* Field to decide if rx of control frames happen in rxbuf or lb-pool */
255 bool usebufpool;
256
257#ifdef SDTEST
258 /* external loopback */
259 bool ext_loop;
260 uint8 loopid;
261
262 /* pktgen configuration */
263 uint pktgen_freq; /* Ticks between bursts */
264 uint pktgen_count; /* Packets to send each burst */
265 uint pktgen_print; /* Bursts between count displays */
266 uint pktgen_total; /* Stop after this many */
267 uint pktgen_minlen; /* Minimum packet data len */
268 uint pktgen_maxlen; /* Maximum packet data len */
269 uint pktgen_mode; /* Configured mode: tx, rx, or echo */
270 uint pktgen_stop; /* Number of tx failures causing stop */
271
272 /* active pktgen fields */
273 uint pktgen_tick; /* Tick counter for bursts */
274 uint pktgen_ptick; /* Burst counter for printing */
275 uint pktgen_sent; /* Number of test packets generated */
276 uint pktgen_rcvd; /* Number of test packets received */
277 uint pktgen_fail; /* Number of failed send attempts */
278 uint16 pktgen_len; /* Length of next packet to send */
279#endif /* SDTEST */
280
281 /* Some additional counters */
282 uint tx_sderrs; /* Count of tx attempts with sd errors */
283 uint fcqueued; /* Tx packets that got queued */
284 uint rxrtx; /* Count of rtx requests (NAK to dongle) */
285 uint rx_toolong; /* Receive frames too long to receive */
286 uint rxc_errors; /* SDIO errors when reading control frames */
287 uint rx_hdrfail; /* SDIO errors on header reads */
288 uint rx_badhdr; /* Bad received headers (roosync?) */
289 uint rx_badseq; /* Mismatched rx sequence number */
290 uint fc_rcvd; /* Number of flow-control events received */
291 uint fc_xoff; /* Number which turned on flow-control */
292 uint fc_xon; /* Number which turned off flow-control */
293 uint rxglomfail; /* Failed deglom attempts */
294 uint rxglomframes; /* Number of glom frames (superframes) */
295 uint rxglompkts; /* Number of packets from glom frames */
296 uint f2rxhdrs; /* Number of header reads */
297 uint f2rxdata; /* Number of frame data reads */
298 uint f2txdata; /* Number of f2 frame writes */
299 uint f1regdata; /* Number of f1 register accesses */
300
301 uint8 *ctrl_frame_buf;
302 uint32 ctrl_frame_len;
303 bool ctrl_frame_stat;
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;
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#define ALIGNMENT 4
354
355#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
356extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable);
357#endif
358
359#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD)
360#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD
361#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */
362#define PKTALIGN(osh, p, len, align) \
363 do { \
364 uint datalign; \
365 datalign = (uintptr)PKTDATA((osh), (p)); \
366 datalign = ROUNDUP(datalign, (align)) - datalign; \
367 ASSERT(datalign < (align)); \
368 ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \
369 if (datalign) \
370 PKTPULL((osh), (p), datalign); \
371 PKTSETLEN((osh), (p), (len)); \
372 } while (0)
373
374/* Limit on rounding up frames */
375static const uint max_roundup = 512;
376
377/* Try doing readahead */
378static bool dhd_readahead;
379
380
381/* To check if there's window offered */
382#define DATAOK(bus) \
383 (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \
384 (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0))
385
386/* Macros to get register read/write status */
387/* NOTE: these assume a local dhdsdio_bus_t *bus! */
388#define R_SDREG(regvar, regaddr, retryvar) \
389do { \
390 retryvar = 0; \
391 do { \
392 regvar = R_REG(bus->dhd->osh, regaddr); \
393 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
394 if (retryvar) { \
395 bus->regfails += (retryvar-1); \
396 if (retryvar > retry_limit) { \
397 DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \
398 __FUNCTION__, __LINE__)); \
399 regvar = 0; \
400 } \
401 } \
402} while (0)
403
404#define W_SDREG(regval, regaddr, retryvar) \
405do { \
406 retryvar = 0; \
407 do { \
408 W_REG(bus->dhd->osh, regaddr, regval); \
409 } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \
410 if (retryvar) { \
411 bus->regfails += (retryvar-1); \
412 if (retryvar > retry_limit) \
413 DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \
414 __FUNCTION__, __LINE__)); \
415 } \
416} while (0)
417
418
419#define DHD_BUS SDIO_BUS
420
421#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
422
423#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE)
424
425#define GSPI_PR55150_BAILOUT
426
427
428#ifdef SDTEST
429static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq);
430static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start);
431#endif
432
433#ifdef DHD_DEBUG_TRAP
434static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size);
435#endif /* DHD_DEBUG_TRAP */
436static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
437
438static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh);
439static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh);
440static void dhdsdio_disconnect(void *ptr);
441static bool dhdsdio_chipmatch(uint16 chipid);
442static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh,
443 void * regsva, uint16 devid);
444static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh);
445static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh);
446static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, int reset_flag);
447
448static uint process_nvram_vars(char *varbuf, uint len);
449
450static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size);
451static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
452 uint8 *buf, uint nbytes,
453 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
454static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags,
455 uint8 *buf, uint nbytes,
456 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle);
457
458static bool dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh);
459static int _dhdsdio_download_firmware(struct dhd_bus *bus);
460
461static int dhdsdio_download_code_file(struct dhd_bus *bus, char *image_path);
462static int dhdsdio_download_nvram(struct dhd_bus *bus);
463#ifdef BCMEMBEDIMAGE
464static int dhdsdio_download_code_array(struct dhd_bus *bus);
465#endif
466
467
468static void
469dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
470{
471 int32 min_size = DONGLE_MIN_MEMSIZE;
472 /* Restrict the memsize to user specified limit */
473 DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n",
474 dhd_dongle_memsize, min_size));
475 if ((dhd_dongle_memsize > min_size) &&
476 (dhd_dongle_memsize < (int32)bus->orig_ramsize))
477 bus->ramsize = dhd_dongle_memsize;
478}
479
480static int
481dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address)
482{
483 int err = 0;
484 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
485 (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
486 if (!err)
487 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
488 (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
489 if (!err)
490 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
491 (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
492 return err;
493}
494
495
496/* Turn backplane clock on or off */
497static int
498dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok)
499{
500 int err;
501 uint8 clkctl, clkreq, devctl;
502 bcmsdh_info_t *sdh;
503
504 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
505
506#if defined(OOB_INTR_ONLY)
507 pendok = FALSE;
508#endif
509 clkctl = 0;
510 sdh = bus->sdh;
511
512
513 if (on) {
514 /* Request HT Avail */
515 clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
516
517 if ((bus->sih->chip == BCM4329_CHIP_ID) && (bus->sih->chiprev == 0))
518 clkreq |= SBSDIO_FORCE_ALP;
519
520
521
522
523 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
524 if (err) {
525 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
526 return BCME_ERROR;
527 }
528
529 if (pendok &&
530 ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) {
531 uint32 dummy, retries;
532 R_SDREG(dummy, &bus->regs->clockctlstatus, retries);
533 }
534
535 /* Check current status */
536 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
537 if (err) {
538 DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err));
539 return BCME_ERROR;
540 }
541
542 /* Go to pending and await interrupt if appropriate */
543 if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
544 /* Allow only clock-available interrupt */
545 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
546 if (err) {
547 DHD_ERROR(("%s: Devctl access error setting CA: %d\n",
548 __FUNCTION__, err));
549 return BCME_ERROR;
550 }
551
552 devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
553 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
554 DHD_INFO(("CLKCTL: set PENDING\n"));
555 bus->clkstate = CLK_PENDING;
556 return BCME_OK;
557 } else if (bus->clkstate == CLK_PENDING) {
558 /* Cancel CA-only interrupt filter */
559 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
560 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
561 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
562 }
563
564 /* Otherwise, wait here (polling) for HT Avail */
565 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
566 SPINWAIT_SLEEP(sdioh_spinwait_sleep,
567 ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
568 SBSDIO_FUNC1_CHIPCLKCSR, &err)),
569 !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY);
570 }
571 if (err) {
572 DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err));
573 return BCME_ERROR;
574 }
575 if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
576 DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n",
577 __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl));
578 return BCME_ERROR;
579 }
580
581
582 /* Mark clock available */
583 bus->clkstate = CLK_AVAIL;
584 DHD_INFO(("CLKCTL: turned ON\n"));
585
586#if defined(DHD_DEBUG)
587 if (bus->alp_only == TRUE) {
588#if !defined(BCMLXSDMMC)
589 if (!SBSDIO_ALPONLY(clkctl)) {
590 DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__));
591 }
592#endif /* !defined(BCMLXSDMMC) */
593 } else {
594 if (SBSDIO_ALPONLY(clkctl)) {
595 DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__));
596 }
597 }
598#endif /* defined (DHD_DEBUG) */
599
600 bus->activity = TRUE;
601 } else {
602 clkreq = 0;
603
604 if (bus->clkstate == CLK_PENDING) {
605 /* Cancel CA-only interrupt filter */
606 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
607 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
608 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
609 }
610
611 bus->clkstate = CLK_SDONLY;
612 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
613 DHD_INFO(("CLKCTL: turned OFF\n"));
614 if (err) {
615 DHD_ERROR(("%s: Failed access turning clock off: %d\n",
616 __FUNCTION__, err));
617 return BCME_ERROR;
618 }
619 }
620 return BCME_OK;
621}
622
623/* Change idle/active SD state */
624static int
625dhdsdio_sdclk(dhd_bus_t *bus, bool on)
626{
627 int err;
628 int32 iovalue;
629
630 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
631
632 if (on) {
633 if (bus->idleclock == DHD_IDLE_STOP) {
634 /* Turn on clock and restore mode */
635 iovalue = 1;
636 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
637 &iovalue, sizeof(iovalue), TRUE);
638 if (err) {
639 DHD_ERROR(("%s: error enabling sd_clock: %d\n",
640 __FUNCTION__, err));
641 return BCME_ERROR;
642 }
643
644 iovalue = bus->sd_mode;
645 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
646 &iovalue, sizeof(iovalue), TRUE);
647 if (err) {
648 DHD_ERROR(("%s: error changing sd_mode: %d\n",
649 __FUNCTION__, err));
650 return BCME_ERROR;
651 }
652 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
653 /* Restore clock speed */
654 iovalue = bus->sd_divisor;
655 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
656 &iovalue, sizeof(iovalue), TRUE);
657 if (err) {
658 DHD_ERROR(("%s: error restoring sd_divisor: %d\n",
659 __FUNCTION__, err));
660 return BCME_ERROR;
661 }
662 }
663 bus->clkstate = CLK_SDONLY;
664 } else {
665 /* Stop or slow the SD clock itself */
666 if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) {
667 DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n",
668 __FUNCTION__, bus->sd_divisor, bus->sd_mode));
669 return BCME_ERROR;
670 }
671 if (bus->idleclock == DHD_IDLE_STOP) {
672 if (sd1idle) {
673 /* Change to SD1 mode and turn off clock */
674 iovalue = 1;
675 err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
676 &iovalue, sizeof(iovalue), TRUE);
677 if (err) {
678 DHD_ERROR(("%s: error changing sd_clock: %d\n",
679 __FUNCTION__, err));
680 return BCME_ERROR;
681 }
682 }
683
684 iovalue = 0;
685 err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0,
686 &iovalue, sizeof(iovalue), TRUE);
687 if (err) {
688 DHD_ERROR(("%s: error disabling sd_clock: %d\n",
689 __FUNCTION__, err));
690 return BCME_ERROR;
691 }
692 } else if (bus->idleclock != DHD_IDLE_ACTIVE) {
693 /* Set divisor to idle value */
694 iovalue = bus->idleclock;
695 err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
696 &iovalue, sizeof(iovalue), TRUE);
697 if (err) {
698 DHD_ERROR(("%s: error changing sd_divisor: %d\n",
699 __FUNCTION__, err));
700 return BCME_ERROR;
701 }
702 }
703 bus->clkstate = CLK_NONE;
704 }
705
706 return BCME_OK;
707}
708
709/* Transition SD and backplane clock readiness */
710static int
711dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok)
712{
713 int ret = BCME_OK;
714#ifdef DHD_DEBUG
715 uint oldstate = bus->clkstate;
716#endif /* DHD_DEBUG */
717
718 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
719
720 /* Early exit if we're already there */
721 if (bus->clkstate == target) {
722 if (target == CLK_AVAIL) {
723 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
724 bus->activity = TRUE;
725 }
726 return ret;
727 }
728
729 switch (target) {
730 case CLK_AVAIL:
731 /* Make sure SD clock is available */
732 if (bus->clkstate == CLK_NONE)
733 dhdsdio_sdclk(bus, TRUE);
734 /* Now request HT Avail on the backplane */
735 ret = dhdsdio_htclk(bus, TRUE, pendok);
736 if (ret == BCME_OK) {
737 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
738 bus->activity = TRUE;
739 }
740 break;
741
742 case CLK_SDONLY:
743 /* Remove HT request, or bring up SD clock */
744 if (bus->clkstate == CLK_NONE)
745 ret = dhdsdio_sdclk(bus, TRUE);
746 else if (bus->clkstate == CLK_AVAIL)
747 ret = dhdsdio_htclk(bus, FALSE, FALSE);
748 else
749 DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n",
750 bus->clkstate, target));
751 if (ret == BCME_OK)
752 dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms);
753 break;
754
755 case CLK_NONE:
756 /* Make sure to remove HT request */
757 if (bus->clkstate == CLK_AVAIL)
758 ret = dhdsdio_htclk(bus, FALSE, FALSE);
759 /* Now remove the SD clock */
760 ret = dhdsdio_sdclk(bus, FALSE);
761 dhd_os_wd_timer(bus->dhd, 0);
762 break;
763 }
764#ifdef DHD_DEBUG
765 DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate));
766#endif /* DHD_DEBUG */
767
768 return ret;
769}
770
771int
772dhdsdio_bussleep(dhd_bus_t *bus, bool sleep)
773{
774 bcmsdh_info_t *sdh = bus->sdh;
775 sdpcmd_regs_t *regs = bus->regs;
776 uint retries = 0;
777
778 DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n",
779 (sleep ? "SLEEP" : "WAKE"),
780 (bus->sleeping ? "SLEEP" : "WAKE")));
781
782 /* Done if we're already in the requested state */
783 if (sleep == bus->sleeping)
784 return BCME_OK;
785
786 /* Going to sleep: set the alarm and turn off the lights... */
787 if (sleep) {
788 /* Don't sleep if something is pending */
789 if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq))
790 return BCME_BUSY;
791
792
793 /* Disable SDIO interrupts (no longer interested) */
794 bcmsdh_intr_disable(bus->sdh);
795
796 /* Make sure the controller has the bus up */
797 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
798
799 /* Tell device to start using OOB wakeup */
800 W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
801 if (retries > retry_limit)
802 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
803
804 /* Turn off our contribution to the HT clock request */
805 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
806
807 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
808 SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
809
810 /* Isolate the bus */
811 if (bus->sih->chip != BCM4329_CHIP_ID && bus->sih->chip != BCM4319_CHIP_ID) {
812 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL,
813 SBSDIO_DEVCTL_PADS_ISO, NULL);
814 }
815
816 /* Change state */
817 bus->sleeping = TRUE;
818
819 } else {
820 /* Waking up: bus power up is ok, set local state */
821
822 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
823 0, NULL);
824
825 /* Force pad isolation off if possible (in case power never toggled) */
826 if ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev >= 10))
827 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL);
828
829
830 /* Make sure the controller has the bus up */
831 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
832
833 /* Send misc interrupt to indicate OOB not needed */
834 W_SDREG(0, &regs->tosbmailboxdata, retries);
835 if (retries <= retry_limit)
836 W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
837
838 if (retries > retry_limit)
839 DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"));
840
841 /* Make sure we have SD bus access */
842 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
843
844 /* Change state */
845 bus->sleeping = FALSE;
846
847 /* Enable interrupts again */
848 if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) {
849 bus->intdis = FALSE;
850 bcmsdh_intr_enable(bus->sdh);
851 }
852 }
853
854 return BCME_OK;
855}
856#if defined(OOB_INTR_ONLY)
857void
858dhd_enable_oob_intr(struct dhd_bus *bus, bool enable)
859{
860#if defined(HW_OOB)
861 bcmsdh_enable_hw_oob_intr(bus->sdh, enable);
862#else
863 sdpcmd_regs_t *regs = bus->regs;
864 uint retries = 0;
865
866 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
867 if (enable == TRUE) {
868
869 /* Tell device to start using OOB wakeup */
870 W_SDREG(SMB_USE_OOB, &regs->tosbmailbox, retries);
871 if (retries > retry_limit)
872 DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"));
873
874 } else {
875 /* Send misc interrupt to indicate OOB not needed */
876 W_SDREG(0, &regs->tosbmailboxdata, retries);
877 if (retries <= retry_limit)
878 W_SDREG(SMB_DEV_INT, &regs->tosbmailbox, retries);
879 }
880
881 /* Turn off our contribution to the HT clock request */
882 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
883#endif /* !defined(HW_OOB) */
884}
885#endif /* defined(OOB_INTR_ONLY) */
886
887#define BUS_WAKE(bus) \
888 do { \
889 if ((bus)->sleeping) \
890 dhdsdio_bussleep((bus), FALSE); \
891 } while (0);
892
893
894/* Writes a HW/SW header into the packet and sends it. */
895/* Assumes: (a) header space already there, (b) caller holds lock */
896static int
897dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt)
898{
899 int ret;
900 osl_t *osh;
901 uint8 *frame;
902 uint16 len, pad = 0;
903 uint32 swheader;
904 uint retries = 0;
905 bcmsdh_info_t *sdh;
906 void *new;
907 int i;
908
909 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
910
911 sdh = bus->sdh;
912 osh = bus->dhd->osh;
913
914 if (bus->dhd->dongle_reset) {
915 ret = BCME_NOTREADY;
916 goto done;
917 }
918
919 frame = (uint8*)PKTDATA(osh, pkt);
920
921 /* Add alignment padding, allocate new packet if needed */
922 if ((pad = ((uintptr)frame % DHD_SDALIGN))) {
923 if (PKTHEADROOM(osh, pkt) < pad) {
924 DHD_INFO(("%s: insufficient headroom %d for %d pad\n",
925 __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad));
926 bus->dhd->tx_realloc++;
927 new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE);
928 if (!new) {
929 DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n",
930 __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN));
931 ret = BCME_NOMEM;
932 goto done;
933 }
934
935 PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN);
936 bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt));
937 if (free_pkt)
938 PKTFREE(osh, pkt, TRUE);
939 /* free the pkt if canned one is not used */
940 free_pkt = TRUE;
941 pkt = new;
942 frame = (uint8*)PKTDATA(osh, pkt);
943 ASSERT(((uintptr)frame % DHD_SDALIGN) == 0);
944 pad = 0;
945 } else {
946 PKTPUSH(osh, pkt, pad);
947 frame = (uint8*)PKTDATA(osh, pkt);
948
949 ASSERT((pad + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt));
950 bzero(frame, pad + SDPCM_HDRLEN);
951 }
952 }
953 ASSERT(pad < DHD_SDALIGN);
954
955 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
956 len = (uint16)PKTLEN(osh, pkt);
957 *(uint16*)frame = htol16(len);
958 *(((uint16*)frame) + 1) = htol16(~len);
959
960 /* Software tag: channel, sequence number, data offset */
961 swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq |
962 (((pad + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
963 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
964 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
965
966#ifdef DHD_DEBUG
967 tx_packets[PKTPRIO(pkt)]++;
968 if (DHD_BYTES_ON() &&
969 (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) ||
970 (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) {
971 prhex("Tx Frame", frame, len);
972 } else if (DHD_HDRS_ON()) {
973 prhex("TxHdr", frame, MIN(len, 16));
974 }
975#endif
976
977 /* Raise len to next SDIO block to eliminate tail command */
978 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
979 uint16 pad = bus->blocksize - (len % bus->blocksize);
980 if ((pad <= bus->roundup) && (pad < bus->blocksize))
981#ifdef NOTUSED
982 if (pad <= PKTTAILROOM(osh, pkt))
983#endif /* NOTUSED */
984 len += pad;
985 } else if (len % DHD_SDALIGN) {
986 len += DHD_SDALIGN - (len % DHD_SDALIGN);
987 }
988
989 /* Some controllers have trouble with odd bytes -- round to even */
990 if (forcealign && (len & (ALIGNMENT - 1))) {
991#ifdef NOTUSED
992 if (PKTTAILROOM(osh, pkt))
993#endif
994 len = ROUNDUP(len, ALIGNMENT);
995#ifdef NOTUSED
996 else
997 DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len));
998#endif
999 }
1000
1001 do {
1002 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1003 frame, len, pkt, NULL, NULL);
1004 bus->f2txdata++;
1005 ASSERT(ret != BCME_PENDING);
1006
1007 if (ret < 0) {
1008 /* On failure, abort the command and terminate the frame */
1009 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1010 __FUNCTION__, ret));
1011 bus->tx_sderrs++;
1012
1013 bcmsdh_abort(sdh, SDIO_FUNC_2);
1014 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1015 SFC_WF_TERM, NULL);
1016 bus->f1regdata++;
1017
1018 for (i = 0; i < 3; i++) {
1019 uint8 hi, lo;
1020 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1021 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1022 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1023 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1024 bus->f1regdata += 2;
1025 if ((hi == 0) && (lo == 0))
1026 break;
1027 }
1028
1029 }
1030 if (ret == 0) {
1031 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1032 }
1033 } while ((ret < 0) && retrydata && retries++ < TXRETRIES);
1034
1035done:
1036 /* restore pkt buffer pointer before calling tx complete routine */
1037 PKTPULL(osh, pkt, SDPCM_HDRLEN + pad);
1038 dhd_os_sdunlock(bus->dhd);
1039 dhd_txcomplete(bus->dhd, pkt, ret != 0);
1040 dhd_os_sdlock(bus->dhd);
1041
1042 if (free_pkt)
1043 PKTFREE(osh, pkt, TRUE);
1044
1045 return ret;
1046}
1047
1048int
1049dhd_bus_txdata(struct dhd_bus *bus, void *pkt)
1050{
1051 int ret = BCME_ERROR;
1052 osl_t *osh;
1053 uint datalen, prec;
1054
1055 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1056
1057 osh = bus->dhd->osh;
1058 datalen = PKTLEN(osh, pkt);
1059
1060#ifdef SDTEST
1061 /* Push the test header if doing loopback */
1062 if (bus->ext_loop) {
1063 uint8* data;
1064 PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN);
1065 data = PKTDATA(osh, pkt);
1066 *data++ = SDPCM_TEST_ECHOREQ;
1067 *data++ = (uint8)bus->loopid++;
1068 *data++ = (datalen >> 0);
1069 *data++ = (datalen >> 8);
1070 datalen += SDPCM_TEST_HDRLEN;
1071 }
1072#endif /* SDTEST */
1073
1074 /* Add space for the header */
1075 PKTPUSH(osh, pkt, SDPCM_HDRLEN);
1076 ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2));
1077
1078 prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK));
1079
1080
1081 /* Check for existing queue, current flow-control, pending event, or pending clock */
1082 if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched ||
1083 (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) ||
1084 (bus->clkstate != CLK_AVAIL)) {
1085 DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__,
1086 pktq_len(&bus->txq)));
1087 bus->fcqueued++;
1088
1089 /* Priority based enq */
1090 dhd_os_sdlock_txq(bus->dhd);
1091 if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) {
1092 PKTPULL(osh, pkt, SDPCM_HDRLEN);
1093 dhd_txcomplete(bus->dhd, pkt, FALSE);
1094 PKTFREE(osh, pkt, TRUE);
1095 DHD_ERROR(("%s: out of bus->txq !!!\n", __FUNCTION__));
1096 ret = BCME_NORESOURCE;
1097 } else {
1098 ret = BCME_OK;
1099 }
1100 dhd_os_sdunlock_txq(bus->dhd);
1101
1102 if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow)
1103 dhd_txflowcontrol(bus->dhd, 0, ON);
1104
1105#ifdef DHD_DEBUG
1106 if (pktq_plen(&bus->txq, prec) > qcount[prec])
1107 qcount[prec] = pktq_plen(&bus->txq, prec);
1108#endif
1109 /* Schedule DPC if needed to send queued packet(s) */
1110 if (dhd_deferred_tx && !bus->dpc_sched) {
1111 bus->dpc_sched = TRUE;
1112 dhd_sched_dpc(bus->dhd);
1113 }
1114 } else {
1115 /* Lock: we're about to use shared data/code (and SDIO) */
1116 dhd_os_sdlock(bus->dhd);
1117
1118 /* Otherwise, send it now */
1119 BUS_WAKE(bus);
1120 /* Make sure back plane ht clk is on, no pending allowed */
1121 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
1122
1123#ifndef SDTEST
1124 DHD_TRACE(("%s: calling txpkt\n", __FUNCTION__));
1125 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1126#else
1127 ret = dhdsdio_txpkt(bus, pkt,
1128 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1129#endif
1130 if (ret)
1131 bus->dhd->tx_errors++;
1132 else
1133 bus->dhd->dstats.tx_bytes += datalen;
1134
1135 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1136 bus->activity = FALSE;
1137 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1138 }
1139
1140 dhd_os_sdunlock(bus->dhd);
1141 }
1142
1143
1144 return ret;
1145}
1146
1147static uint
1148dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes)
1149{
1150 void *pkt;
1151 uint32 intstatus = 0;
1152 uint retries = 0;
1153 int ret = 0, prec_out;
1154 uint cnt = 0;
1155 uint datalen;
1156 uint8 tx_prec_map;
1157
1158 dhd_pub_t *dhd = bus->dhd;
1159 sdpcmd_regs_t *regs = bus->regs;
1160
1161 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1162
1163 tx_prec_map = ~bus->flowcontrol;
1164
1165 /* Send frames until the limit or some other event */
1166 for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) {
1167 dhd_os_sdlock_txq(bus->dhd);
1168 if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) {
1169 dhd_os_sdunlock_txq(bus->dhd);
1170 break;
1171 }
1172 dhd_os_sdunlock_txq(bus->dhd);
1173 datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN;
1174
1175#ifndef SDTEST
1176 ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE);
1177#else
1178 ret = dhdsdio_txpkt(bus, pkt,
1179 (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE);
1180#endif
1181 if (ret)
1182 bus->dhd->tx_errors++;
1183 else
1184 bus->dhd->dstats.tx_bytes += datalen;
1185
1186 /* In poll mode, need to check for other events */
1187 if (!bus->intr && cnt)
1188 {
1189 /* Check device status, signal pending interrupt */
1190 R_SDREG(intstatus, &regs->intstatus, retries);
1191 bus->f2txdata++;
1192 if (bcmsdh_regfail(bus->sdh))
1193 break;
1194 if (intstatus & bus->hostintmask)
1195 bus->ipend = TRUE;
1196 }
1197 }
1198
1199 /* Deflow-control stack if needed */
1200 if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) &&
1201 dhd->txoff && (pktq_len(&bus->txq) < FCLOW))
1202 dhd_txflowcontrol(dhd, 0, OFF);
1203
1204 return cnt;
1205}
1206
1207int
1208dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1209{
1210 uint8 *frame;
1211 uint16 len;
1212 uint32 swheader;
1213 uint retries = 0;
1214 bcmsdh_info_t *sdh = bus->sdh;
1215 uint8 doff = 0;
1216 int ret = -1;
1217 int i;
1218
1219 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1220
1221 if (bus->dhd->dongle_reset)
1222 return -EIO;
1223
1224 /* Back the pointer to make a room for bus header */
1225 frame = msg - SDPCM_HDRLEN;
1226 len = (msglen += SDPCM_HDRLEN);
1227
1228 /* Add alignment padding (optional for ctl frames) */
1229 if (dhd_alignctl) {
1230 if ((doff = ((uintptr)frame % DHD_SDALIGN))) {
1231 frame -= doff;
1232 len += doff;
1233 msglen += doff;
1234 bzero(frame, doff + SDPCM_HDRLEN);
1235 }
1236 ASSERT(doff < DHD_SDALIGN);
1237 }
1238 doff += SDPCM_HDRLEN;
1239
1240 /* Round send length to next SDIO block */
1241 if (bus->roundup && bus->blocksize && (len > bus->blocksize)) {
1242 uint16 pad = bus->blocksize - (len % bus->blocksize);
1243 if ((pad <= bus->roundup) && (pad < bus->blocksize))
1244 len += pad;
1245 } else if (len % DHD_SDALIGN) {
1246 len += DHD_SDALIGN - (len % DHD_SDALIGN);
1247 }
1248
1249 /* Satisfy length-alignment requirements */
1250 if (forcealign && (len & (ALIGNMENT - 1)))
1251 len = ROUNDUP(len, ALIGNMENT);
1252
1253 ASSERT(ISALIGNED((uintptr)frame, 2));
1254
1255
1256 /* Need to lock here to protect txseq and SDIO tx calls */
1257 dhd_os_sdlock(bus->dhd);
1258
1259 BUS_WAKE(bus);
1260
1261 /* Make sure backplane clock is on */
1262 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
1263
1264 /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
1265 *(uint16*)frame = htol16((uint16)msglen);
1266 *(((uint16*)frame) + 1) = htol16(~msglen);
1267
1268 /* Software tag: channel, sequence number, data offset */
1269 swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK)
1270 | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK);
1271 htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN);
1272 htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader));
1273
1274 if (!DATAOK(bus)) {
1275 DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n",
1276 __FUNCTION__, bus->tx_max, bus->tx_seq));
1277 bus->ctrl_frame_stat = TRUE;
1278 /* Send from dpc */
1279 bus->ctrl_frame_buf = frame;
1280 bus->ctrl_frame_len = len;
1281
1282 dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat);
1283
1284 if (bus->ctrl_frame_stat == FALSE) {
1285 DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__));
1286 ret = 0;
1287 } else {
1288 if (!bus->dhd->hang_was_sent)
1289 DHD_ERROR(("%s: ctrl_frame_stat == TRUE\n", __FUNCTION__));
1290 ret = -1;
1291 }
1292 }
1293
1294 if (ret == -1) {
1295#ifdef DHD_DEBUG
1296 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
1297 prhex("Tx Frame", frame, len);
1298 } else if (DHD_HDRS_ON()) {
1299 prhex("TxHdr", frame, MIN(len, 16));
1300 }
1301#endif
1302
1303 do {
1304 bus->ctrl_frame_stat = FALSE;
1305 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
1306 frame, len, NULL, NULL, NULL);
1307 ASSERT(ret != BCME_PENDING);
1308
1309 if (ret < 0) {
1310 /* On failure, abort the command and terminate the frame */
1311 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
1312 __FUNCTION__, ret));
1313 bus->tx_sderrs++;
1314
1315 bcmsdh_abort(sdh, SDIO_FUNC_2);
1316
1317 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
1318 SFC_WF_TERM, NULL);
1319 bus->f1regdata++;
1320
1321 for (i = 0; i < 3; i++) {
1322 uint8 hi, lo;
1323 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1324 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
1325 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
1326 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
1327 bus->f1regdata += 2;
1328 if ((hi == 0) && (lo == 0))
1329 break;
1330 }
1331
1332 }
1333 if (ret == 0) {
1334 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
1335 }
1336 } while ((ret < 0) && retries++ < TXRETRIES);
1337 }
1338
1339 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
1340 bus->activity = FALSE;
1341 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
1342 }
1343
1344 dhd_os_sdunlock(bus->dhd);
1345
1346 if (ret)
1347 bus->dhd->tx_ctlerrs++;
1348 else
1349 bus->dhd->tx_ctlpkts++;
1350
1351 return ret ? -EIO : 0;
1352}
1353
1354int
1355dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen)
1356{
1357 int timeleft;
1358 uint rxlen = 0;
1359 bool pending;
1360
1361 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1362
1363 if (bus->dhd->dongle_reset)
1364 return -EIO;
1365
1366 /* Wait until control frame is available */
1367 timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending);
1368
1369 dhd_os_sdlock(bus->dhd);
1370 rxlen = bus->rxlen;
1371 bcopy(bus->rxctl, msg, MIN(msglen, rxlen));
1372 bus->rxlen = 0;
1373 dhd_os_sdunlock(bus->dhd);
1374
1375 if (rxlen) {
1376 DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n",
1377 __FUNCTION__, rxlen, msglen));
1378 } else if (timeleft == 0) {
1379 DHD_ERROR(("%s: resumed on timeout\n", __FUNCTION__));
1380#ifdef DHD_DEBUG_TRAP
1381 dhd_os_sdlock(bus->dhd);
1382 dhdsdio_checkdied(bus, NULL, 0);
1383 dhd_os_sdunlock(bus->dhd);
1384#endif /* DHD_DEBUG_TRAP */
1385 } else if (pending == TRUE) {
1386 DHD_CTL(("%s: cancelled\n", __FUNCTION__));
1387 return -ERESTARTSYS;
1388 } else {
1389 DHD_CTL(("%s: resumed for unknown reason?\n", __FUNCTION__));
1390#ifdef DHD_DEBUG_TRAP
1391 dhd_os_sdlock(bus->dhd);
1392 dhdsdio_checkdied(bus, NULL, 0);
1393 dhd_os_sdunlock(bus->dhd);
1394#endif /* DHD_DEBUG_TRAP */
1395 }
1396
1397 if (rxlen)
1398 bus->dhd->rx_ctlpkts++;
1399 else
1400 bus->dhd->rx_ctlerrs++;
1401
1402 return rxlen ? (int)rxlen : -ETIMEDOUT;
1403}
1404
1405/* IOVar table */
1406enum {
1407 IOV_INTR = 1,
1408 IOV_POLLRATE,
1409 IOV_SDREG,
1410 IOV_SBREG,
1411 IOV_SDCIS,
1412 IOV_MEMBYTES,
1413 IOV_MEMSIZE,
1414#ifdef DHD_DEBUG_TRAP
1415 IOV_CHECKDIED,
1416#endif
1417 IOV_DOWNLOAD,
1418 IOV_FORCEEVEN,
1419 IOV_SDIOD_DRIVE,
1420 IOV_READAHEAD,
1421 IOV_SDRXCHAIN,
1422 IOV_ALIGNCTL,
1423 IOV_SDALIGN,
1424 IOV_DEVRESET,
1425 IOV_CPU,
1426#ifdef SDTEST
1427 IOV_PKTGEN,
1428 IOV_EXTLOOP,
1429#endif /* SDTEST */
1430 IOV_SPROM,
1431 IOV_TXBOUND,
1432 IOV_RXBOUND,
1433 IOV_TXMINMAX,
1434 IOV_IDLETIME,
1435 IOV_IDLECLOCK,
1436 IOV_SD1IDLE,
1437 IOV_SLEEP,
1438 IOV_VARS
1439};
1440
1441const bcm_iovar_t dhdsdio_iovars[] = {
1442 {"intr", IOV_INTR, 0, IOVT_BOOL, 0 },
1443 {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 },
1444 {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 },
1445 {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 },
1446 {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 },
1447 {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 },
1448 {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) },
1449 {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 },
1450 {"download", IOV_DOWNLOAD, 0, IOVT_BOOL, 0 },
1451 {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 },
1452 {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 },
1453 {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 },
1454 {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 },
1455 {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 },
1456 {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 },
1457 {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 },
1458#ifdef DHD_DEBUG
1459 {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
1460 {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) },
1461 {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
1462 {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 },
1463 {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 },
1464 {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 },
1465 {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 },
1466 {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 },
1467#endif /* DHD_DEBUG */
1468#ifdef DHD_DEBUG_TRAP
1469 {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 },
1470#endif /* DHD_DEBUG_TRAP */
1471#ifdef SDTEST
1472 {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 },
1473 {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) },
1474#endif /* SDTEST */
1475
1476 {NULL, 0, 0, 0, 0 }
1477};
1478
1479static void
1480dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div)
1481{
1482 uint q1, q2;
1483
1484 if (!div) {
1485 bcm_bprintf(strbuf, "%s N/A", desc);
1486 } else {
1487 q1 = num / div;
1488 q2 = (100 * (num - (q1 * div))) / div;
1489 bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2);
1490 }
1491}
1492
1493void
1494dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
1495{
1496 dhd_bus_t *bus = dhdp->bus;
1497
1498 bcm_bprintf(strbuf, "Bus SDIO structure:\n");
1499 bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n",
1500 bus->hostintmask, bus->intstatus, bus->sdpcm_ver);
1501 bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n",
1502 bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip,
1503 bus->rxlen, bus->rx_seq);
1504 bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n",
1505 bus->intr, bus->intrcount, bus->lastintrs, bus->spurious);
1506 bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n",
1507 bus->pollrate, bus->pollcnt, bus->regfails);
1508
1509 bcm_bprintf(strbuf, "\nAdditional counters:\n");
1510 bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n",
1511 bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong,
1512 bus->rxc_errors);
1513 bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n",
1514 bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq);
1515 bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n",
1516 bus->fc_rcvd, bus->fc_xoff, bus->fc_xon);
1517 bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n",
1518 bus->rxglomfail, bus->rxglomframes, bus->rxglompkts);
1519 bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n",
1520 (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata,
1521 bus->f2txdata, bus->f1regdata);
1522 {
1523 dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets,
1524 (bus->f2rxhdrs + bus->f2rxdata));
1525 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata);
1526 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets,
1527 (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1528 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount);
1529 bcm_bprintf(strbuf, "\n");
1530
1531 dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts),
1532 bus->dhd->rx_packets);
1533 dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes);
1534 bcm_bprintf(strbuf, "\n");
1535
1536 dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata);
1537 dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata);
1538 dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets,
1539 (bus->f2txdata + bus->f1regdata));
1540 dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount);
1541 bcm_bprintf(strbuf, "\n");
1542
1543 dhd_dump_pct(strbuf, "Total: pkts/f2rw",
1544 (bus->dhd->tx_packets + bus->dhd->rx_packets),
1545 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata));
1546 dhd_dump_pct(strbuf, ", pkts/f1sd",
1547 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata);
1548 dhd_dump_pct(strbuf, ", pkts/sd",
1549 (bus->dhd->tx_packets + bus->dhd->rx_packets),
1550 (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata));
1551 dhd_dump_pct(strbuf, ", pkts/int",
1552 (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount);
1553 bcm_bprintf(strbuf, "\n\n");
1554 }
1555
1556#ifdef SDTEST
1557 if (bus->pktgen_count) {
1558 bcm_bprintf(strbuf, "pktgen config and count:\n");
1559 bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n",
1560 bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print,
1561 bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen);
1562 bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n",
1563 bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail);
1564 }
1565#endif /* SDTEST */
1566#ifdef DHD_DEBUG
1567 bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n",
1568 bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not "));
1569 bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup);
1570#endif /* DHD_DEBUG */
1571 bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n",
1572 bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping);
1573}
1574
1575void
1576dhd_bus_clearcounts(dhd_pub_t *dhdp)
1577{
1578 dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus;
1579
1580 bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0;
1581 bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0;
1582 bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0;
1583 bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0;
1584 bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0;
1585 bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0;
1586}
1587
1588#ifdef SDTEST
1589static int
1590dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg)
1591{
1592 dhd_pktgen_t pktgen;
1593
1594 pktgen.version = DHD_PKTGEN_VERSION;
1595 pktgen.freq = bus->pktgen_freq;
1596 pktgen.count = bus->pktgen_count;
1597 pktgen.print = bus->pktgen_print;
1598 pktgen.total = bus->pktgen_total;
1599 pktgen.minlen = bus->pktgen_minlen;
1600 pktgen.maxlen = bus->pktgen_maxlen;
1601 pktgen.numsent = bus->pktgen_sent;
1602 pktgen.numrcvd = bus->pktgen_rcvd;
1603 pktgen.numfail = bus->pktgen_fail;
1604 pktgen.mode = bus->pktgen_mode;
1605 pktgen.stop = bus->pktgen_stop;
1606
1607 bcopy(&pktgen, arg, sizeof(pktgen));
1608
1609 return 0;
1610}
1611
1612static int
1613dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg)
1614{
1615 dhd_pktgen_t pktgen;
1616 uint oldcnt, oldmode;
1617
1618 bcopy(arg, &pktgen, sizeof(pktgen));
1619 if (pktgen.version != DHD_PKTGEN_VERSION)
1620 return BCME_BADARG;
1621
1622 oldcnt = bus->pktgen_count;
1623 oldmode = bus->pktgen_mode;
1624
1625 bus->pktgen_freq = pktgen.freq;
1626 bus->pktgen_count = pktgen.count;
1627 bus->pktgen_print = pktgen.print;
1628 bus->pktgen_total = pktgen.total;
1629 bus->pktgen_minlen = pktgen.minlen;
1630 bus->pktgen_maxlen = pktgen.maxlen;
1631 bus->pktgen_mode = pktgen.mode;
1632 bus->pktgen_stop = pktgen.stop;
1633
1634 bus->pktgen_tick = bus->pktgen_ptick = 0;
1635 bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen);
1636 bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen);
1637
1638 /* Clear counts for a new pktgen (mode change, or was stopped) */
1639 if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode))
1640 bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0;
1641
1642 return 0;
1643}
1644#endif /* SDTEST */
1645
1646static int
1647dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size)
1648{
1649 int bcmerror = 0;
1650 uint32 sdaddr;
1651 uint dsize;
1652
1653 /* Determine initial transfer parameters */
1654 sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK;
1655 if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK)
1656 dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr);
1657 else
1658 dsize = size;
1659
1660 /* Set the backplane window to include the start address */
1661 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1662 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1663 goto xfer_done;
1664 }
1665
1666 /* Do the transfer(s) */
1667 while (size) {
1668 DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n",
1669 __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr,
1670 (address & SBSDIO_SBWINDOW_MASK)));
1671 if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) {
1672 DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__));
1673 break;
1674 }
1675
1676 /* Adjust for next transfer (if any) */
1677 if ((size -= dsize)) {
1678 data += dsize;
1679 address += dsize;
1680 if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) {
1681 DHD_ERROR(("%s: window change failed\n", __FUNCTION__));
1682 break;
1683 }
1684 sdaddr = 0;
1685 dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size);
1686 }
1687 }
1688
1689xfer_done:
1690 /* Return the window to backplane enumeration space for core access */
1691 if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) {
1692 DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__,
1693 bcmsdh_cur_sbwad(bus->sdh)));
1694 }
1695
1696 return bcmerror;
1697}
1698
1699#ifdef DHD_DEBUG_TRAP
1700static int
1701dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh)
1702{
1703 uint32 addr;
1704 int rv;
1705
1706 /* Read last word in memory to determine address of sdpcm_shared structure */
1707 if ((rv = dhdsdio_membytes(bus, FALSE, bus->ramsize - 4, (uint8 *)&addr, 4)) < 0)
1708 return rv;
1709
1710 addr = ltoh32(addr);
1711
1712 DHD_INFO(("sdpcm_shared address 0x%08X\n", addr));
1713
1714 /*
1715 * Check if addr is valid.
1716 * NVRAM length at the end of memory should have been overwritten.
1717 */
1718 if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) {
1719 DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", __FUNCTION__, addr));
1720 return BCME_ERROR;
1721 }
1722
1723 /* Read hndrte_shared structure */
1724 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0)
1725 return rv;
1726
1727 /* Endianness */
1728 sh->flags = ltoh32(sh->flags);
1729 sh->trap_addr = ltoh32(sh->trap_addr);
1730 sh->assert_exp_addr = ltoh32(sh->assert_exp_addr);
1731 sh->assert_file_addr = ltoh32(sh->assert_file_addr);
1732 sh->assert_line = ltoh32(sh->assert_line);
1733 sh->console_addr = ltoh32(sh->console_addr);
1734 sh->msgtrace_addr = ltoh32(sh->msgtrace_addr);
1735
1736 if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) {
1737 DHD_ERROR(("%s: sdpcm_shared version %d in dhd "
1738 "is different than sdpcm_shared version %d in dongle\n",
1739 __FUNCTION__, SDPCM_SHARED_VERSION,
1740 sh->flags & SDPCM_SHARED_VERSION_MASK));
1741 return BCME_ERROR;
1742 }
1743
1744 return BCME_OK;
1745}
1746
1747static int
1748dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size)
1749{
1750 int bcmerror = 0;
1751 uint msize = 512;
1752 char *mbuffer = NULL;
1753 uint maxstrlen = 256;
1754 char *str = NULL;
1755 trap_t tr;
1756 sdpcm_shared_t sdpcm_shared;
1757 struct bcmstrbuf strbuf;
1758
1759 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1760
1761 if (data == NULL) {
1762 /*
1763 * Called after a rx ctrl timeout. "data" is NULL.
1764 * allocate memory to trace the trap or assert.
1765 */
1766 size = msize;
1767 mbuffer = data = MALLOC(bus->dhd->osh, msize);
1768 if (mbuffer == NULL) {
1769 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize));
1770 bcmerror = BCME_NOMEM;
1771 goto done;
1772 }
1773 }
1774
1775 if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) {
1776 DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen));
1777 bcmerror = BCME_NOMEM;
1778 goto done;
1779 }
1780
1781 if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0)
1782 goto done;
1783
1784 bcm_binit(&strbuf, data, size);
1785
1786 bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n",
1787 sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr);
1788
1789 if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) {
1790 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
1791 * (Avoids conflict with real asserts for programmatic parsing of output.)
1792 */
1793 bcm_bprintf(&strbuf, "Assrt not built in dongle\n");
1794 }
1795
1796 if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) {
1797 /* NOTE: Misspelled assert is intentional - DO NOT FIX.
1798 * (Avoids conflict with real asserts for programmatic parsing of output.)
1799 */
1800 bcm_bprintf(&strbuf, "No trap%s in dongle",
1801 (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT)
1802 ?"/assrt" :"");
1803 } else {
1804 if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) {
1805 /* Download assert */
1806 bcm_bprintf(&strbuf, "Dongle assert");
1807 if (sdpcm_shared.assert_exp_addr != 0) {
1808 str[0] = '\0';
1809 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
1810 sdpcm_shared.assert_exp_addr,
1811 (uint8 *)str, maxstrlen)) < 0)
1812 goto done;
1813
1814 str[maxstrlen - 1] = '\0';
1815 bcm_bprintf(&strbuf, " expr \"%s\"", str);
1816 }
1817
1818 if (sdpcm_shared.assert_file_addr != 0) {
1819 str[0] = '\0';
1820 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
1821 sdpcm_shared.assert_file_addr,
1822 (uint8 *)str, maxstrlen)) < 0)
1823 goto done;
1824
1825 str[maxstrlen - 1] = '\0';
1826 bcm_bprintf(&strbuf, " file \"%s\"", str);
1827 }
1828
1829 bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line);
1830 }
1831
1832 if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
1833 if ((bcmerror = dhdsdio_membytes(bus, FALSE,
1834 sdpcm_shared.trap_addr,
1835 (uint8*)&tr, sizeof(trap_t))) < 0)
1836 goto done;
1837
1838 bcm_bprintf(&strbuf,
1839 "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x,"
1840 "lp 0x%x, rpc 0x%x Trap offset 0x%x, "
1841 "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n",
1842 tr.type, tr.epc, tr.cpsr, tr.spsr, tr.r13, tr.r14, tr.pc,
1843 sdpcm_shared.trap_addr,
1844 tr.r0, tr.r1, tr.r2, tr.r3, tr.r4, tr.r5, tr.r6, tr.r7);
1845 }
1846 }
1847
1848 if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) {
1849 DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
1850 }
1851
1852done:
1853 if (mbuffer)
1854 MFREE(bus->dhd->osh, mbuffer, msize);
1855 if (str)
1856 MFREE(bus->dhd->osh, str, maxstrlen);
1857
1858 return bcmerror;
1859}
1860#endif /* DHD_DEBUG_TRAP */
1861
1862#ifdef DHD_DEBUG
1863#define CONSOLE_LINE_MAX 192
1864
1865static int
1866dhdsdio_readconsole(dhd_bus_t *bus)
1867{
1868 dhd_console_t *c = &bus->console;
1869 uint8 line[CONSOLE_LINE_MAX], ch;
1870 uint32 n, idx, addr;
1871 int rv;
1872
1873 /* Don't do anything until FWREADY updates console address */
1874 if (bus->console_addr == 0)
1875 return 0;
1876
1877 /* Read console log struct */
1878 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log);
1879 if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0)
1880 return rv;
1881
1882 /* Allocate console buffer (one time only) */
1883 if (c->buf == NULL) {
1884 c->bufsize = ltoh32(c->log.buf_size);
1885 if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL)
1886 return BCME_NOMEM;
1887 }
1888
1889 idx = ltoh32(c->log.idx);
1890
1891 /* Protect against corrupt value */
1892 if (idx > c->bufsize)
1893 return BCME_ERROR;
1894
1895 /* Skip reading the console buffer if the index pointer has not moved */
1896 if (idx == c->last)
1897 return BCME_OK;
1898
1899 /* Read the console buffer */
1900 addr = ltoh32(c->log.buf);
1901 if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0)
1902 return rv;
1903
1904 while (c->last != idx) {
1905 for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) {
1906 if (c->last == idx) {
1907 /* This would output a partial line. Instead, back up
1908 * the buffer pointer and output this line next time around.
1909 */
1910 if (c->last >= n)
1911 c->last -= n;
1912 else
1913 c->last = c->bufsize - n;
1914 goto break2;
1915 }
1916 ch = c->buf[c->last];
1917 c->last = (c->last + 1) % c->bufsize;
1918 if (ch == '\n')
1919 break;
1920 line[n] = ch;
1921 }
1922
1923 if (n > 0) {
1924 if (line[n - 1] == '\r')
1925 n--;
1926 line[n] = 0;
1927 printf("CONSOLE: %s\n", line);
1928 }
1929 }
1930break2:
1931
1932 return BCME_OK;
1933}
1934#endif /* DHD_DEBUG */
1935
1936int
1937dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len)
1938{
1939 int bcmerror = BCME_OK;
1940
1941 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1942
1943 /* Basic sanity checks */
1944 if (bus->dhd->up) {
1945 bcmerror = BCME_NOTDOWN;
1946 goto err;
1947 }
1948 if (!len) {
1949 bcmerror = BCME_BUFTOOSHORT;
1950 goto err;
1951 }
1952
1953 /* Free the old ones and replace with passed variables */
1954 if (bus->vars)
1955 MFREE(bus->dhd->osh, bus->vars, bus->varsz);
1956
1957 bus->vars = MALLOC(bus->dhd->osh, len);
1958 bus->varsz = bus->vars ? len : 0;
1959 if (bus->vars == NULL) {
1960 bcmerror = BCME_NOMEM;
1961 goto err;
1962 }
1963
1964 /* Copy the passed variables, which should include the terminating double-null */
1965 bcopy(arg, bus->vars, bus->varsz);
1966err:
1967 return bcmerror;
1968}
1969
1970static int
1971dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name,
1972 void *params, int plen, void *arg, int len, int val_size)
1973{
1974 int bcmerror = 0;
1975 int32 int_val = 0;
1976 bool bool_val = 0;
1977
1978 DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n",
1979 __FUNCTION__, actionid, name, params, plen, arg, len, val_size));
1980
1981 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
1982 goto exit;
1983
1984 if (plen >= (int)sizeof(int_val))
1985 bcopy(params, &int_val, sizeof(int_val));
1986
1987 bool_val = (int_val != 0) ? TRUE : FALSE;
1988
1989
1990 /* Some ioctls use the bus */
1991 dhd_os_sdlock(bus->dhd);
1992
1993 /* Check if dongle is in reset. If so, only allow DEVRESET iovars */
1994 if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) ||
1995 actionid == IOV_GVAL(IOV_DEVRESET))) {
1996 bcmerror = BCME_NOTREADY;
1997 goto exit;
1998 }
1999
2000 /* Handle sleep stuff before any clock mucking */
2001 if (vi->varid == IOV_SLEEP) {
2002 if (IOV_ISSET(actionid)) {
2003 bcmerror = dhdsdio_bussleep(bus, bool_val);
2004 } else {
2005 int_val = (int32)bus->sleeping;
2006 bcopy(&int_val, arg, val_size);
2007 }
2008 goto exit;
2009 }
2010
2011 /* Request clock to allow SDIO accesses */
2012 if (!bus->dhd->dongle_reset) {
2013 BUS_WAKE(bus);
2014 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2015 }
2016
2017 switch (actionid) {
2018 case IOV_GVAL(IOV_INTR):
2019 int_val = (int32)bus->intr;
2020 bcopy(&int_val, arg, val_size);
2021 break;
2022
2023 case IOV_SVAL(IOV_INTR):
2024 bus->intr = bool_val;
2025 bus->intdis = FALSE;
2026 if (bus->dhd->up) {
2027 if (bus->intr) {
2028 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
2029 bcmsdh_intr_enable(bus->sdh);
2030 } else {
2031 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
2032 bcmsdh_intr_disable(bus->sdh);
2033 }
2034 }
2035 break;
2036
2037 case IOV_GVAL(IOV_POLLRATE):
2038 int_val = (int32)bus->pollrate;
2039 bcopy(&int_val, arg, val_size);
2040 break;
2041
2042 case IOV_SVAL(IOV_POLLRATE):
2043 bus->pollrate = (uint)int_val;
2044 bus->poll = (bus->pollrate != 0);
2045 break;
2046
2047 case IOV_GVAL(IOV_IDLETIME):
2048 int_val = bus->idletime;
2049 bcopy(&int_val, arg, val_size);
2050 break;
2051
2052 case IOV_SVAL(IOV_IDLETIME):
2053 if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) {
2054 bcmerror = BCME_BADARG;
2055 } else {
2056 bus->idletime = int_val;
2057 }
2058 break;
2059
2060 case IOV_GVAL(IOV_IDLECLOCK):
2061 int_val = (int32)bus->idleclock;
2062 bcopy(&int_val, arg, val_size);
2063 break;
2064
2065 case IOV_SVAL(IOV_IDLECLOCK):
2066 bus->idleclock = int_val;
2067 break;
2068
2069 case IOV_GVAL(IOV_SD1IDLE):
2070 int_val = (int32)sd1idle;
2071 bcopy(&int_val, arg, val_size);
2072 break;
2073
2074 case IOV_SVAL(IOV_SD1IDLE):
2075 sd1idle = bool_val;
2076 break;
2077
2078
2079 case IOV_SVAL(IOV_MEMBYTES):
2080 case IOV_GVAL(IOV_MEMBYTES):
2081 {
2082 uint32 address;
2083 uint size, dsize;
2084 uint8 *data;
2085
2086 bool set = (actionid == IOV_SVAL(IOV_MEMBYTES));
2087
2088 ASSERT(plen >= 2*sizeof(int));
2089
2090 address = (uint32)int_val;
2091 bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val));
2092 size = (uint)int_val;
2093
2094 /* Do some validation */
2095 dsize = set ? plen - (2 * sizeof(int)) : len;
2096 if (dsize < size) {
2097 DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n",
2098 __FUNCTION__, (set ? "set" : "get"), address, size, dsize));
2099 bcmerror = BCME_BADARG;
2100 break;
2101 }
2102
2103 DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__,
2104 (set ? "write" : "read"), size, address));
2105
2106 /* If we know about SOCRAM, check for a fit */
2107 if ((bus->orig_ramsize) &&
2108 ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) {
2109 DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n",
2110 __FUNCTION__, bus->orig_ramsize, size, address));
2111 bcmerror = BCME_BADARG;
2112 break;
2113 }
2114
2115 /* Generate the actual data pointer */
2116 data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg;
2117
2118 /* Call to do the transfer */
2119 bcmerror = dhdsdio_membytes(bus, set, address, data, size);
2120
2121 break;
2122 }
2123
2124 case IOV_GVAL(IOV_MEMSIZE):
2125 int_val = (int32)bus->ramsize;
2126 bcopy(&int_val, arg, val_size);
2127 break;
2128
2129 case IOV_GVAL(IOV_SDIOD_DRIVE):
2130 int_val = (int32)dhd_sdiod_drive_strength;
2131 bcopy(&int_val, arg, val_size);
2132 break;
2133
2134 case IOV_SVAL(IOV_SDIOD_DRIVE):
2135 dhd_sdiod_drive_strength = int_val;
2136 si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength);
2137 break;
2138
2139 case IOV_SVAL(IOV_DOWNLOAD):
2140 bcmerror = dhdsdio_download_state(bus, bool_val);
2141 break;
2142
2143 case IOV_SVAL(IOV_VARS):
2144 bcmerror = dhdsdio_downloadvars(bus, arg, len);
2145 break;
2146
2147 case IOV_GVAL(IOV_READAHEAD):
2148 int_val = (int32)dhd_readahead;
2149 bcopy(&int_val, arg, val_size);
2150 break;
2151
2152 case IOV_SVAL(IOV_READAHEAD):
2153 if (bool_val && !dhd_readahead)
2154 bus->nextlen = 0;
2155 dhd_readahead = bool_val;
2156 break;
2157
2158 case IOV_GVAL(IOV_SDRXCHAIN):
2159 int_val = (int32)bus->use_rxchain;
2160 bcopy(&int_val, arg, val_size);
2161 break;
2162
2163 case IOV_SVAL(IOV_SDRXCHAIN):
2164 if (bool_val && !bus->sd_rxchain)
2165 bcmerror = BCME_UNSUPPORTED;
2166 else
2167 bus->use_rxchain = bool_val;
2168 break;
2169 case IOV_GVAL(IOV_ALIGNCTL):
2170 int_val = (int32)dhd_alignctl;
2171 bcopy(&int_val, arg, val_size);
2172 break;
2173
2174 case IOV_SVAL(IOV_ALIGNCTL):
2175 dhd_alignctl = bool_val;
2176 break;
2177
2178 case IOV_GVAL(IOV_SDALIGN):
2179 int_val = DHD_SDALIGN;
2180 bcopy(&int_val, arg, val_size);
2181 break;
2182
2183#ifdef DHD_DEBUG
2184 case IOV_GVAL(IOV_VARS):
2185 if (bus->varsz < (uint)len)
2186 bcopy(bus->vars, arg, bus->varsz);
2187 else
2188 bcmerror = BCME_BUFTOOSHORT;
2189 break;
2190#endif /* DHD_DEBUG */
2191
2192#ifdef DHD_DEBUG
2193 case IOV_GVAL(IOV_SDREG):
2194 {
2195 sdreg_t *sd_ptr;
2196 uint32 addr, size;
2197
2198 sd_ptr = (sdreg_t *)params;
2199
2200 addr = (uintptr)bus->regs + sd_ptr->offset;
2201 size = sd_ptr->func;
2202 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
2203 if (bcmsdh_regfail(bus->sdh))
2204 bcmerror = BCME_SDIO_ERROR;
2205 bcopy(&int_val, arg, sizeof(int32));
2206 break;
2207 }
2208
2209 case IOV_SVAL(IOV_SDREG):
2210 {
2211 sdreg_t *sd_ptr;
2212 uint32 addr, size;
2213
2214 sd_ptr = (sdreg_t *)params;
2215
2216 addr = (uintptr)bus->regs + sd_ptr->offset;
2217 size = sd_ptr->func;
2218 bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value);
2219 if (bcmsdh_regfail(bus->sdh))
2220 bcmerror = BCME_SDIO_ERROR;
2221 break;
2222 }
2223
2224 /* Same as above, but offset is not backplane (not SDIO core) */
2225 case IOV_GVAL(IOV_SBREG):
2226 {
2227 sdreg_t sdreg;
2228 uint32 addr, size;
2229
2230 bcopy(params, &sdreg, sizeof(sdreg));
2231
2232 addr = SI_ENUM_BASE + sdreg.offset;
2233 size = sdreg.func;
2234 int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size);
2235 if (bcmsdh_regfail(bus->sdh))
2236 bcmerror = BCME_SDIO_ERROR;
2237 bcopy(&int_val, arg, sizeof(int32));
2238 break;
2239 }
2240
2241 case IOV_SVAL(IOV_SBREG):
2242 {
2243 sdreg_t sdreg;
2244 uint32 addr, size;
2245
2246 bcopy(params, &sdreg, sizeof(sdreg));
2247
2248 addr = SI_ENUM_BASE + sdreg.offset;
2249 size = sdreg.func;
2250 bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value);
2251 if (bcmsdh_regfail(bus->sdh))
2252 bcmerror = BCME_SDIO_ERROR;
2253 break;
2254 }
2255
2256 case IOV_GVAL(IOV_SDCIS):
2257 {
2258 *(char *)arg = 0;
2259
2260 bcmstrcat(arg, "\nFunc 0\n");
2261 bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2262 bcmstrcat(arg, "\nFunc 1\n");
2263 bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2264 bcmstrcat(arg, "\nFunc 2\n");
2265 bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT);
2266 break;
2267 }
2268
2269 case IOV_GVAL(IOV_FORCEEVEN):
2270 int_val = (int32)forcealign;
2271 bcopy(&int_val, arg, val_size);
2272 break;
2273
2274 case IOV_SVAL(IOV_FORCEEVEN):
2275 forcealign = bool_val;
2276 break;
2277
2278 case IOV_GVAL(IOV_TXBOUND):
2279 int_val = (int32)dhd_txbound;
2280 bcopy(&int_val, arg, val_size);
2281 break;
2282
2283 case IOV_SVAL(IOV_TXBOUND):
2284 dhd_txbound = (uint)int_val;
2285 break;
2286
2287 case IOV_GVAL(IOV_RXBOUND):
2288 int_val = (int32)dhd_rxbound;
2289 bcopy(&int_val, arg, val_size);
2290 break;
2291
2292 case IOV_SVAL(IOV_RXBOUND):
2293 dhd_rxbound = (uint)int_val;
2294 break;
2295
2296 case IOV_GVAL(IOV_TXMINMAX):
2297 int_val = (int32)dhd_txminmax;
2298 bcopy(&int_val, arg, val_size);
2299 break;
2300
2301 case IOV_SVAL(IOV_TXMINMAX):
2302 dhd_txminmax = (uint)int_val;
2303 break;
2304
2305
2306
2307#endif /* DHD_DEBUG */
2308
2309
2310#ifdef SDTEST
2311 case IOV_GVAL(IOV_EXTLOOP):
2312 int_val = (int32)bus->ext_loop;
2313 bcopy(&int_val, arg, val_size);
2314 break;
2315
2316 case IOV_SVAL(IOV_EXTLOOP):
2317 bus->ext_loop = bool_val;
2318 break;
2319
2320 case IOV_GVAL(IOV_PKTGEN):
2321 bcmerror = dhdsdio_pktgen_get(bus, arg);
2322 break;
2323
2324 case IOV_SVAL(IOV_PKTGEN):
2325 bcmerror = dhdsdio_pktgen_set(bus, arg);
2326 break;
2327#endif /* SDTEST */
2328
2329
2330 case IOV_SVAL(IOV_DEVRESET):
2331 DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n",
2332 __FUNCTION__, bool_val, bus->dhd->dongle_reset,
2333 bus->dhd->busstate));
2334
2335 ASSERT(bus->dhd->osh);
2336 /* ASSERT(bus->cl_devid); */
2337
2338 dhd_bus_devreset(bus->dhd, (uint8)bool_val);
2339
2340 break;
2341
2342 case IOV_GVAL(IOV_DEVRESET):
2343 DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__));
2344
2345 /* Get its status */
2346 int_val = (bool) bus->dhd->dongle_reset;
2347 bcopy(&int_val, arg, val_size);
2348
2349 break;
2350
2351 default:
2352 bcmerror = BCME_UNSUPPORTED;
2353 break;
2354 }
2355
2356exit:
2357 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2358 bus->activity = FALSE;
2359 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2360 }
2361
2362 dhd_os_sdunlock(bus->dhd);
2363
2364 if (actionid == IOV_SVAL(IOV_DEVRESET) && bool_val == FALSE)
2365 dhd_preinit_ioctls((dhd_pub_t *) bus->dhd);
2366
2367 return bcmerror;
2368}
2369
2370static int
2371dhdsdio_write_vars(dhd_bus_t *bus)
2372{
2373 int bcmerror = 0;
2374 uint32 varsize;
2375 uint32 varaddr;
2376 uint8 *vbuffer;
2377 uint32 varsizew;
2378#ifdef DHD_DEBUG
2379 char *nvram_ularray;
2380#endif /* DHD_DEBUG */
2381
2382 /* Even if there are no vars are to be written, we still need to set the ramsize. */
2383 varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0;
2384 varaddr = (bus->ramsize - 4) - varsize;
2385
2386 if (bus->vars) {
2387 vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize);
2388 if (!vbuffer)
2389 return BCME_NOMEM;
2390
2391 bzero(vbuffer, varsize);
2392 bcopy(bus->vars, vbuffer, bus->varsz);
2393
2394 /* Write the vars list */
2395 bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize);
2396#ifdef DHD_DEBUG
2397 /* Verify NVRAM bytes */
2398 DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize));
2399 nvram_ularray = (char*)MALLOC(bus->dhd->osh, varsize);
2400 if (!nvram_ularray)
2401 return BCME_NOMEM;
2402
2403 /* Upload image to verify downloaded contents. */
2404 memset(nvram_ularray, 0xaa, varsize);
2405
2406 /* Read the vars list to temp buffer for comparison */
2407 bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize);
2408 if (bcmerror) {
2409 DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n",
2410 __FUNCTION__, bcmerror, varsize, varaddr));
2411 }
2412 /* Compare the org NVRAM with the one read from RAM */
2413 if (memcmp(vbuffer, nvram_ularray, varsize)) {
2414 DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__));
2415 } else
2416 DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n",
2417 __FUNCTION__));
2418
2419 MFREE(bus->dhd->osh, nvram_ularray, varsize);
2420#endif /* DHD_DEBUG */
2421
2422 MFREE(bus->dhd->osh, vbuffer, varsize);
2423 }
2424
2425 /* adjust to the user specified RAM */
2426 DHD_INFO(("Physical memory size: %d, usable memory size: %d\n",
2427 bus->orig_ramsize, bus->ramsize));
2428 DHD_INFO(("Vars are at %d, orig varsize is %d\n",
2429 varaddr, varsize));
2430 varsize = ((bus->orig_ramsize - 4) - varaddr);
2431
2432 /*
2433 * Determine the length token:
2434 * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits.
2435 */
2436 if (bcmerror) {
2437 varsizew = 0;
2438 } else {
2439 varsizew = varsize / 4;
2440 varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF);
2441 varsizew = htol32(varsizew);
2442 }
2443
2444 DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew));
2445
2446 /* Write the length token to the last word */
2447 bcmerror = dhdsdio_membytes(bus, TRUE, (bus->orig_ramsize - 4),
2448 (uint8*)&varsizew, 4);
2449
2450 return bcmerror;
2451}
2452
2453static int
2454dhdsdio_download_state(dhd_bus_t *bus, bool enter)
2455{
2456 uint retries;
2457 int bcmerror = 0;
2458
2459 /* To enter download state, disable ARM and reset SOCRAM.
2460 * To exit download state, simply reset ARM (default is RAM boot).
2461 */
2462 if (enter) {
2463
2464 bus->alp_only = TRUE;
2465
2466 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2467 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2468 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2469 bcmerror = BCME_ERROR;
2470 goto fail;
2471 }
2472
2473 si_core_disable(bus->sih, 0);
2474 if (bcmsdh_regfail(bus->sdh)) {
2475 bcmerror = BCME_SDIO_ERROR;
2476 goto fail;
2477 }
2478
2479 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2480 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2481 bcmerror = BCME_ERROR;
2482 goto fail;
2483 }
2484
2485 si_core_reset(bus->sih, 0, 0);
2486 if (bcmsdh_regfail(bus->sdh)) {
2487 DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__));
2488 bcmerror = BCME_SDIO_ERROR;
2489 goto fail;
2490 }
2491
2492 /* Clear the top bit of memory */
2493 if (bus->ramsize) {
2494 uint32 zeros = 0;
2495 dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4);
2496 }
2497 } else {
2498 if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) {
2499 DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__));
2500 bcmerror = BCME_ERROR;
2501 goto fail;
2502 }
2503
2504 if (!si_iscoreup(bus->sih)) {
2505 DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__));
2506 bcmerror = BCME_ERROR;
2507 goto fail;
2508 }
2509
2510 if ((bcmerror = dhdsdio_write_vars(bus))) {
2511 DHD_ERROR(("%s: no vars written to RAM\n", __FUNCTION__));
2512 bcmerror = 0;
2513 }
2514
2515 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) &&
2516 !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) {
2517 DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__));
2518 bcmerror = BCME_ERROR;
2519 goto fail;
2520 }
2521 W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries);
2522
2523
2524 if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) &&
2525 !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
2526 DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__));
2527 bcmerror = BCME_ERROR;
2528 goto fail;
2529 }
2530
2531 si_core_reset(bus->sih, 0, 0);
2532 if (bcmsdh_regfail(bus->sdh)) {
2533 DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__));
2534 bcmerror = BCME_SDIO_ERROR;
2535 goto fail;
2536 }
2537
2538 /* Allow HT Clock now that the ARM is running. */
2539 bus->alp_only = FALSE;
2540
2541 bus->dhd->busstate = DHD_BUS_LOAD;
2542 }
2543
2544fail:
2545 /* Always return to SDIOD core */
2546 if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0))
2547 si_setcore(bus->sih, SDIOD_CORE_ID, 0);
2548
2549 return bcmerror;
2550}
2551
2552int
2553dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
2554 void *params, int plen, void *arg, int len, bool set)
2555{
2556 dhd_bus_t *bus = dhdp->bus;
2557 const bcm_iovar_t *vi = NULL;
2558 int bcmerror = 0;
2559 int val_size;
2560 uint32 actionid;
2561
2562 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2563
2564 ASSERT(name);
2565 ASSERT(len >= 0);
2566
2567 /* Get MUST have return space */
2568 ASSERT(set || (arg && len));
2569
2570 /* Set does NOT take qualifiers */
2571 ASSERT(!set || (!params && !plen));
2572
2573 /* Look up var locally; if not found pass to host driver */
2574 if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) {
2575 dhd_os_sdlock(bus->dhd);
2576
2577 BUS_WAKE(bus);
2578
2579 /* Turn on clock in case SD command needs backplane */
2580 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2581
2582 bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set);
2583
2584 /* Check for bus configuration changes of interest */
2585
2586 /* If it was divisor change, read the new one */
2587 if (set && strcmp(name, "sd_divisor") == 0) {
2588 if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0,
2589 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
2590 bus->sd_divisor = -1;
2591 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2592 } else {
2593 DHD_INFO(("%s: noted %s update, value now %d\n",
2594 __FUNCTION__, name, bus->sd_divisor));
2595 }
2596 }
2597 /* If it was a mode change, read the new one */
2598 if (set && strcmp(name, "sd_mode") == 0) {
2599 if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0,
2600 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
2601 bus->sd_mode = -1;
2602 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name));
2603 } else {
2604 DHD_INFO(("%s: noted %s update, value now %d\n",
2605 __FUNCTION__, name, bus->sd_mode));
2606 }
2607 }
2608 /* Similar check for blocksize change */
2609 if (set && strcmp(name, "sd_blocksize") == 0) {
2610 int32 fnum = 2;
2611 if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32),
2612 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
2613 bus->blocksize = 0;
2614 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
2615 } else {
2616 DHD_INFO(("%s: noted %s update, value now %d\n",
2617 __FUNCTION__, "sd_blocksize", bus->blocksize));
2618 }
2619 }
2620 bus->roundup = MIN(max_roundup, bus->blocksize);
2621
2622 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
2623 bus->activity = FALSE;
2624 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
2625 }
2626
2627 dhd_os_sdunlock(bus->dhd);
2628 goto exit;
2629 }
2630
2631 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
2632 name, (set ? "set" : "get"), len, plen));
2633
2634 /* set up 'params' pointer in case this is a set command so that
2635 * the convenience int and bool code can be common to set and get
2636 */
2637 if (params == NULL) {
2638 params = arg;
2639 plen = len;
2640 }
2641
2642 if (vi->type == IOVT_VOID)
2643 val_size = 0;
2644 else if (vi->type == IOVT_BUFFER)
2645 val_size = len;
2646 else
2647 /* all other types are integer sized */
2648 val_size = sizeof(int);
2649
2650 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
2651 bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size);
2652
2653exit:
2654 return bcmerror;
2655}
2656
2657void
2658dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex)
2659{
2660 osl_t *osh = bus->dhd->osh;
2661 uint32 local_hostintmask;
2662 uint8 saveclk;
2663 uint retries;
2664 int err;
2665
2666 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2667
2668 if (enforce_mutex)
2669 dhd_os_sdlock(bus->dhd);
2670
2671 BUS_WAKE(bus);
2672
2673 /* Change our idea of bus state */
2674 bus->dhd->busstate = DHD_BUS_DOWN;
2675
2676 /* Enable clock for device interrupts */
2677 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2678
2679 /* Disable and clear interrupts at the chip level also */
2680 W_SDREG(0, &bus->regs->hostintmask, retries);
2681 local_hostintmask = bus->hostintmask;
2682 bus->hostintmask = 0;
2683
2684 /* Force clocks on backplane to be sure F2 interrupt propagates */
2685 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
2686 if (!err) {
2687 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
2688 (saveclk | SBSDIO_FORCE_HT), &err);
2689 }
2690 if (err) {
2691 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
2692 }
2693
2694 /* Turn off the bus (F2), free any pending packets */
2695 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
2696 bcmsdh_intr_disable(bus->sdh);
2697 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
2698
2699 /* Clear any pending interrupts now that F2 is disabled */
2700 W_SDREG(local_hostintmask, &bus->regs->intstatus, retries);
2701
2702 /* Turn off the backplane clock (only) */
2703 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
2704
2705 /* Clear the data packet queues */
2706 pktq_flush(osh, &bus->txq, TRUE);
2707
2708 /* Clear any held glomming stuff */
2709 if (bus->glomd)
2710 PKTFREE(osh, bus->glomd, FALSE);
2711
2712 if (bus->glom)
2713 PKTFREE(osh, bus->glom, FALSE);
2714
2715 bus->glom = bus->glomd = NULL;
2716
2717 /* Clear rx control and wake any waiters */
2718 bus->rxlen = 0;
2719 dhd_os_ioctl_resp_wake(bus->dhd);
2720
2721 /* Reset some F2 state stuff */
2722 bus->rxskip = FALSE;
2723 bus->tx_seq = bus->rx_seq = 0;
2724
2725 if (enforce_mutex)
2726 dhd_os_sdunlock(bus->dhd);
2727}
2728
2729int
2730dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex)
2731{
2732 dhd_bus_t *bus = dhdp->bus;
2733 dhd_timeout_t tmo;
2734 uint retries = 0;
2735 uint8 ready, enable;
2736 int err, ret = BCME_ERROR;
2737 uint8 saveclk;
2738
2739 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2740
2741 ASSERT(bus->dhd);
2742 if (!bus->dhd)
2743 return BCME_OK;
2744
2745 if (enforce_mutex)
2746 dhd_os_sdlock(bus->dhd);
2747
2748 /* Make sure backplane clock is on, needed to generate F2 interrupt */
2749 err = dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
2750 if ((err != BCME_OK) || (bus->clkstate != CLK_AVAIL)) {
2751 DHD_ERROR(("%s: Failed to set backplane clock: err %d\n", __FUNCTION__, err));
2752 goto exit;
2753 }
2754
2755 /* Force clocks on backplane to be sure F2 interrupt propagates */
2756 saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
2757 if (!err) {
2758 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
2759 (saveclk | SBSDIO_FORCE_HT), &err);
2760 }
2761 if (err) {
2762 DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err));
2763 goto exit;
2764 }
2765
2766 /* Enable function 2 (frame transfers) */
2767 W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT),
2768 &bus->regs->tosbmailboxdata, retries);
2769 enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
2770
2771 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
2772
2773 /* Give the dongle some time to do its thing and set IOR2 */
2774 dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000);
2775
2776 ready = 0;
2777 while (ready != enable && !dhd_timeout_expired(&tmo))
2778 ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL);
2779
2780
2781 DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n",
2782 __FUNCTION__, enable, ready, tmo.elapsed));
2783
2784
2785 /* If F2 successfully enabled, set core and enable interrupts */
2786 if (ready == enable) {
2787 /* Make sure we're talking to the core. */
2788 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)))
2789 bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0);
2790
2791 /* Set up the interrupt mask and enable interrupts */
2792 bus->hostintmask = HOSTINTMASK;
2793 W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries);
2794
2795 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err);
2796
2797 /* Set bus state according to enable result */
2798 dhdp->busstate = DHD_BUS_DATA;
2799
2800 /* bcmsdh_intr_unmask(bus->sdh); */
2801
2802 bus->intdis = FALSE;
2803 if (bus->intr) {
2804 DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__));
2805 bcmsdh_intr_enable(bus->sdh);
2806 } else {
2807 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
2808 bcmsdh_intr_disable(bus->sdh);
2809 }
2810
2811 }
2812
2813
2814 else {
2815 /* Disable F2 again */
2816 enable = SDIO_FUNC_ENABLE_1;
2817 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL);
2818 }
2819
2820 /* Restore previous clock setting */
2821 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
2822
2823
2824 /* If we didn't come up, turn off backplane clock */
2825 if (dhdp->busstate != DHD_BUS_DATA)
2826 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
2827
2828 ret = BCME_OK;
2829exit:
2830 if (enforce_mutex)
2831 dhd_os_sdunlock(bus->dhd);
2832
2833 return ret;
2834}
2835
2836static void
2837dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx)
2838{
2839 bcmsdh_info_t *sdh = bus->sdh;
2840 sdpcmd_regs_t *regs = bus->regs;
2841 uint retries = 0;
2842 uint16 lastrbc;
2843 uint8 hi, lo;
2844 int err;
2845
2846 DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__,
2847 (abort ? "abort command, " : ""), (rtx ? ", send NAK" : "")));
2848
2849 if (abort) {
2850 bcmsdh_abort(sdh, SDIO_FUNC_2);
2851 }
2852
2853 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err);
2854 bus->f1regdata++;
2855
2856 /* Wait until the packet has been flushed (device/FIFO stable) */
2857 for (lastrbc = retries = 0xffff; retries > 0; retries--) {
2858 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL);
2859 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL);
2860 bus->f1regdata += 2;
2861
2862 if ((hi == 0) && (lo == 0))
2863 break;
2864
2865 if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) {
2866 DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n",
2867 __FUNCTION__, lastrbc, ((hi << 8) + lo)));
2868 }
2869 lastrbc = (hi << 8) + lo;
2870 }
2871
2872 if (!retries) {
2873 DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc));
2874 } else {
2875 DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries)));
2876 }
2877
2878 if (rtx) {
2879 bus->rxrtx++;
2880 W_SDREG(SMB_NAK, &regs->tosbmailbox, retries);
2881 bus->f1regdata++;
2882 if (retries <= retry_limit) {
2883 bus->rxskip = TRUE;
2884 }
2885 }
2886
2887 /* Clear partial in any case */
2888 bus->nextlen = 0;
2889
2890 /* If we can't reach the device, signal failure */
2891 if (err || bcmsdh_regfail(sdh))
2892 bus->dhd->busstate = DHD_BUS_DOWN;
2893}
2894
2895static void
2896dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff)
2897{
2898 bcmsdh_info_t *sdh = bus->sdh;
2899 uint rdlen, pad;
2900
2901 int sdret;
2902
2903 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2904
2905 /* Control data already received in aligned rxctl */
2906 if ((bus->bus == SPI_BUS) && (!bus->usebufpool))
2907 goto gotpkt;
2908
2909 ASSERT(bus->rxbuf);
2910 /* Set rxctl for frame (w/optional alignment) */
2911 bus->rxctl = bus->rxbuf;
2912 if (dhd_alignctl) {
2913 bus->rxctl += firstread;
2914 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
2915 bus->rxctl += (DHD_SDALIGN - pad);
2916 bus->rxctl -= firstread;
2917 }
2918 ASSERT(bus->rxctl >= bus->rxbuf);
2919
2920 /* Copy the already-read portion over */
2921 bcopy(hdr, bus->rxctl, firstread);
2922 if (len <= firstread)
2923 goto gotpkt;
2924
2925 /* Copy the full data pkt in gSPI case and process ioctl. */
2926 if (bus->bus == SPI_BUS) {
2927 bcopy(hdr, bus->rxctl, len);
2928 goto gotpkt;
2929 }
2930
2931 /* Raise rdlen to next SDIO block to avoid tail command */
2932 rdlen = len - firstread;
2933 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
2934 pad = bus->blocksize - (rdlen % bus->blocksize);
2935 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
2936 ((len + pad) < bus->dhd->maxctl))
2937 rdlen += pad;
2938 } else if (rdlen % DHD_SDALIGN) {
2939 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
2940 }
2941
2942 /* Satisfy length-alignment requirements */
2943 if (forcealign && (rdlen & (ALIGNMENT - 1)))
2944 rdlen = ROUNDUP(rdlen, ALIGNMENT);
2945
2946 /* Drop if the read is too big or it exceeds our maximum */
2947 if ((rdlen + firstread) > bus->dhd->maxctl) {
2948 DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n",
2949 __FUNCTION__, rdlen, bus->dhd->maxctl));
2950 bus->dhd->rx_errors++;
2951 dhdsdio_rxfail(bus, FALSE, FALSE);
2952 goto done;
2953 }
2954
2955 if ((len - doff) > bus->dhd->maxctl) {
2956 DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n",
2957 __FUNCTION__, len, (len - doff), bus->dhd->maxctl));
2958 bus->dhd->rx_errors++; bus->rx_toolong++;
2959 dhdsdio_rxfail(bus, FALSE, FALSE);
2960 goto done;
2961 }
2962
2963
2964 /* Read remainder of frame body into the rxctl buffer */
2965 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
2966 (bus->rxctl + firstread), rdlen, NULL, NULL, NULL);
2967 bus->f2rxdata++;
2968 ASSERT(sdret != BCME_PENDING);
2969
2970 /* Control frame failures need retransmission */
2971 if (sdret < 0) {
2972 DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret));
2973 bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */
2974 dhdsdio_rxfail(bus, TRUE, TRUE);
2975 goto done;
2976 }
2977
2978gotpkt:
2979
2980#ifdef DHD_DEBUG
2981 if (DHD_BYTES_ON() && DHD_CTL_ON()) {
2982 prhex("RxCtrl", bus->rxctl, len);
2983 }
2984#endif
2985
2986 /* Point to valid data and indicate its length */
2987 bus->rxctl += doff;
2988 bus->rxlen = len - doff;
2989
2990done:
2991 /* Awake any waiters */
2992 dhd_os_ioctl_resp_wake(bus->dhd);
2993}
2994
2995static uint8
2996dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq)
2997{
2998 uint16 dlen, totlen;
2999 uint8 *dptr, num = 0;
3000
3001 uint16 sublen, check;
3002 void *pfirst, *plast, *pnext, *save_pfirst;
3003 osl_t *osh = bus->dhd->osh;
3004
3005 int errcode;
3006 uint8 chan, seq, doff, sfdoff;
3007 uint8 txmax;
3008
3009 int ifidx = 0;
3010 bool usechain = bus->use_rxchain;
3011
3012 /* If packets, issue read(s) and send up packet chain */
3013 /* Return sequence numbers consumed? */
3014
3015 DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom));
3016
3017 /* If there's a descriptor, generate the packet chain */
3018 if (bus->glomd) {
3019 dhd_os_sdlock_rxq(bus->dhd);
3020
3021 pfirst = plast = pnext = NULL;
3022 dlen = (uint16)PKTLEN(osh, bus->glomd);
3023 dptr = PKTDATA(osh, bus->glomd);
3024 if (!dlen || (dlen & 1)) {
3025 DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n",
3026 __FUNCTION__, dlen));
3027 dlen = 0;
3028 }
3029
3030 for (totlen = num = 0; dlen; num++) {
3031 /* Get (and move past) next length */
3032 sublen = ltoh16_ua(dptr);
3033 dlen -= sizeof(uint16);
3034 dptr += sizeof(uint16);
3035 if ((sublen < SDPCM_HDRLEN) ||
3036 ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) {
3037 DHD_ERROR(("%s: descriptor len %d bad: %d\n",
3038 __FUNCTION__, num, sublen));
3039 pnext = NULL;
3040 break;
3041 }
3042 if (sublen % DHD_SDALIGN) {
3043 DHD_ERROR(("%s: sublen %d not a multiple of %d\n",
3044 __FUNCTION__, sublen, DHD_SDALIGN));
3045 usechain = FALSE;
3046 }
3047 totlen += sublen;
3048
3049 /* For last frame, adjust read len so total is a block multiple */
3050 if (!dlen) {
3051 sublen += (ROUNDUP(totlen, bus->blocksize) - totlen);
3052 totlen = ROUNDUP(totlen, bus->blocksize);
3053 }
3054
3055 /* Allocate/chain packet for next subframe */
3056 if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) {
3057 DHD_ERROR(("%s: PKTGET failed, num %d len %d\n",
3058 __FUNCTION__, num, sublen));
3059 break;
3060 }
3061 ASSERT(!PKTLINK(pnext));
3062 if (!pfirst) {
3063 ASSERT(!plast);
3064 pfirst = plast = pnext;
3065 } else {
3066 ASSERT(plast);
3067 PKTSETNEXT(osh, plast, pnext);
3068 plast = pnext;
3069 }
3070
3071 /* Adhere to start alignment requirements */
3072 PKTALIGN(osh, pnext, sublen, DHD_SDALIGN);
3073 }
3074
3075 /* If all allocations succeeded, save packet chain in bus structure */
3076 if (pnext) {
3077 DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n",
3078 __FUNCTION__, totlen, num));
3079 if (DHD_GLOM_ON() && bus->nextlen) {
3080 if (totlen != bus->nextlen) {
3081 DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d "
3082 "rxseq %d\n", __FUNCTION__, bus->nextlen,
3083 totlen, rxseq));
3084 }
3085 }
3086 bus->glom = pfirst;
3087 pfirst = pnext = NULL;
3088 } else {
3089 if (pfirst)
3090 PKTFREE(osh, pfirst, FALSE);
3091 bus->glom = NULL;
3092 num = 0;
3093 }
3094
3095 /* Done with descriptor packet */
3096 PKTFREE(osh, bus->glomd, FALSE);
3097 bus->glomd = NULL;
3098 bus->nextlen = 0;
3099
3100 dhd_os_sdunlock_rxq(bus->dhd);
3101 }
3102
3103 /* Ok -- either we just generated a packet chain, or had one from before */
3104 if (bus->glom) {
3105 if (DHD_GLOM_ON()) {
3106 DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__));
3107 for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) {
3108 DHD_GLOM((" %p: %p len 0x%04x (%d)\n",
3109 pnext, (uint8*)PKTDATA(osh, pnext),
3110 PKTLEN(osh, pnext), PKTLEN(osh, pnext)));
3111 }
3112 }
3113
3114 pfirst = bus->glom;
3115 dlen = (uint16)pkttotlen(osh, pfirst);
3116
3117 /* Do an SDIO read for the superframe. Configurable iovar to
3118 * read directly into the chained packet, or allocate a large
3119 * packet and and copy into the chain.
3120 */
3121 if (usechain) {
3122 errcode = dhd_bcmsdh_recv_buf(bus,
3123 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
3124 F2SYNC, (uint8*)PKTDATA(osh, pfirst),
3125 dlen, pfirst, NULL, NULL);
3126 } else if (bus->dataptr) {
3127 errcode = dhd_bcmsdh_recv_buf(bus,
3128 bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2,
3129 F2SYNC, bus->dataptr,
3130 dlen, NULL, NULL, NULL);
3131 sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr);
3132 if (sublen != dlen) {
3133 DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n",
3134 __FUNCTION__, dlen, sublen));
3135 errcode = -1;
3136 }
3137 pnext = NULL;
3138 } else {
3139 DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen));
3140 errcode = -1;
3141 }
3142 bus->f2rxdata++;
3143 ASSERT(errcode != BCME_PENDING);
3144
3145 /* On failure, kill the superframe, allow a couple retries */
3146 if (errcode < 0) {
3147 DHD_ERROR(("%s: glom read of %d bytes failed: %d\n",
3148 __FUNCTION__, dlen, errcode));
3149 bus->dhd->rx_errors++;
3150
3151 if (bus->glomerr++ < 3) {
3152 dhdsdio_rxfail(bus, TRUE, TRUE);
3153 } else {
3154 bus->glomerr = 0;
3155 dhdsdio_rxfail(bus, TRUE, FALSE);
3156 dhd_os_sdlock_rxq(bus->dhd);
3157 PKTFREE(osh, bus->glom, FALSE);
3158 dhd_os_sdunlock_rxq(bus->dhd);
3159 bus->rxglomfail++;
3160 bus->glom = NULL;
3161 }
3162 return 0;
3163 }
3164
3165#ifdef DHD_DEBUG
3166 if (DHD_GLOM_ON()) {
3167 prhex("SUPERFRAME", PKTDATA(osh, pfirst),
3168 MIN(PKTLEN(osh, pfirst), 48));
3169 }
3170#endif
3171
3172
3173 /* Validate the superframe header */
3174 dptr = (uint8 *)PKTDATA(osh, pfirst);
3175 sublen = ltoh16_ua(dptr);
3176 check = ltoh16_ua(dptr + sizeof(uint16));
3177
3178 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3179 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3180 bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3181 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3182 DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n",
3183 __FUNCTION__, bus->nextlen, seq));
3184 bus->nextlen = 0;
3185 }
3186 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3187 txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3188
3189 errcode = 0;
3190 if ((uint16)~(sublen^check)) {
3191 DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n",
3192 __FUNCTION__, sublen, check));
3193 errcode = -1;
3194 } else if (ROUNDUP(sublen, bus->blocksize) != dlen) {
3195 DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n",
3196 __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen));
3197 errcode = -1;
3198 } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) {
3199 DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__,
3200 SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN])));
3201 errcode = -1;
3202 } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) {
3203 DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__));
3204 errcode = -1;
3205 } else if ((doff < SDPCM_HDRLEN) ||
3206 (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) {
3207 DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n",
3208 __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), SDPCM_HDRLEN));
3209 errcode = -1;
3210 }
3211
3212 /* Check sequence number of superframe SW header */
3213 if (rxseq != seq) {
3214 DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n",
3215 __FUNCTION__, seq, rxseq));
3216 bus->rx_badseq++;
3217 rxseq = seq;
3218 }
3219
3220 /* Check window for sanity */
3221 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3222 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3223 __FUNCTION__, txmax, bus->tx_seq));
3224 txmax = bus->tx_seq + 2;
3225 }
3226 bus->tx_max = txmax;
3227
3228 /* Remove superframe header, remember offset */
3229 PKTPULL(osh, pfirst, doff);
3230 sfdoff = doff;
3231
3232 /* Validate all the subframe headers */
3233 for (num = 0, pnext = pfirst; pnext && !errcode;
3234 num++, pnext = PKTNEXT(osh, pnext)) {
3235 dptr = (uint8 *)PKTDATA(osh, pnext);
3236 dlen = (uint16)PKTLEN(osh, pnext);
3237 sublen = ltoh16_ua(dptr);
3238 check = ltoh16_ua(dptr + sizeof(uint16));
3239 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3240 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3241#ifdef DHD_DEBUG
3242 if (DHD_GLOM_ON()) {
3243 prhex("subframe", dptr, 32);
3244 }
3245#endif
3246
3247 if ((uint16)~(sublen^check)) {
3248 DHD_ERROR(("%s (subframe %d): HW hdr error: "
3249 "len/check 0x%04x/0x%04x\n",
3250 __FUNCTION__, num, sublen, check));
3251 errcode = -1;
3252 } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) {
3253 DHD_ERROR(("%s (subframe %d): length mismatch: "
3254 "len 0x%04x, expect 0x%04x\n",
3255 __FUNCTION__, num, sublen, dlen));
3256 errcode = -1;
3257 } else if ((chan != SDPCM_DATA_CHANNEL) &&
3258 (chan != SDPCM_EVENT_CHANNEL)) {
3259 DHD_ERROR(("%s (subframe %d): bad channel %d\n",
3260 __FUNCTION__, num, chan));
3261 errcode = -1;
3262 } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) {
3263 DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n",
3264 __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN));
3265 errcode = -1;
3266 }
3267 }
3268
3269 if (errcode) {
3270 /* Terminate frame on error, request a couple retries */
3271 if (bus->glomerr++ < 3) {
3272 /* Restore superframe header space */
3273 PKTPUSH(osh, pfirst, sfdoff);
3274 dhdsdio_rxfail(bus, TRUE, TRUE);
3275 } else {
3276 bus->glomerr = 0;
3277 dhdsdio_rxfail(bus, TRUE, FALSE);
3278 dhd_os_sdlock_rxq(bus->dhd);
3279 PKTFREE(osh, bus->glom, FALSE);
3280 dhd_os_sdunlock_rxq(bus->dhd);
3281 bus->rxglomfail++;
3282 bus->glom = NULL;
3283 }
3284 bus->nextlen = 0;
3285 return 0;
3286 }
3287
3288 /* Basic SD framing looks ok - process each packet (header) */
3289 save_pfirst = pfirst;
3290 bus->glom = NULL;
3291 plast = NULL;
3292
3293 dhd_os_sdlock_rxq(bus->dhd);
3294 for (num = 0; pfirst; rxseq++, pfirst = pnext) {
3295 pnext = PKTNEXT(osh, pfirst);
3296 PKTSETNEXT(osh, pfirst, NULL);
3297
3298 dptr = (uint8 *)PKTDATA(osh, pfirst);
3299 sublen = ltoh16_ua(dptr);
3300 chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]);
3301 seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]);
3302 doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]);
3303
3304 DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n",
3305 __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst),
3306 PKTLEN(osh, pfirst), sublen, chan, seq));
3307
3308 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL));
3309
3310 if (rxseq != seq) {
3311 DHD_GLOM(("%s: rx_seq %d, expected %d\n",
3312 __FUNCTION__, seq, rxseq));
3313 bus->rx_badseq++;
3314 rxseq = seq;
3315 }
3316
3317#ifdef DHD_DEBUG
3318 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3319 prhex("Rx Subframe Data", dptr, dlen);
3320 }
3321#endif
3322
3323 PKTSETLEN(osh, pfirst, sublen);
3324 PKTPULL(osh, pfirst, doff);
3325
3326 if (PKTLEN(osh, pfirst) == 0) {
3327 PKTFREE(bus->dhd->osh, pfirst, FALSE);
3328 if (plast) {
3329 PKTSETNEXT(osh, plast, pnext);
3330 } else {
3331 ASSERT(save_pfirst == pfirst);
3332 save_pfirst = pnext;
3333 }
3334 continue;
3335 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst) != 0) {
3336 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
3337 bus->dhd->rx_errors++;
3338 PKTFREE(osh, pfirst, FALSE);
3339 if (plast) {
3340 PKTSETNEXT(osh, plast, pnext);
3341 } else {
3342 ASSERT(save_pfirst == pfirst);
3343 save_pfirst = pnext;
3344 }
3345 continue;
3346 }
3347
3348 /* this packet will go up, link back into chain and count it */
3349 PKTSETNEXT(osh, pfirst, pnext);
3350 plast = pfirst;
3351 num++;
3352
3353#ifdef DHD_DEBUG
3354 if (DHD_GLOM_ON()) {
3355 DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n",
3356 __FUNCTION__, num, pfirst,
3357 PKTDATA(osh, pfirst), PKTLEN(osh, pfirst),
3358 PKTNEXT(osh, pfirst), PKTLINK(pfirst)));
3359 prhex("", (uint8 *)PKTDATA(osh, pfirst),
3360 MIN(PKTLEN(osh, pfirst), 32));
3361 }
3362#endif /* DHD_DEBUG */
3363 }
3364 dhd_os_sdunlock_rxq(bus->dhd);
3365 if (num) {
3366 dhd_os_sdunlock(bus->dhd);
3367 dhd_rx_frame(bus->dhd, ifidx, save_pfirst, num);
3368 dhd_os_sdlock(bus->dhd);
3369 }
3370
3371 bus->rxglomframes++;
3372 bus->rxglompkts += num;
3373 }
3374 return num;
3375}
3376
3377/* Return TRUE if there may be more frames to read */
3378static uint
3379dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished)
3380{
3381 osl_t *osh = bus->dhd->osh;
3382 bcmsdh_info_t *sdh = bus->sdh;
3383
3384 uint16 len, check; /* Extracted hardware header fields */
3385 uint8 chan, seq, doff; /* Extracted software header fields */
3386 uint8 fcbits; /* Extracted fcbits from software header */
3387 uint8 delta;
3388
3389 void *pkt; /* Packet for event or data frames */
3390 uint16 pad; /* Number of pad bytes to read */
3391 uint16 rdlen; /* Total number of bytes to read */
3392 uint8 rxseq; /* Next sequence number to expect */
3393 uint rxleft = 0; /* Remaining number of frames allowed */
3394 int sdret; /* Return code from bcmsdh calls */
3395 uint8 txmax; /* Maximum tx sequence offered */
3396 bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */
3397 uint8 *rxbuf;
3398 int ifidx = 0;
3399 uint rxcount = 0; /* Total frames read */
3400
3401#if defined(DHD_DEBUG) || defined(SDTEST)
3402 bool sdtest = FALSE; /* To limit message spew from test mode */
3403#endif
3404
3405 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3406
3407 ASSERT(maxframes);
3408
3409#ifdef SDTEST
3410 /* Allow pktgen to override maxframes */
3411 if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) {
3412 maxframes = bus->pktgen_count;
3413 sdtest = TRUE;
3414 }
3415#endif
3416
3417 /* Not finished unless we encounter no more frames indication */
3418 *finished = FALSE;
3419
3420
3421 for (rxseq = bus->rx_seq, rxleft = maxframes;
3422 !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN;
3423 rxseq++, rxleft--) {
3424
3425 /* Handle glomming separately */
3426 if (bus->glom || bus->glomd) {
3427 uint8 cnt;
3428 DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n",
3429 __FUNCTION__, bus->glomd, bus->glom));
3430 cnt = dhdsdio_rxglom(bus, rxseq);
3431 DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt));
3432 rxseq += cnt - 1;
3433 rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1;
3434 continue;
3435 }
3436
3437 /* Try doing single read if we can */
3438 if (dhd_readahead && bus->nextlen) {
3439 uint16 nextlen = bus->nextlen;
3440 bus->nextlen = 0;
3441
3442 if (bus->bus == SPI_BUS) {
3443 rdlen = len = nextlen;
3444 }
3445 else {
3446 rdlen = len = nextlen << 4;
3447
3448 /* Pad read to blocksize for efficiency */
3449 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3450 pad = bus->blocksize - (rdlen % bus->blocksize);
3451 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3452 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
3453 rdlen += pad;
3454 } else if (rdlen % DHD_SDALIGN) {
3455 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3456 }
3457 }
3458
3459 /* We use bus->rxctl buffer in WinXP for initial control pkt receives.
3460 * Later we use buffer-poll for data as well as control packets.
3461 * This is required becuase dhd receives full frame in gSPI unlike SDIO.
3462 * After the frame is received we have to distinguish whether it is data
3463 * or non-data frame.
3464 */
3465 /* Allocate a packet buffer */
3466 dhd_os_sdlock_rxq(bus->dhd);
3467 if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) {
3468 if (bus->bus == SPI_BUS) {
3469 bus->usebufpool = FALSE;
3470 bus->rxctl = bus->rxbuf;
3471 if (dhd_alignctl) {
3472 bus->rxctl += firstread;
3473 if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN)))
3474 bus->rxctl += (DHD_SDALIGN - pad);
3475 bus->rxctl -= firstread;
3476 }
3477 ASSERT(bus->rxctl >= bus->rxbuf);
3478 rxbuf = bus->rxctl;
3479 /* Read the entire frame */
3480 sdret = dhd_bcmsdh_recv_buf(bus,
3481 bcmsdh_cur_sbwad(sdh),
3482 SDIO_FUNC_2,
3483 F2SYNC, rxbuf, rdlen,
3484 NULL, NULL, NULL);
3485 bus->f2rxdata++;
3486 ASSERT(sdret != BCME_PENDING);
3487
3488
3489 /* Control frame failures need retransmission */
3490 if (sdret < 0) {
3491 DHD_ERROR(("%s: read %d control bytes failed: %d\n",
3492 __FUNCTION__, rdlen, sdret));
3493 /* dhd.rx_ctlerrs is higher level */
3494 bus->rxc_errors++;
3495 dhd_os_sdunlock_rxq(bus->dhd);
3496 dhdsdio_rxfail(bus, TRUE,
3497 (bus->bus == SPI_BUS) ? FALSE : TRUE);
3498 continue;
3499 }
3500 } else {
3501 /* Give up on data, request rtx of events */
3502 DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d "
3503 "expected rxseq %d\n",
3504 __FUNCTION__, len, rdlen, rxseq));
3505 /* Just go try again w/normal header read */
3506 dhd_os_sdunlock_rxq(bus->dhd);
3507 continue;
3508 }
3509 } else {
3510 if (bus->bus == SPI_BUS)
3511 bus->usebufpool = TRUE;
3512
3513 ASSERT(!PKTLINK(pkt));
3514 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
3515 rxbuf = (uint8 *)PKTDATA(osh, pkt);
3516 /* Read the entire frame */
3517 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh),
3518 SDIO_FUNC_2,
3519 F2SYNC, rxbuf, rdlen,
3520 pkt, NULL, NULL);
3521 bus->f2rxdata++;
3522 ASSERT(sdret != BCME_PENDING);
3523
3524 if (sdret < 0) {
3525 DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n",
3526 __FUNCTION__, rdlen, sdret));
3527 PKTFREE(bus->dhd->osh, pkt, FALSE);
3528 bus->dhd->rx_errors++;
3529 dhd_os_sdunlock_rxq(bus->dhd);
3530 /* Force retry w/normal header read. Don't attemp NAK for
3531 * gSPI
3532 */
3533 dhdsdio_rxfail(bus, TRUE,
3534 (bus->bus == SPI_BUS) ? FALSE : TRUE);
3535 continue;
3536 }
3537 }
3538 dhd_os_sdunlock_rxq(bus->dhd);
3539
3540 /* Now check the header */
3541 bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN);
3542
3543 /* Extract hardware header fields */
3544 len = ltoh16_ua(bus->rxhdr);
3545 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
3546
3547 /* All zeros means readahead info was bad */
3548 if (!(len|check)) {
3549 DHD_INFO(("%s (nextlen): read zeros in HW header???\n",
3550 __FUNCTION__));
3551 dhd_os_sdlock_rxq(bus->dhd);
3552 PKTFREE2();
3553 dhd_os_sdunlock_rxq(bus->dhd);
3554 GSPI_PR55150_BAILOUT;
3555 continue;
3556 }
3557
3558 /* Validate check bytes */
3559 if ((uint16)~(len^check)) {
3560 DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check"
3561 " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen,
3562 len, check));
3563 dhd_os_sdlock_rxq(bus->dhd);
3564 PKTFREE2();
3565 dhd_os_sdunlock_rxq(bus->dhd);
3566 bus->rx_badhdr++;
3567 dhdsdio_rxfail(bus, FALSE, FALSE);
3568 GSPI_PR55150_BAILOUT;
3569 continue;
3570 }
3571
3572 /* Validate frame length */
3573 if (len < SDPCM_HDRLEN) {
3574 DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n",
3575 __FUNCTION__, len));
3576 dhd_os_sdlock_rxq(bus->dhd);
3577 PKTFREE2();
3578 dhd_os_sdunlock_rxq(bus->dhd);
3579 GSPI_PR55150_BAILOUT;
3580 continue;
3581 }
3582
3583 /* Check for consistency with readahead info */
3584 len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4));
3585 if (len_consistent) {
3586 /* Mismatch, force retry w/normal header (may be >4K) */
3587 DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; "
3588 "expected rxseq %d\n",
3589 __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq));
3590 dhd_os_sdlock_rxq(bus->dhd);
3591 PKTFREE2();
3592 dhd_os_sdunlock_rxq(bus->dhd);
3593 dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE);
3594 GSPI_PR55150_BAILOUT;
3595 continue;
3596 }
3597
3598
3599 /* Extract software header fields */
3600 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3601 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3602 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3603 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3604
3605 bus->nextlen =
3606 bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3607 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3608 DHD_INFO(("%s (nextlen): got frame w/nextlen too large"
3609 " (%d), seq %d\n", __FUNCTION__, bus->nextlen,
3610 seq));
3611 bus->nextlen = 0;
3612 }
3613
3614 bus->dhd->rx_readahead_cnt ++;
3615 /* Handle Flow Control */
3616 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3617
3618 delta = 0;
3619 if (~bus->flowcontrol & fcbits) {
3620 bus->fc_xoff++;
3621 delta = 1;
3622 }
3623 if (bus->flowcontrol & ~fcbits) {
3624 bus->fc_xon++;
3625 delta = 1;
3626 }
3627
3628 if (delta) {
3629 bus->fc_rcvd++;
3630 bus->flowcontrol = fcbits;
3631 }
3632
3633 /* Check and update sequence number */
3634 if (rxseq != seq) {
3635 DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n",
3636 __FUNCTION__, seq, rxseq));
3637 bus->rx_badseq++;
3638 rxseq = seq;
3639 }
3640
3641 /* Check window for sanity */
3642 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3643 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3644 __FUNCTION__, txmax, bus->tx_seq));
3645 txmax = bus->tx_seq + 2;
3646 }
3647 bus->tx_max = txmax;
3648
3649#ifdef DHD_DEBUG
3650 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3651 prhex("Rx Data", rxbuf, len);
3652 } else if (DHD_HDRS_ON()) {
3653 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
3654 }
3655#endif
3656
3657 if (chan == SDPCM_CONTROL_CHANNEL) {
3658 if (bus->bus == SPI_BUS) {
3659 dhdsdio_read_control(bus, rxbuf, len, doff);
3660 if (bus->usebufpool) {
3661 dhd_os_sdlock_rxq(bus->dhd);
3662 PKTFREE(bus->dhd->osh, pkt, FALSE);
3663 dhd_os_sdunlock_rxq(bus->dhd);
3664 }
3665 continue;
3666 } else {
3667 DHD_ERROR(("%s (nextlen): readahead on control"
3668 " packet %d?\n", __FUNCTION__, seq));
3669 /* Force retry w/normal header read */
3670 bus->nextlen = 0;
3671 dhdsdio_rxfail(bus, FALSE, TRUE);
3672 dhd_os_sdlock_rxq(bus->dhd);
3673 PKTFREE2();
3674 dhd_os_sdunlock_rxq(bus->dhd);
3675 continue;
3676 }
3677 }
3678
3679 if ((bus->bus == SPI_BUS) && !bus->usebufpool) {
3680 DHD_ERROR(("Received %d bytes on %d channel. Running out of "
3681 "rx pktbuf's or not yet malloced.\n", len, chan));
3682 continue;
3683 }
3684
3685 /* Validate data offset */
3686 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
3687 DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n",
3688 __FUNCTION__, doff, len, SDPCM_HDRLEN));
3689 dhd_os_sdlock_rxq(bus->dhd);
3690 PKTFREE2();
3691 dhd_os_sdunlock_rxq(bus->dhd);
3692 ASSERT(0);
3693 dhdsdio_rxfail(bus, FALSE, FALSE);
3694 continue;
3695 }
3696
3697 /* All done with this one -- now deliver the packet */
3698 goto deliver;
3699 }
3700 /* gSPI frames should not be handled in fractions */
3701 if (bus->bus == SPI_BUS) {
3702 break;
3703 }
3704
3705 /* Read frame header (hardware and software) */
3706 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3707 bus->rxhdr, firstread, NULL, NULL, NULL);
3708 bus->f2rxhdrs++;
3709 ASSERT(sdret != BCME_PENDING);
3710
3711 if (sdret < 0) {
3712 DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret));
3713 bus->rx_hdrfail++;
3714 dhdsdio_rxfail(bus, TRUE, TRUE);
3715 continue;
3716 }
3717
3718#ifdef DHD_DEBUG
3719 if (DHD_BYTES_ON() || DHD_HDRS_ON()) {
3720 prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN);
3721 }
3722#endif
3723
3724 /* Extract hardware header fields */
3725 len = ltoh16_ua(bus->rxhdr);
3726 check = ltoh16_ua(bus->rxhdr + sizeof(uint16));
3727
3728 /* All zeros means no more frames */
3729 if (!(len|check)) {
3730 *finished = TRUE;
3731 break;
3732 }
3733
3734 /* Validate check bytes */
3735 if ((uint16)~(len^check)) {
3736 DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n",
3737 __FUNCTION__, len, check));
3738 bus->rx_badhdr++;
3739 dhdsdio_rxfail(bus, FALSE, FALSE);
3740 continue;
3741 }
3742
3743 /* Validate frame length */
3744 if (len < SDPCM_HDRLEN) {
3745 DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len));
3746 continue;
3747 }
3748
3749 /* Extract software header fields */
3750 chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3751 seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3752 doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3753 txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3754
3755 /* Validate data offset */
3756 if ((doff < SDPCM_HDRLEN) || (doff > len)) {
3757 DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n",
3758 __FUNCTION__, doff, len, SDPCM_HDRLEN, seq));
3759 bus->rx_badhdr++;
3760 ASSERT(0);
3761 dhdsdio_rxfail(bus, FALSE, FALSE);
3762 continue;
3763 }
3764
3765 /* Save the readahead length if there is one */
3766 bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
3767 if ((bus->nextlen << 4) > MAX_RX_DATASZ) {
3768 DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n",
3769 __FUNCTION__, bus->nextlen, seq));
3770 bus->nextlen = 0;
3771 }
3772
3773 /* Handle Flow Control */
3774 fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]);
3775
3776 delta = 0;
3777 if (~bus->flowcontrol & fcbits) {
3778 bus->fc_xoff++;
3779 delta = 1;
3780 }
3781 if (bus->flowcontrol & ~fcbits) {
3782 bus->fc_xon++;
3783 delta = 1;
3784 }
3785
3786 if (delta) {
3787 bus->fc_rcvd++;
3788 bus->flowcontrol = fcbits;
3789 }
3790
3791 /* Check and update sequence number */
3792 if (rxseq != seq) {
3793 DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq));
3794 bus->rx_badseq++;
3795 rxseq = seq;
3796 }
3797
3798 /* Check window for sanity */
3799 if ((uint8)(txmax - bus->tx_seq) > 0x40) {
3800 DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n",
3801 __FUNCTION__, txmax, bus->tx_seq));
3802 txmax = bus->tx_seq + 2;
3803 }
3804 bus->tx_max = txmax;
3805
3806 /* Call a separate function for control frames */
3807 if (chan == SDPCM_CONTROL_CHANNEL) {
3808 dhdsdio_read_control(bus, bus->rxhdr, len, doff);
3809 continue;
3810 }
3811
3812 ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) ||
3813 (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL));
3814
3815 /* Length to read */
3816 rdlen = (len > firstread) ? (len - firstread) : 0;
3817
3818 /* May pad read to blocksize for efficiency */
3819 if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) {
3820 pad = bus->blocksize - (rdlen % bus->blocksize);
3821 if ((pad <= bus->roundup) && (pad < bus->blocksize) &&
3822 ((rdlen + pad + firstread) < MAX_RX_DATASZ))
3823 rdlen += pad;
3824 } else if (rdlen % DHD_SDALIGN) {
3825 rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN);
3826 }
3827
3828 /* Satisfy length-alignment requirements */
3829 if (forcealign && (rdlen & (ALIGNMENT - 1)))
3830 rdlen = ROUNDUP(rdlen, ALIGNMENT);
3831
3832 if ((rdlen + firstread) > MAX_RX_DATASZ) {
3833 /* Too long -- skip this frame */
3834 DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen));
3835 bus->dhd->rx_errors++; bus->rx_toolong++;
3836 dhdsdio_rxfail(bus, FALSE, FALSE);
3837 continue;
3838 }
3839
3840 dhd_os_sdlock_rxq(bus->dhd);
3841 if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) {
3842 /* Give up on data, request rtx of events */
3843 DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n",
3844 __FUNCTION__, rdlen, chan));
3845 bus->dhd->rx_dropped++;
3846 dhd_os_sdunlock_rxq(bus->dhd);
3847 dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan));
3848 continue;
3849 }
3850 dhd_os_sdunlock_rxq(bus->dhd);
3851
3852 ASSERT(!PKTLINK(pkt));
3853
3854 /* Leave room for what we already read, and align remainder */
3855 ASSERT(firstread < (PKTLEN(osh, pkt)));
3856 PKTPULL(osh, pkt, firstread);
3857 PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN);
3858
3859 /* Read the remaining frame data */
3860 sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
3861 ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL);
3862 bus->f2rxdata++;
3863 ASSERT(sdret != BCME_PENDING);
3864
3865 if (sdret < 0) {
3866 DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen,
3867 ((chan == SDPCM_EVENT_CHANNEL) ? "event" :
3868 ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret));
3869 dhd_os_sdlock_rxq(bus->dhd);
3870 PKTFREE(bus->dhd->osh, pkt, FALSE);
3871 dhd_os_sdunlock_rxq(bus->dhd);
3872 bus->dhd->rx_errors++;
3873 dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan));
3874 continue;
3875 }
3876
3877 /* Copy the already-read portion */
3878 PKTPUSH(osh, pkt, firstread);
3879 bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread);
3880
3881#ifdef DHD_DEBUG
3882 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
3883 prhex("Rx Data", PKTDATA(osh, pkt), len);
3884 }
3885#endif
3886
3887deliver:
3888 /* Save superframe descriptor and allocate packet frame */
3889 if (chan == SDPCM_GLOM_CHANNEL) {
3890 if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) {
3891 DHD_GLOM(("%s: got glom descriptor, %d bytes:\n",
3892 __FUNCTION__, len));
3893#ifdef DHD_DEBUG
3894 if (DHD_GLOM_ON()) {
3895 prhex("Glom Data", PKTDATA(osh, pkt), len);
3896 }
3897#endif
3898 PKTSETLEN(osh, pkt, len);
3899 ASSERT(doff == SDPCM_HDRLEN);
3900 PKTPULL(osh, pkt, SDPCM_HDRLEN);
3901 bus->glomd = pkt;
3902 } else {
3903 DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__));
3904 dhdsdio_rxfail(bus, FALSE, FALSE);
3905 }
3906 continue;
3907 }
3908
3909 /* Fill in packet len and prio, deliver upward */
3910 PKTSETLEN(osh, pkt, len);
3911 PKTPULL(osh, pkt, doff);
3912
3913#ifdef SDTEST
3914 /* Test channel packets are processed separately */
3915 if (chan == SDPCM_TEST_CHANNEL) {
3916 dhdsdio_testrcv(bus, pkt, seq);
3917 continue;
3918 }
3919#endif /* SDTEST */
3920
3921 if (PKTLEN(osh, pkt) == 0) {
3922 dhd_os_sdlock_rxq(bus->dhd);
3923 PKTFREE(bus->dhd->osh, pkt, FALSE);
3924 dhd_os_sdunlock_rxq(bus->dhd);
3925 continue;
3926 } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt) != 0) {
3927 DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__));
3928 dhd_os_sdlock_rxq(bus->dhd);
3929 PKTFREE(bus->dhd->osh, pkt, FALSE);
3930 dhd_os_sdunlock_rxq(bus->dhd);
3931 bus->dhd->rx_errors++;
3932 continue;
3933 }
3934
3935
3936 /* Unlock during rx call */
3937 dhd_os_sdunlock(bus->dhd);
3938 dhd_rx_frame(bus->dhd, ifidx, pkt, 1);
3939 dhd_os_sdlock(bus->dhd);
3940 }
3941 rxcount = maxframes - rxleft;
3942#ifdef DHD_DEBUG
3943 /* Message if we hit the limit */
3944 if (!rxleft && !sdtest)
3945 DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes));
3946 else
3947#endif /* DHD_DEBUG */
3948 DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount));
3949 /* Back off rxseq if awaiting rtx, update rx_seq */
3950 if (bus->rxskip)
3951 rxseq--;
3952 bus->rx_seq = rxseq;
3953
3954 return rxcount;
3955}
3956
3957static uint32
3958dhdsdio_hostmail(dhd_bus_t *bus)
3959{
3960 sdpcmd_regs_t *regs = bus->regs;
3961 uint32 intstatus = 0;
3962 uint32 hmb_data;
3963 uint8 fcbits;
3964 uint retries = 0;
3965
3966 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
3967
3968 /* Read mailbox data and ack that we did so */
3969 R_SDREG(hmb_data, &regs->tohostmailboxdata, retries);
3970 if (retries <= retry_limit)
3971 W_SDREG(SMB_INT_ACK, &regs->tosbmailbox, retries);
3972 bus->f1regdata += 2;
3973
3974 /* Dongle recomposed rx frames, accept them again */
3975 if (hmb_data & HMB_DATA_NAKHANDLED) {
3976 DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq));
3977 if (!bus->rxskip) {
3978 DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__));
3979 }
3980 bus->rxskip = FALSE;
3981 intstatus |= I_HMB_FRAME_IND;
3982 }
3983
3984 /*
3985 * DEVREADY does not occur with gSPI.
3986 */
3987 if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) {
3988 bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT;
3989 if (bus->sdpcm_ver != SDPCM_PROT_VERSION)
3990 DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n",
3991 bus->sdpcm_ver, SDPCM_PROT_VERSION));
3992 else
3993 DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver));
3994 }
3995
3996 /*
3997 * Flow Control has been moved into the RX headers and this out of band
3998 * method isn't used any more. Leae this here for possibly remaining backward
3999 * compatible with older dongles
4000 */
4001 if (hmb_data & HMB_DATA_FC) {
4002 fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT;
4003
4004 if (fcbits & ~bus->flowcontrol)
4005 bus->fc_xoff++;
4006 if (bus->flowcontrol & ~fcbits)
4007 bus->fc_xon++;
4008
4009 bus->fc_rcvd++;
4010 bus->flowcontrol = fcbits;
4011 }
4012
4013 /* Shouldn't be any others */
4014 if (hmb_data & ~(HMB_DATA_DEVREADY |
4015 HMB_DATA_NAKHANDLED |
4016 HMB_DATA_FC |
4017 HMB_DATA_FWREADY |
4018 HMB_DATA_FCDATA_MASK |
4019 HMB_DATA_VERSION_MASK)) {
4020 DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data));
4021 }
4022
4023 return intstatus;
4024}
4025
4026bool
4027dhdsdio_dpc(dhd_bus_t *bus)
4028{
4029 bcmsdh_info_t *sdh = bus->sdh;
4030 sdpcmd_regs_t *regs = bus->regs;
4031 uint32 intstatus, newstatus = 0;
4032 uint retries = 0;
4033 uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */
4034 uint txlimit = dhd_txbound; /* Tx frames to send before resched */
4035 uint framecnt = 0; /* Temporary counter of tx/rx frames */
4036 bool rxdone = TRUE; /* Flag for no more read data */
4037 bool resched = FALSE; /* Flag indicating resched wanted */
4038
4039 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4040
4041 /* Start with leftover status bits */
4042 intstatus = bus->intstatus;
4043
4044 dhd_os_sdlock(bus->dhd);
4045
4046 /* If waiting for HTAVAIL, check status */
4047 if (bus->clkstate == CLK_PENDING) {
4048 int err;
4049 uint8 clkctl, devctl = 0;
4050
4051#ifdef DHD_DEBUG
4052 /* Check for inconsistent device control */
4053 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
4054 if (err) {
4055 DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err));
4056 bus->dhd->busstate = DHD_BUS_DOWN;
4057 } else {
4058 ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY);
4059 }
4060#endif /* DHD_DEBUG */
4061
4062 /* Read CSR, if clock on switch to AVAIL, else ignore */
4063 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4064 if (err) {
4065 DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err));
4066 bus->dhd->busstate = DHD_BUS_DOWN;
4067 }
4068
4069 DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl));
4070
4071 if (SBSDIO_HTAV(clkctl)) {
4072 devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err);
4073 if (err) {
4074 DHD_ERROR(("%s: error reading DEVCTL: %d\n",
4075 __FUNCTION__, err));
4076 bus->dhd->busstate = DHD_BUS_DOWN;
4077 }
4078 devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
4079 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err);
4080 if (err) {
4081 DHD_ERROR(("%s: error writing DEVCTL: %d\n",
4082 __FUNCTION__, err));
4083 bus->dhd->busstate = DHD_BUS_DOWN;
4084 }
4085 bus->clkstate = CLK_AVAIL;
4086 } else {
4087 goto clkwait;
4088 }
4089 }
4090
4091 BUS_WAKE(bus);
4092
4093 /* Make sure backplane clock is on */
4094 dhdsdio_clkctl(bus, CLK_AVAIL, TRUE);
4095 if (bus->clkstate == CLK_PENDING)
4096 goto clkwait;
4097
4098 /* Pending interrupt indicates new device status */
4099 if (bus->ipend) {
4100 bus->ipend = FALSE;
4101 R_SDREG(newstatus, &regs->intstatus, retries);
4102 bus->f1regdata++;
4103 if (bcmsdh_regfail(bus->sdh))
4104 newstatus = 0;
4105 newstatus &= bus->hostintmask;
4106 bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
4107 if (newstatus) {
4108 W_SDREG(newstatus, &regs->intstatus, retries);
4109 bus->f1regdata++;
4110 }
4111 }
4112
4113 /* Merge new bits with previous */
4114 intstatus |= newstatus;
4115 bus->intstatus = 0;
4116
4117 /* Handle flow-control change: read new state in case our ack
4118 * crossed another change interrupt. If change still set, assume
4119 * FC ON for safety, let next loop through do the debounce.
4120 */
4121 if (intstatus & I_HMB_FC_CHANGE) {
4122 intstatus &= ~I_HMB_FC_CHANGE;
4123 W_SDREG(I_HMB_FC_CHANGE, &regs->intstatus, retries);
4124 R_SDREG(newstatus, &regs->intstatus, retries);
4125 bus->f1regdata += 2;
4126 bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
4127 intstatus |= (newstatus & bus->hostintmask);
4128 }
4129
4130 /* Handle host mailbox indication */
4131 if (intstatus & I_HMB_HOST_INT) {
4132#ifdef CONFIG_HAS_WAKELOCK
4133 wake_lock_timeout(&bus->dhd->wow_wakelock, 3*HZ);
4134#endif
4135 intstatus &= ~I_HMB_HOST_INT;
4136 intstatus |= dhdsdio_hostmail(bus);
4137 }
4138
4139 /* Generally don't ask for these, can get CRC errors... */
4140 if (intstatus & I_WR_OOSYNC) {
4141 DHD_ERROR(("Dongle reports WR_OOSYNC\n"));
4142 intstatus &= ~I_WR_OOSYNC;
4143 }
4144
4145 if (intstatus & I_RD_OOSYNC) {
4146 DHD_ERROR(("Dongle reports RD_OOSYNC\n"));
4147 intstatus &= ~I_RD_OOSYNC;
4148 }
4149
4150 if (intstatus & I_SBINT) {
4151 DHD_ERROR(("Dongle reports SBINT\n"));
4152 intstatus &= ~I_SBINT;
4153 }
4154
4155 /* Would be active due to wake-wlan in gSPI */
4156 if (intstatus & I_CHIPACTIVE) {
4157 DHD_INFO(("Dongle reports CHIPACTIVE\n"));
4158 intstatus &= ~I_CHIPACTIVE;
4159 }
4160
4161 /* Ignore frame indications if rxskip is set */
4162 if (bus->rxskip)
4163 intstatus &= ~I_HMB_FRAME_IND;
4164
4165 /* On frame indication, read available frames */
4166 if (PKT_AVAILABLE()) {
4167#ifdef CONFIG_HAS_WAKELOCK
4168 wake_lock_timeout(&bus->dhd->wow_wakelock, 3*HZ);
4169#endif
4170 framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone);
4171 if (rxdone || bus->rxskip)
4172 intstatus &= ~I_HMB_FRAME_IND;
4173 rxlimit -= MIN(framecnt, rxlimit);
4174 }
4175
4176 /* Keep still-pending events for next scheduling */
4177 bus->intstatus = intstatus;
4178
4179clkwait:
4180 /* Re-enable interrupts to detect new device events (mailbox, rx frame)
4181 * or clock availability. (Allows tx loop to check ipend if desired.)
4182 * (Unless register access seems hosed, as we may not be able to ACK...)
4183 */
4184 if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) {
4185 DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n",
4186 __FUNCTION__, rxdone, framecnt));
4187 bus->intdis = FALSE;
4188#if defined(OOB_INTR_ONLY)
4189 bcmsdh_oob_intr_set(1);
4190#endif /* (OOB_INTR_ONLY) */
4191 bcmsdh_intr_enable(sdh);
4192 }
4193
4194 if (DATAOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) {
4195 int ret, i;
4196
4197 ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC,
4198 (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len,
4199 NULL, NULL, NULL);
4200 ASSERT(ret != BCME_PENDING);
4201
4202 if (ret < 0) {
4203 /* On failure, abort the command and terminate the frame */
4204 DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n",
4205 __FUNCTION__, ret));
4206 bus->tx_sderrs++;
4207
4208 bcmsdh_abort(sdh, SDIO_FUNC_2);
4209
4210 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL,
4211 SFC_WF_TERM, NULL);
4212 bus->f1regdata++;
4213
4214 for (i = 0; i < 3; i++) {
4215 uint8 hi, lo;
4216 hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4217 SBSDIO_FUNC1_WFRAMEBCHI, NULL);
4218 lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4219 SBSDIO_FUNC1_WFRAMEBCLO, NULL);
4220 bus->f1regdata += 2;
4221 if ((hi == 0) && (lo == 0))
4222 break;
4223 }
4224
4225 }
4226 if (ret == 0) {
4227 bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
4228 }
4229
4230 printf("Return_dpc value is : %d\n", ret);
4231 bus->ctrl_frame_stat = FALSE;
4232 dhd_wait_event_wakeup(bus->dhd);
4233 }
4234 /* Send queued frames (limit 1 if rx may still be pending) */
4235 else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate &&
4236 pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) {
4237 framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax);
4238 framecnt = dhdsdio_sendfromq(bus, framecnt);
4239 txlimit -= framecnt;
4240 }
4241
4242 /* Resched if events or tx frames are pending, else await next interrupt */
4243 /* On failed register access, all bets are off: no resched or interrupts */
4244 if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) {
4245 DHD_ERROR(("%s: failed backplane access over SDIO, halting operation %d \n",
4246 __FUNCTION__, bcmsdh_regfail(sdh)));
4247 bus->dhd->busstate = DHD_BUS_DOWN;
4248 bus->intstatus = 0;
4249 } else if (bus->clkstate == CLK_PENDING) {
4250 DHD_INFO(("%s: rescheduled due to CLK_PENDING awaiting \
4251 I_CHIPACTIVE interrupt", __FUNCTION__));
4252 resched = TRUE;
4253 } else if (bus->intstatus || bus->ipend ||
4254 (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) ||
4255 PKT_AVAILABLE()) { /* Read multiple frames */
4256 resched = TRUE;
4257 }
4258
4259
4260 bus->dpc_sched = resched;
4261
4262 /* If we're done for now, turn off clock request. */
4263 if ((bus->clkstate != CLK_PENDING) && bus->idletime == DHD_IDLE_IMMEDIATE) {
4264 bus->activity = FALSE;
4265 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4266 }
4267
4268 dhd_os_sdunlock(bus->dhd);
4269
4270 return resched;
4271}
4272
4273bool
4274dhd_bus_dpc(struct dhd_bus *bus)
4275{
4276 bool resched;
4277
4278 /* Call the DPC directly. */
4279 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
4280 resched = dhdsdio_dpc(bus);
4281
4282 return resched;
4283}
4284
4285void
4286dhdsdio_isr(void *arg)
4287{
4288 dhd_bus_t *bus = (dhd_bus_t*)arg;
4289 bcmsdh_info_t *sdh;
4290
4291 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4292
4293 if (!bus) {
4294 DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__));
4295 return;
4296 }
4297 sdh = bus->sdh;
4298
4299 if (bus->dhd->busstate == DHD_BUS_DOWN) {
4300 DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__));
4301 return;
4302 }
4303 /* Count the interrupt call */
4304 bus->intrcount++;
4305 bus->ipend = TRUE;
4306
4307 /* Shouldn't get this interrupt if we're sleeping? */
4308 if (bus->sleeping) {
4309 DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n"));
4310 return;
4311 }
4312
4313 /* Disable additional interrupts (is this needed now)? */
4314 if (bus->intr) {
4315 DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__));
4316 } else {
4317 DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n"));
4318 }
4319
4320 bcmsdh_intr_disable(sdh);
4321 bus->intdis = TRUE;
4322
4323#if defined(SDIO_ISR_THREAD)
4324 DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__));
4325 dhd_os_wake_lock(bus->dhd);
4326 while (dhdsdio_dpc(bus));
4327 dhd_os_wake_unlock(bus->dhd);
4328#else
4329 bus->dpc_sched = TRUE;
4330 dhd_sched_dpc(bus->dhd);
4331#endif
4332
4333}
4334
4335#ifdef SDTEST
4336static void
4337dhdsdio_pktgen_init(dhd_bus_t *bus)
4338{
4339 /* Default to specified length, or full range */
4340 if (dhd_pktgen_len) {
4341 bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN);
4342 bus->pktgen_minlen = bus->pktgen_maxlen;
4343 } else {
4344 bus->pktgen_maxlen = MAX_PKTGEN_LEN;
4345 bus->pktgen_minlen = 0;
4346 }
4347 bus->pktgen_len = (uint16)bus->pktgen_minlen;
4348
4349 /* Default to per-watchdog burst with 10s print time */
4350 bus->pktgen_freq = 1;
4351 bus->pktgen_print = 10000 / dhd_watchdog_ms;
4352 bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000;
4353
4354 /* Default to echo mode */
4355 bus->pktgen_mode = DHD_PKTGEN_ECHO;
4356 bus->pktgen_stop = 1;
4357}
4358
4359static void
4360dhdsdio_pktgen(dhd_bus_t *bus)
4361{
4362 void *pkt;
4363 uint8 *data;
4364 uint pktcount;
4365 uint fillbyte;
4366 osl_t *osh = bus->dhd->osh;
4367 uint16 len;
4368
4369 /* Display current count if appropriate */
4370 if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) {
4371 bus->pktgen_ptick = 0;
4372 printf("%s: send attempts %d rcvd %d\n",
4373 __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd);
4374 }
4375
4376 /* For recv mode, just make sure dongle has started sending */
4377 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
4378 if (!bus->pktgen_rcvd)
4379 dhdsdio_sdtest_set(bus, TRUE);
4380 return;
4381 }
4382
4383 /* Otherwise, generate or request the specified number of packets */
4384 for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) {
4385 /* Stop if total has been reached */
4386 if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) {
4387 bus->pktgen_count = 0;
4388 break;
4389 }
4390
4391 /* Allocate an appropriate-sized packet */
4392 len = bus->pktgen_len;
4393 if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN),
4394 TRUE))) {;
4395 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
4396 break;
4397 }
4398 PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
4399 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4400
4401 /* Write test header cmd and extra based on mode */
4402 switch (bus->pktgen_mode) {
4403 case DHD_PKTGEN_ECHO:
4404 *data++ = SDPCM_TEST_ECHOREQ;
4405 *data++ = (uint8)bus->pktgen_sent;
4406 break;
4407
4408 case DHD_PKTGEN_SEND:
4409 *data++ = SDPCM_TEST_DISCARD;
4410 *data++ = (uint8)bus->pktgen_sent;
4411 break;
4412
4413 case DHD_PKTGEN_RXBURST:
4414 *data++ = SDPCM_TEST_BURST;
4415 *data++ = (uint8)bus->pktgen_count;
4416 break;
4417
4418 default:
4419 DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode));
4420 PKTFREE(osh, pkt, TRUE);
4421 bus->pktgen_count = 0;
4422 return;
4423 }
4424
4425 /* Write test header length field */
4426 *data++ = (len >> 0);
4427 *data++ = (len >> 8);
4428
4429 /* Then fill in the remainder -- N/A for burst, but who cares... */
4430 for (fillbyte = 0; fillbyte < len; fillbyte++)
4431 *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent);
4432
4433#ifdef DHD_DEBUG
4434 if (DHD_BYTES_ON() && DHD_DATA_ON()) {
4435 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4436 prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN);
4437 }
4438#endif
4439
4440 /* Send it */
4441 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE)) {
4442 bus->pktgen_fail++;
4443 if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail)
4444 bus->pktgen_count = 0;
4445 }
4446 bus->pktgen_sent++;
4447
4448 /* Bump length if not fixed, wrap at max */
4449 if (++bus->pktgen_len > bus->pktgen_maxlen)
4450 bus->pktgen_len = (uint16)bus->pktgen_minlen;
4451
4452 /* Special case for burst mode: just send one request! */
4453 if (bus->pktgen_mode == DHD_PKTGEN_RXBURST)
4454 break;
4455 }
4456}
4457
4458static void
4459dhdsdio_sdtest_set(dhd_bus_t *bus, bool start)
4460{
4461 void *pkt;
4462 uint8 *data;
4463 osl_t *osh = bus->dhd->osh;
4464
4465 /* Allocate the packet */
4466 if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, TRUE))) {
4467 DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__));
4468 return;
4469 }
4470 PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN);
4471 data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN;
4472
4473 /* Fill in the test header */
4474 *data++ = SDPCM_TEST_SEND;
4475 *data++ = start;
4476 *data++ = (bus->pktgen_maxlen >> 0);
4477 *data++ = (bus->pktgen_maxlen >> 8);
4478
4479 /* Send it */
4480 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE))
4481 bus->pktgen_fail++;
4482}
4483
4484
4485static void
4486dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq)
4487{
4488 osl_t *osh = bus->dhd->osh;
4489 uint8 *data;
4490 uint pktlen;
4491
4492 uint8 cmd;
4493 uint8 extra;
4494 uint16 len;
4495 uint16 offset;
4496
4497 /* Check for min length */
4498 if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) {
4499 DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen));
4500 PKTFREE(osh, pkt, FALSE);
4501 return;
4502 }
4503
4504 /* Extract header fields */
4505 data = PKTDATA(osh, pkt);
4506 cmd = *data++;
4507 extra = *data++;
4508 len = *data++; len += *data++ << 8;
4509
4510 /* Check length for relevant commands */
4511 if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) {
4512 if (pktlen != len + SDPCM_TEST_HDRLEN) {
4513 DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d"
4514 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
4515 PKTFREE(osh, pkt, FALSE);
4516 return;
4517 }
4518 }
4519
4520 /* Process as per command */
4521 switch (cmd) {
4522 case SDPCM_TEST_ECHOREQ:
4523 /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */
4524 *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP;
4525 if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE) == 0) {
4526 bus->pktgen_sent++;
4527 } else {
4528 bus->pktgen_fail++;
4529 PKTFREE(osh, pkt, FALSE);
4530 }
4531 bus->pktgen_rcvd++;
4532 break;
4533
4534 case SDPCM_TEST_ECHORSP:
4535 if (bus->ext_loop) {
4536 PKTFREE(osh, pkt, FALSE);
4537 bus->pktgen_rcvd++;
4538 break;
4539 }
4540
4541 for (offset = 0; offset < len; offset++, data++) {
4542 if (*data != SDPCM_TEST_FILL(offset, extra)) {
4543 DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: "
4544 "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n",
4545 offset, len, SDPCM_TEST_FILL(offset, extra), *data));
4546 break;
4547 }
4548 }
4549 PKTFREE(osh, pkt, FALSE);
4550 bus->pktgen_rcvd++;
4551 break;
4552
4553 case SDPCM_TEST_DISCARD:
4554 PKTFREE(osh, pkt, FALSE);
4555 bus->pktgen_rcvd++;
4556 break;
4557
4558 case SDPCM_TEST_BURST:
4559 case SDPCM_TEST_SEND:
4560 default:
4561 DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d"
4562 " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len));
4563 PKTFREE(osh, pkt, FALSE);
4564 break;
4565 }
4566
4567 /* For recv mode, stop at limie (and tell dongle to stop sending) */
4568 if (bus->pktgen_mode == DHD_PKTGEN_RECV) {
4569 if (bus->pktgen_total && (bus->pktgen_rcvd >= bus->pktgen_total)) {
4570 bus->pktgen_count = 0;
4571 dhdsdio_sdtest_set(bus, FALSE);
4572 }
4573 }
4574}
4575#endif /* SDTEST */
4576
4577extern bool
4578dhd_bus_watchdog(dhd_pub_t *dhdp)
4579{
4580 dhd_bus_t *bus;
4581
4582 DHD_TIMER(("%s: Enter\n", __FUNCTION__));
4583
4584 bus = dhdp->bus;
4585
4586 if (bus->dhd->dongle_reset)
4587 return FALSE;
4588
4589 /* Ignore the timer if simulating bus down */
4590 if (bus->sleeping)
4591 return FALSE;
4592
4593 /* Poll period: check device if appropriate. */
4594 if (bus->poll && (++bus->polltick >= bus->pollrate)) {
4595 uint32 intstatus = 0;
4596
4597 /* Reset poll tick */
4598 bus->polltick = 0;
4599
4600 /* Check device if no interrupts */
4601 if (!bus->intr || (bus->intrcount == bus->lastintrs)) {
4602
4603 if (!bus->dpc_sched) {
4604 uint8 devpend;
4605 devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0,
4606 SDIOD_CCCR_INTPEND, NULL);
4607 intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2);
4608 }
4609
4610 /* If there is something, make like the ISR and schedule the DPC */
4611 if (intstatus) {
4612 bus->pollcnt++;
4613 bus->ipend = TRUE;
4614 if (bus->intr) {
4615 bcmsdh_intr_disable(bus->sdh);
4616 }
4617 bus->dpc_sched = TRUE;
4618 dhd_sched_dpc(bus->dhd);
4619
4620 }
4621 }
4622
4623 /* Update interrupt tracking */
4624 bus->lastintrs = bus->intrcount;
4625 }
4626
4627#ifdef DHD_DEBUG
4628 /* Poll for console output periodically */
4629 if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) {
4630 bus->console.count += dhd_watchdog_ms;
4631 if (bus->console.count >= dhd_console_ms) {
4632 bus->console.count -= dhd_console_ms;
4633 /* Make sure backplane clock is on */
4634 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4635 if (dhdsdio_readconsole(bus) < 0)
4636 dhd_console_ms = 0; /* On error, stop trying */
4637 }
4638 }
4639#endif /* DHD_DEBUG */
4640
4641#ifdef SDTEST
4642 /* Generate packets if configured */
4643 if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) {
4644 /* Make sure backplane clock is on */
4645 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4646 bus->pktgen_tick = 0;
4647 dhdsdio_pktgen(bus);
4648 }
4649#endif
4650
4651 /* On idle timeout clear activity flag and/or turn off clock */
4652 if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) {
4653 if (++bus->idlecount >= bus->idletime) {
4654 bus->idlecount = 0;
4655 if (bus->activity) {
4656 bus->activity = FALSE;
4657 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
4658 }
4659 }
4660 }
4661
4662 return bus->ipend;
4663}
4664
4665#ifdef DHD_DEBUG
4666extern int
4667dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen)
4668{
4669 dhd_bus_t *bus = dhdp->bus;
4670 uint32 addr, val;
4671 int rv;
4672 void *pkt;
4673
4674 /* Address could be zero if CONSOLE := 0 in dongle Makefile */
4675 if (bus->console_addr == 0)
4676 return BCME_UNSUPPORTED;
4677
4678 /* Exclusive bus access */
4679 dhd_os_sdlock(bus->dhd);
4680
4681 /* Don't allow input if dongle is in reset */
4682 if (bus->dhd->dongle_reset) {
4683 dhd_os_sdunlock(bus->dhd);
4684 return BCME_NOTREADY;
4685 }
4686
4687 /* Request clock to allow SDIO accesses */
4688 BUS_WAKE(bus);
4689 /* No pend allowed since txpkt is called later, ht clk has to be on */
4690 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
4691
4692 /* Zero cbuf_index */
4693 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx);
4694 val = htol32(0);
4695 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
4696 goto done;
4697
4698 /* Write message into cbuf */
4699 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf);
4700 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0)
4701 goto done;
4702
4703 /* Write length into vcons_in */
4704 addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in);
4705 val = htol32(msglen);
4706 if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0)
4707 goto done;
4708
4709 /* Bump dongle by sending an empty event pkt.
4710 * sdpcm_sendup (RX) checks for virtual console input.
4711 */
4712 if (((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) &&
4713 bus->clkstate == CLK_AVAIL)
4714 dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE);
4715
4716done:
4717 if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) {
4718 bus->activity = FALSE;
4719 dhdsdio_clkctl(bus, CLK_NONE, TRUE);
4720 }
4721
4722 dhd_os_sdunlock(bus->dhd);
4723
4724 return rv;
4725}
4726#endif /* DHD_DEBUG */
4727
4728#ifdef DHD_DEBUG
4729static void
4730dhd_dump_cis(uint fn, uint8 *cis)
4731{
4732 uint byte, tag, tdata;
4733 DHD_INFO(("Function %d CIS:\n", fn));
4734
4735 for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) {
4736 if ((byte % 16) == 0)
4737 DHD_INFO((" "));
4738 DHD_INFO(("%02x ", cis[byte]));
4739 if ((byte % 16) == 15)
4740 DHD_INFO(("\n"));
4741 if (!tdata--) {
4742 tag = cis[byte];
4743 if (tag == 0xff)
4744 break;
4745 else if (!tag)
4746 tdata = 0;
4747 else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT)
4748 tdata = cis[byte + 1] + 1;
4749 else
4750 DHD_INFO(("]"));
4751 }
4752 }
4753 if ((byte % 16) != 15)
4754 DHD_INFO(("\n"));
4755}
4756#endif /* DHD_DEBUG */
4757
4758static bool
4759dhdsdio_chipmatch(uint16 chipid)
4760{
4761 if (chipid == BCM4325_CHIP_ID)
4762 return TRUE;
4763 if (chipid == BCM4329_CHIP_ID)
4764 return TRUE;
4765 if (chipid == BCM4315_CHIP_ID)
4766 return TRUE;
4767 if (chipid == BCM4319_CHIP_ID)
4768 return TRUE;
4769 return FALSE;
4770}
4771
4772static void *
4773dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot,
4774 uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh,
4775 void *dev)
4776{
4777 int ret;
4778 dhd_bus_t *bus;
4779
4780 /* Init global variables at run-time, not as part of the declaration.
4781 * This is required to support init/de-init of the driver. Initialization
4782 * of globals as part of the declaration results in non-deterministic
4783 * behavior since the value of the globals may be different on the
4784 * first time that the driver is initialized vs subsequent initializations.
4785 */
4786 dhd_txbound = DHD_TXBOUND;
4787 dhd_rxbound = DHD_RXBOUND;
4788 dhd_alignctl = TRUE;
4789 sd1idle = TRUE;
4790 dhd_readahead = TRUE;
4791 retrydata = FALSE;
4792 dhd_doflow = TRUE;
4793 dhd_dongle_memsize = 0;
4794 dhd_txminmax = DHD_TXMINMAX;
4795
4796 forcealign = TRUE;
4797
4798
4799 dhd_common_init();
4800
4801 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
4802 DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid));
4803
4804 /* We make assumptions about address window mappings */
4805 ASSERT((uintptr)regsva == SI_ENUM_BASE);
4806
4807 /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start
4808 * means early parse could fail, so here we should get either an ID
4809 * we recognize OR (-1) indicating we must request power first.
4810 */
4811 /* Check the Vendor ID */
4812 switch (venid) {
4813 case 0x0000:
4814 case VENDOR_BROADCOM:
4815 break;
4816 default:
4817 DHD_ERROR(("%s: unknown vendor: 0x%04x\n",
4818 __FUNCTION__, venid));
4819 return NULL;
4820 }
4821
4822 /* Check the Device ID and make sure it's one that we support */
4823 switch (devid) {
4824 case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */
4825 case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */
4826 case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */
4827 DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__));
4828 break;
4829 case BCM4329_D11NDUAL_ID: /* 4329 802.11n dualband device */
4830 case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */
4831 case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */
4832 case 0x4329:
4833 DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__));
4834 break;
4835 case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */
4836 case BCM4315_D11G_ID: /* 4315 802.11g id */
4837 case BCM4315_D11A_ID: /* 4315 802.11a id */
4838 DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__));
4839 break;
4840 case BCM4319_D11N_ID: /* 4319 802.11n id */
4841 case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */
4842 case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */
4843 DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__));
4844 break;
4845 case 0:
4846 DHD_INFO(("%s: allow device id 0, will check chip internals\n",
4847 __FUNCTION__));
4848 break;
4849
4850 default:
4851 DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n",
4852 __FUNCTION__, venid, devid));
4853 return NULL;
4854 }
4855
4856 if (osh == NULL) {
4857 /* Ask the OS interface part for an OSL handle */
4858 if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) {
4859 DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__));
4860 return NULL;
4861 }
4862 }
4863
4864 /* Allocate private bus interface state */
4865 if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) {
4866 DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__));
4867 goto fail;
4868 }
4869 bzero(bus, sizeof(dhd_bus_t));
4870 bus->sdh = sdh;
4871 bus->cl_devid = (uint16)devid;
4872 bus->bus = DHD_BUS;
4873 bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
4874 bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */
4875
4876 /* attempt to attach to the dongle */
4877 if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) {
4878 DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__));
4879 goto fail;
4880 }
4881
4882 /* Attach to the dhd/OS/network interface */
4883 if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE, dev))) {
4884 DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__));
4885 goto fail;
4886 }
4887
4888 /* Allocate buffers */
4889 if (!(dhdsdio_probe_malloc(bus, osh, sdh))) {
4890 DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__));
4891 goto fail;
4892 }
4893
4894 if (!(dhdsdio_probe_init(bus, osh, sdh))) {
4895 DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__));
4896 goto fail;
4897 }
4898
4899 /* Register interrupt callback, but mask it (not operational yet). */
4900 DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__));
4901 bcmsdh_intr_disable(sdh);
4902 if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) {
4903 DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n",
4904 __FUNCTION__, ret));
4905 goto fail;
4906 }
4907 DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__));
4908
4909 DHD_INFO(("%s: completed!!\n", __FUNCTION__));
4910
4911
4912 /* if firmware path present try to download and bring up bus */
4913 if ((ret = dhd_bus_start(bus->dhd)) != 0) {
4914#if 1
4915 DHD_ERROR(("%s: failed\n", __FUNCTION__));
4916 goto fail;
4917#else
4918 if (ret == BCME_NOTUP) {
4919 DHD_ERROR(("%s: dongle is not responding\n", __FUNCTION__));
4920 goto fail;
4921 }
4922#endif
4923 }
4924 /* Ok, have the per-port tell the stack we're open for business */
4925 if (dhd_net_attach(bus->dhd, 0) != 0) {
4926 DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__));
4927 goto fail;
4928 }
4929
4930 return bus;
4931
4932fail:
4933 dhdsdio_release(bus, osh);
4934 return NULL;
4935}
4936
4937
4938static bool
4939dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva,
4940 uint16 devid)
4941{
4942 uint8 clkctl = 0;
4943 int err = 0;
4944
4945 bus->alp_only = TRUE;
4946
4947 /* Return the window to backplane enumeration space for core access */
4948 if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) {
4949 DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__));
4950 }
4951
4952#ifdef DHD_DEBUG
4953 printf("F1 signature read @0x18000000=0x%4x\n",
4954 bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4));
4955
4956
4957#endif /* DHD_DEBUG */
4958
4959
4960 /* Force PLL off until si_attach() programs PLL control regs */
4961
4962
4963
4964 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err);
4965 if (!err)
4966 clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err);
4967
4968 if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) {
4969 DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n",
4970 err, DHD_INIT_CLKCTL1, clkctl));
4971 goto fail;
4972 }
4973
4974
4975#ifdef DHD_DEBUG
4976 if (DHD_INFO_ON()) {
4977 uint fn, numfn;
4978 uint8 *cis[SDIOD_MAX_IOFUNCS];
4979 int err = 0;
4980
4981 numfn = bcmsdh_query_iofnum(sdh);
4982 ASSERT(numfn <= SDIOD_MAX_IOFUNCS);
4983
4984 /* Make sure ALP is available before trying to read CIS */
4985 SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
4986 SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
4987 !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY);
4988
4989 /* Now request ALP be put on the bus */
4990 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
4991 DHD_INIT_CLKCTL2, &err);
4992 OSL_DELAY(65);
4993
4994 for (fn = 0; fn <= numfn; fn++) {
4995 if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
4996 DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn));
4997 break;
4998 }
4999 bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT);
5000
5001 if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) {
5002 DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err));
5003 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
5004 break;
5005 }
5006 dhd_dump_cis(fn, cis[fn]);
5007 }
5008
5009 while (fn-- > 0) {
5010 ASSERT(cis[fn]);
5011 MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT);
5012 }
5013
5014 if (err) {
5015 DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n"));
5016 goto fail;
5017 }
5018 }
5019#endif /* DHD_DEBUG */
5020
5021 /* si_attach() will provide an SI handle and scan the backplane */
5022 if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh,
5023 &bus->vars, &bus->varsz))) {
5024 DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__));
5025 goto fail;
5026 }
5027
5028 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
5029
5030 if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) {
5031 DHD_ERROR(("%s: unsupported chip: 0x%04x\n",
5032 __FUNCTION__, bus->sih->chip));
5033 goto fail;
5034 }
5035
5036 si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength);
5037
5038
5039 /* Get info on the ARM and SOCRAM cores... */
5040 if (!DHD_NOPMU(bus)) {
5041 if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) ||
5042 (si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) {
5043 bus->armrev = si_corerev(bus->sih);
5044 } else {
5045 DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__));
5046 goto fail;
5047 }
5048 if (!(bus->orig_ramsize = si_socram_size(bus->sih))) {
5049 DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__));
5050 goto fail;
5051 }
5052 bus->ramsize = bus->orig_ramsize;
5053 if (dhd_dongle_memsize)
5054 dhd_dongle_setmemsize(bus, dhd_dongle_memsize);
5055
5056 DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n",
5057 bus->ramsize, bus->orig_ramsize));
5058 }
5059
5060 /* ...but normally deal with the SDPCMDEV core */
5061 if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) &&
5062 !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) {
5063 DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__));
5064 goto fail;
5065 }
5066 bus->sdpcmrev = si_corerev(bus->sih);
5067
5068 /* Set core control so an SDIO reset does a backplane reset */
5069 OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN);
5070
5071 pktq_init(&bus->txq, (PRIOMASK + 1), QLEN);
5072
5073 /* Locate an appropriately-aligned portion of hdrbuf */
5074 bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN);
5075
5076 /* Set the poll and/or interrupt flags */
5077 bus->intr = (bool)dhd_intr;
5078 if ((bus->poll = (bool)dhd_poll))
5079 bus->pollrate = 1;
5080
5081 return TRUE;
5082
5083fail:
5084 return FALSE;
5085}
5086
5087static bool
5088dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh)
5089{
5090 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5091
5092#ifndef DHD_USE_STATIC_BUF
5093 if (bus->dhd->maxctl) {
5094 bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
5095 if (!(bus->rxbuf = MALLOC(osh, bus->rxblen))) {
5096 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
5097 __FUNCTION__, bus->rxblen));
5098 goto fail;
5099 }
5100 }
5101
5102 /* Allocate buffer to receive glomed packet */
5103 if (!(bus->databuf = MALLOC(osh, MAX_DATA_BUF))) {
5104 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
5105 __FUNCTION__, MAX_DATA_BUF));
5106 /* release rxbuf which was already located as above */
5107 if (!bus->rxblen) MFREE(osh, bus->rxbuf, bus->rxblen);
5108 goto fail;
5109 }
5110#else
5111 if (bus->dhd->maxctl) {
5112 bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN;
5113 if (!(bus->rxbuf = dhd_os_prealloc(DHD_PREALLOC_RXBUF, bus->rxblen))) {
5114 DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n",
5115 __FUNCTION__, bus->rxblen));
5116 goto fail;
5117 }
5118 }
5119 /* Allocate buffer to receive glomed packet */
5120 if (!(bus->databuf = dhd_os_prealloc(DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) {
5121 DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n",
5122 __FUNCTION__, MAX_DATA_BUF));
5123 goto fail;
5124 }
5125#endif /* DHD_USE_STATIC_BUF */
5126
5127 /* Align the buffer */
5128 if ((uintptr)bus->databuf % DHD_SDALIGN)
5129 bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN));
5130 else
5131 bus->dataptr = bus->databuf;
5132
5133 return TRUE;
5134
5135fail:
5136 return FALSE;
5137}
5138
5139
5140static bool
5141dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh)
5142{
5143 int32 fnum;
5144
5145 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5146
5147#ifdef SDTEST
5148 dhdsdio_pktgen_init(bus);
5149#endif /* SDTEST */
5150
5151 /* Disable F2 to clear any intermediate frame state on the dongle */
5152 bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL);
5153
5154 bus->dhd->busstate = DHD_BUS_DOWN;
5155 bus->sleeping = FALSE;
5156 bus->rxflow = FALSE;
5157 bus->prev_rxlim_hit = 0;
5158
5159
5160 /* Done with backplane-dependent accesses, can drop clock... */
5161 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
5162
5163 /* ...and initialize clock/power states */
5164 bus->clkstate = CLK_SDONLY;
5165 bus->idletime = (int32)dhd_idletime;
5166 bus->idleclock = DHD_IDLE_ACTIVE;
5167
5168 /* Query the SD clock speed */
5169 if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0,
5170 &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) {
5171 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor"));
5172 bus->sd_divisor = -1;
5173 } else {
5174 DHD_INFO(("%s: Initial value for %s is %d\n",
5175 __FUNCTION__, "sd_divisor", bus->sd_divisor));
5176 }
5177
5178 /* Query the SD bus mode */
5179 if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0,
5180 &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) {
5181 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode"));
5182 bus->sd_mode = -1;
5183 } else {
5184 DHD_INFO(("%s: Initial value for %s is %d\n",
5185 __FUNCTION__, "sd_mode", bus->sd_mode));
5186 }
5187
5188 /* Query the F2 block size, set roundup accordingly */
5189 fnum = 2;
5190 if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32),
5191 &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) {
5192 bus->blocksize = 0;
5193 DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize"));
5194 } else {
5195 DHD_INFO(("%s: Initial value for %s is %d\n",
5196 __FUNCTION__, "sd_blocksize", bus->blocksize));
5197 }
5198 bus->roundup = MIN(max_roundup, bus->blocksize);
5199
5200 /* Query if bus module supports packet chaining, default to use if supported */
5201 if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0,
5202 &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) {
5203 bus->sd_rxchain = FALSE;
5204 } else {
5205 DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n",
5206 __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support")));
5207 }
5208 bus->use_rxchain = (bool)bus->sd_rxchain;
5209
5210 return TRUE;
5211}
5212
5213bool
5214dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh,
5215 char *fw_path, char *nv_path)
5216{
5217 bool ret;
5218 bus->fw_path = fw_path;
5219 bus->nv_path = nv_path;
5220
5221 ret = dhdsdio_download_firmware(bus, osh, bus->sdh);
5222
5223 return ret;
5224}
5225
5226static bool
5227dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh)
5228{
5229 bool ret;
5230
5231 /* Download the firmware */
5232 dhd_os_wake_lock(bus->dhd);
5233 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5234
5235 ret = _dhdsdio_download_firmware(bus) == 0;
5236
5237 dhdsdio_clkctl(bus, CLK_SDONLY, FALSE);
5238 dhd_os_wake_unlock(bus->dhd);
5239 return ret;
5240}
5241
5242/* Detach and free everything */
5243static void
5244dhdsdio_release(dhd_bus_t *bus, osl_t *osh)
5245{
5246 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5247
5248 if (bus) {
5249 ASSERT(osh);
5250
5251
5252 /* De-register interrupt handler */
5253 bcmsdh_intr_disable(bus->sdh);
5254 bcmsdh_intr_dereg(bus->sdh);
5255
5256 if (bus->dhd) {
5257
5258 dhdsdio_release_dongle(bus, osh, TRUE);
5259
5260 dhd_detach(bus->dhd);
5261 bus->dhd = NULL;
5262 }
5263
5264 dhdsdio_release_malloc(bus, osh);
5265
5266
5267 MFREE(osh, bus, sizeof(dhd_bus_t));
5268 }
5269
5270 if (osh)
5271 dhd_osl_detach(osh);
5272
5273 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
5274}
5275
5276static void
5277dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh)
5278{
5279 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5280
5281 if (bus->dhd && bus->dhd->dongle_reset)
5282 return;
5283
5284 if (bus->rxbuf) {
5285#ifndef DHD_USE_STATIC_BUF
5286 MFREE(osh, bus->rxbuf, bus->rxblen);
5287#endif
5288 bus->rxctl = bus->rxbuf = NULL;
5289 bus->rxlen = 0;
5290 }
5291
5292 if (bus->databuf) {
5293#ifndef DHD_USE_STATIC_BUF
5294 MFREE(osh, bus->databuf, MAX_DATA_BUF);
5295#endif
5296 bus->databuf = NULL;
5297 }
5298}
5299
5300
5301static void
5302dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, int reset_flag)
5303{
5304 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5305
5306 if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag)
5307 return;
5308
5309 if (bus->sih) {
5310 dhdsdio_clkctl(bus, CLK_AVAIL, FALSE);
5311#if !defined(BCMLXSDMMC)
5312 si_watchdog(bus->sih, 4);
5313#endif /* !defined(BCMLXSDMMC) */
5314 dhdsdio_clkctl(bus, CLK_NONE, FALSE);
5315 si_detach(bus->sih);
5316 if (bus->vars && bus->varsz)
5317 MFREE(osh, bus->vars, bus->varsz);
5318 bus->vars = NULL;
5319 }
5320
5321 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
5322}
5323
5324static void
5325dhdsdio_disconnect(void *ptr)
5326{
5327 dhd_bus_t *bus = (dhd_bus_t *)ptr;
5328
5329 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5330
5331 if (bus) {
5332 ASSERT(bus->dhd);
5333 dhdsdio_release(bus, bus->dhd->osh);
5334 }
5335
5336 DHD_TRACE(("%s: Disconnected\n", __FUNCTION__));
5337}
5338
5339
5340/* Register/Unregister functions are called by the main DHD entry
5341 * point (e.g. module insertion) to link with the bus driver, in
5342 * order to look for or await the device.
5343 */
5344
5345static bcmsdh_driver_t dhd_sdio = {
5346 dhdsdio_probe,
5347 dhdsdio_disconnect
5348};
5349
5350int
5351dhd_bus_register(void)
5352{
5353 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5354
5355 return bcmsdh_register(&dhd_sdio);
5356}
5357
5358void
5359dhd_bus_unregister(void)
5360{
5361 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
5362
5363 bcmsdh_unregister();
5364}
5365
5366#ifdef BCMEMBEDIMAGE
5367static int
5368dhdsdio_download_code_array(struct dhd_bus *bus)
5369{
5370 int bcmerror = -1;
5371 int offset = 0;
5372
5373 DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__));
5374
5375 /* Download image */
5376 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
5377 bcmerror = dhdsdio_membytes(bus, TRUE, offset, dlarray + offset, MEMBLOCK);
5378 if (bcmerror) {
5379 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5380 __FUNCTION__, bcmerror, MEMBLOCK, offset));
5381 goto err;
5382 }
5383
5384 offset += MEMBLOCK;
5385 }
5386
5387 if (offset < sizeof(dlarray)) {
5388 bcmerror = dhdsdio_membytes(bus, TRUE, offset,
5389 dlarray + offset, sizeof(dlarray) - offset);
5390 if (bcmerror) {
5391 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5392 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
5393 goto err;
5394 }
5395 }
5396
5397#ifdef DHD_DEBUG
5398 /* Upload and compare the downloaded code */
5399 {
5400 unsigned char *ularray;
5401
5402 ularray = MALLOC(bus->dhd->osh, bus->ramsize);
5403 /* Upload image to verify downloaded contents. */
5404 offset = 0;
5405 memset(ularray, 0xaa, bus->ramsize);
5406 while ((offset + MEMBLOCK) < sizeof(dlarray)) {
5407 bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK);
5408 if (bcmerror) {
5409 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
5410 __FUNCTION__, bcmerror, MEMBLOCK, offset));
5411 goto err;
5412 }
5413
5414 offset += MEMBLOCK;
5415 }
5416
5417 if (offset < sizeof(dlarray)) {
5418 bcmerror = dhdsdio_membytes(bus, FALSE, offset,
5419 ularray + offset, sizeof(dlarray) - offset);
5420 if (bcmerror) {
5421 DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n",
5422 __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset));
5423 goto err;
5424 }
5425 }
5426
5427 if (memcmp(dlarray, ularray, sizeof(dlarray))) {
5428 DHD_ERROR(("%s: Downloaded image is corrupted.\n", __FUNCTION__));
5429 ASSERT(0);
5430 goto err;
5431 } else
5432 DHD_ERROR(("%s: Download, Upload and compare succeeded.\n", __FUNCTION__));
5433
5434 MFREE(bus->dhd->osh, ularray, bus->ramsize);
5435 }
5436#endif /* DHD_DEBUG */
5437
5438err:
5439 return bcmerror;
5440}
5441#endif /* BCMEMBEDIMAGE */
5442
5443static int
5444dhdsdio_download_code_file(struct dhd_bus *bus, char *fw_path)
5445{
5446 int bcmerror = -1;
5447 int offset = 0;
5448 uint len;
5449 void *image = NULL;
5450 uint8 *memblock = NULL, *memptr;
5451
5452 DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, fw_path));
5453
5454 image = dhd_os_open_image(fw_path);
5455 if (image == NULL)
5456 goto err;
5457
5458 memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN);
5459 if (memblock == NULL) {
5460 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK));
5461 goto err;
5462 }
5463 if ((uint32)(uintptr)memblock % DHD_SDALIGN)
5464 memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN));
5465
5466 /* Download image */
5467 while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) {
5468 bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len);
5469 if (bcmerror) {
5470 DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n",
5471 __FUNCTION__, bcmerror, MEMBLOCK, offset));
5472 goto err;
5473 }
5474
5475 offset += MEMBLOCK;
5476 }
5477
5478err:
5479 if (memblock)
5480 MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN);
5481
5482 if (image)
5483 dhd_os_close_image(image);
5484
5485 return bcmerror;
5486}
5487
5488/*
5489 * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file and ending in a NUL.
5490 * Removes carriage returns, empty lines, comment lines, and converts newlines to NULs.
5491 * Shortens buffer as needed and pads with NULs. End of buffer is marked by two NULs.
5492*/
5493
5494static uint
5495process_nvram_vars(char *varbuf, uint len)
5496{
5497 char *dp;
5498 bool findNewline;
5499 int column;
5500 uint buf_len, n;
5501
5502 dp = varbuf;
5503
5504 findNewline = FALSE;
5505 column = 0;
5506
5507 for (n = 0; n < len; n++) {
5508 if (varbuf[n] == 0)
5509 break;
5510 if (varbuf[n] == '\r')
5511 continue;
5512 if (findNewline && varbuf[n] != '\n')
5513 continue;
5514 findNewline = FALSE;
5515 if (varbuf[n] == '#') {
5516 findNewline = TRUE;
5517 continue;
5518 }
5519 if (varbuf[n] == '\n') {
5520 if (column == 0)
5521 continue;
5522 *dp++ = 0;
5523 column = 0;
5524 continue;
5525 }
5526 *dp++ = varbuf[n];
5527 column++;
5528 }
5529 buf_len = dp - varbuf;
5530
5531 while (dp < varbuf + n)
5532 *dp++ = 0;
5533
5534 return buf_len;
5535}
5536
5537/*
5538 EXAMPLE: nvram_array
5539 nvram_arry format:
5540 name=value
5541 Use carriage return at the end of each assignment, and an empty string with
5542 carriage return at the end of array.
5543
5544 For example:
5545 unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"};
5546 Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx.
5547
5548 Search "EXAMPLE: nvram_array" to see how the array is activated.
5549*/
5550
5551void
5552dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params)
5553{
5554 bus->nvram_params = nvram_params;
5555}
5556
5557static int
5558dhdsdio_download_nvram(struct dhd_bus *bus)
5559{
5560 int bcmerror = -1;
5561 uint len;
5562 void * image = NULL;
5563 char * memblock = NULL;
5564 char *bufp;
5565 char *nv_path;
5566 bool nvram_file_exists;
5567
5568 nv_path = bus->nv_path;
5569
5570 nvram_file_exists = ((nv_path != NULL) && (nv_path[0] != '\0'));
5571 if (!nvram_file_exists && (bus->nvram_params == NULL))
5572 return (0);
5573
5574 if (nvram_file_exists) {
5575 image = dhd_os_open_image(nv_path);
5576 if (image == NULL)
5577 goto err;
5578 }
5579
5580 memblock = MALLOC(bus->dhd->osh, MEMBLOCK);
5581 if (memblock == NULL) {
5582 DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
5583 __FUNCTION__, MEMBLOCK));
5584 goto err;
5585 }
5586
5587 /* Download variables */
5588 if (nvram_file_exists) {
5589 len = dhd_os_get_image_block(memblock, MEMBLOCK, image);
5590 }
5591 else {
5592 len = strlen(bus->nvram_params);
5593 ASSERT(len <= MEMBLOCK);
5594 if (len > MEMBLOCK)
5595 len = MEMBLOCK;
5596 memcpy(memblock, bus->nvram_params, len);
5597 }
5598
5599 if (len > 0 && len < MEMBLOCK) {
5600 bufp = (char *)memblock;
5601 bufp[len] = 0;
5602 len = process_nvram_vars(bufp, len);
5603 bufp += len;
5604 *bufp++ = 0;
5605 if (len)
5606 bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1);
5607 if (bcmerror) {
5608 DHD_ERROR(("%s: error downloading vars: %d\n",
5609 __FUNCTION__, bcmerror));
5610 }
5611 }
5612 else {
5613 DHD_ERROR(("%s: error reading nvram file: %d\n",
5614 __FUNCTION__, len));
5615 bcmerror = BCME_SDIO_ERROR;
5616 }
5617
5618err:
5619 if (memblock)
5620 MFREE(bus->dhd->osh, memblock, MEMBLOCK);
5621
5622 if (image)
5623 dhd_os_close_image(image);
5624
5625 return bcmerror;
5626}
5627
5628static int
5629_dhdsdio_download_firmware(struct dhd_bus *bus)
5630{
5631 int bcmerror = -1;
5632
5633 bool embed = FALSE; /* download embedded firmware */
5634 bool dlok = FALSE; /* download firmware succeeded */
5635
5636 /* Out immediately if no image to download */
5637 if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) {
5638#ifdef BCMEMBEDIMAGE
5639 embed = TRUE;
5640#else
5641 return bcmerror;
5642#endif
5643 }
5644
5645 /* Keep arm in reset */
5646 if (dhdsdio_download_state(bus, TRUE)) {
5647 DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__));
5648 goto err;
5649 }
5650
5651 /* External image takes precedence if specified */
5652 if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) {
5653 if (dhdsdio_download_code_file(bus, bus->fw_path)) {
5654 DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__));
5655#ifdef BCMEMBEDIMAGE
5656 embed = TRUE;
5657#else
5658 goto err;
5659#endif
5660 }
5661 else {
5662 embed = FALSE;
5663 dlok = TRUE;
5664 }
5665 }
5666#ifdef BCMEMBEDIMAGE
5667 if (embed) {
5668 if (dhdsdio_download_code_array(bus)) {
5669 DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__));
5670 goto err;
5671 }
5672 else {
5673 dlok = TRUE;
5674 }
5675 }
5676#endif
5677 if (!dlok) {
5678 DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__));
5679 goto err;
5680 }
5681
5682 /* EXAMPLE: nvram_array */
5683 /* If a valid nvram_arry is specified as above, it can be passed down to dongle */
5684 /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */
5685
5686 /* External nvram takes precedence if specified */
5687 if (dhdsdio_download_nvram(bus)) {
5688 DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__));
5689 }
5690
5691 /* Take arm out of reset */
5692 if (dhdsdio_download_state(bus, FALSE)) {
5693 DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__));
5694 goto err;
5695 }
5696
5697 bcmerror = 0;
5698
5699err:
5700 return bcmerror;
5701}
5702
5703static int
5704dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
5705 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
5706{
5707 int status;
5708
5709 /* 4329: GSPI check */
5710 status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle);
5711 return status;
5712}
5713
5714static int
5715dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes,
5716 void *pkt, bcmsdh_cmplt_fn_t complete, void *handle)
5717{
5718 return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle));
5719}
5720
5721uint
5722dhd_bus_chip(struct dhd_bus *bus)
5723{
5724 ASSERT(bus->sih != NULL);
5725 return bus->sih->chip;
5726}
5727
5728void *
5729dhd_bus_pub(struct dhd_bus *bus)
5730{
5731 return bus->dhd;
5732}
5733
5734void *
5735dhd_bus_txq(struct dhd_bus *bus)
5736{
5737 return &bus->txq;
5738}
5739
5740uint
5741dhd_bus_hdrlen(struct dhd_bus *bus)
5742{
5743 return SDPCM_HDRLEN;
5744}
5745
5746int
5747dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag)
5748{
5749 int bcmerror = 0;
5750 dhd_bus_t *bus;
5751
5752 bus = dhdp->bus;
5753
5754 if (flag == TRUE) {
5755 if (!bus->dhd->dongle_reset) {
5756 dhd_os_sdlock(dhdp);
5757 /* Turning off watchdog */
5758 dhd_os_wd_timer(dhdp, 0);
5759#if !defined(IGNORE_ETH0_DOWN)
5760 /* Force flow control as protection when stop come before ifconfig_down */
5761 dhd_txflowcontrol(bus->dhd, 0, ON);
5762#endif /* !defined(IGNORE_ETH0_DOWN) */
5763
5764#if !defined(OOB_INTR_ONLY)
5765 /* to avoid supurious client interrupt during stop process */
5766 bcmsdh_stop(bus->sdh);
5767#endif /* !defined(OOB_INTR_ONLY) */
5768
5769 /* Expect app to have torn down any connection before calling */
5770 /* Stop the bus, disable F2 */
5771 dhd_bus_stop(bus, FALSE);
5772#if defined(OOB_INTR_ONLY)
5773 bcmsdh_set_irq(FALSE);
5774#endif /* defined(OOB_INTR_ONLY) */
5775 /* Clean tx/rx buffer pointers, detach from the dongle */
5776 dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE);
5777
5778 bus->dhd->dongle_reset = TRUE;
5779 bus->dhd->up = FALSE;
5780 dhd_os_sdunlock(dhdp);
5781
5782 DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__));
5783 /* App can now remove power from device */
5784 } else
5785 bcmerror = BCME_SDIO_ERROR;
5786 } else {
5787 /* App must have restored power to device before calling */
5788
5789 DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__));
5790
5791 if (bus->dhd->dongle_reset) {
5792 /* Turn on WLAN */
5793 dhd_os_sdlock(dhdp);
5794
5795 /* Reset SD client */
5796 bcmsdh_reset(bus->sdh);
5797
5798 /* Attempt to re-attach & download */
5799 if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh,
5800 (uint32 *)SI_ENUM_BASE,
5801 bus->cl_devid)) {
5802 /* Attempt to download binary to the dongle */
5803 if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) &&
5804 dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) {
5805
5806 /* Re-init bus, enable F2 transfer */
5807 bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE);
5808 if (bcmerror == BCME_OK) {
5809#if defined(OOB_INTR_ONLY)
5810 bcmsdh_set_irq(TRUE);
5811 dhd_enable_oob_intr(bus, TRUE);
5812#endif /* defined(OOB_INTR_ONLY) */
5813 bus->dhd->dongle_reset = FALSE;
5814 bus->dhd->up = TRUE;
5815#if !defined(IGNORE_ETH0_DOWN)
5816 /* Restore flow control */
5817 dhd_txflowcontrol(bus->dhd, 0, OFF);
5818#endif
5819 /* Turning on watchdog back */
5820 dhd_os_wd_timer(dhdp, dhd_watchdog_ms);
5821
5822 DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__));
5823 } else {
5824 dhd_bus_stop(bus, FALSE);
5825 dhdsdio_release_dongle(bus, bus->dhd->osh, FALSE);
5826 }
5827 } else
5828 bcmerror = BCME_SDIO_ERROR;
5829 } else
5830 bcmerror = BCME_SDIO_ERROR;
5831
5832 dhd_os_sdunlock(dhdp);
5833 } else {
5834 bcmerror = BCME_NOTDOWN;
5835 DHD_ERROR(("%s: Set DEVRESET=FALSE invoked when device is on\n",
5836 __FUNCTION__));
5837 bcmerror = BCME_SDIO_ERROR;
5838 }
5839 }
5840 return bcmerror;
5841}
diff --git a/drivers/net/wireless/bcm4329/dngl_stats.h b/drivers/net/wireless/bcm4329/dngl_stats.h
new file mode 100644
index 00000000000..e5db54e7edf
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/dngl_stats.h
@@ -0,0 +1,43 @@
1/*
2 * Common stats definitions for clients of dongle
3 * ports
4 *
5 * Copyright (C) 1999-2010, 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.2.140.3 2008/05/26 16:52:08 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/bcm4329/hndpmu.c b/drivers/net/wireless/bcm4329/hndpmu.c
new file mode 100644
index 00000000000..307347a43bd
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/hndpmu.c
@@ -0,0 +1,131 @@
1/*
2 * Misc utility routines for accessing PMU corerev specific features
3 * of the SiliconBackplane-based Broadcom chips.
4 *
5 * Copyright (C) 1999-2010, 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.95.2.17.4.11.2.63 2010/07/21 13:55:09 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/* debug/trace */
39#define PMU_ERROR(args)
40
41#define PMU_MSG(args)
42
43
44/* SDIO Pad drive strength to select value mappings */
45typedef struct {
46 uint8 strength; /* Pad Drive Strength in mA */
47 uint8 sel; /* Chip-specific select value */
48} sdiod_drive_str_t;
49
50/* SDIO Drive Strength to sel value table for PMU Rev 1 */
51static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = {
52 {4, 0x2},
53 {2, 0x3},
54 {1, 0x0},
55 {0, 0x0} };
56
57/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
58static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = {
59 {12, 0x7},
60 {10, 0x6},
61 {8, 0x5},
62 {6, 0x4},
63 {4, 0x2},
64 {2, 0x1},
65 {0, 0x0} };
66
67#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
68
69void
70si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength)
71{
72 chipcregs_t *cc;
73 uint origidx, intr_val = 0;
74 sdiod_drive_str_t *str_tab = NULL;
75 uint32 str_mask = 0;
76 uint32 str_shift = 0;
77
78 if (!(sih->cccaps & CC_CAP_PMU)) {
79 return;
80 }
81
82 /* Remember original core before switch to chipc */
83 cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
84
85 switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) {
86 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
87 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1;
88 str_mask = 0x30000000;
89 str_shift = 28;
90 break;
91 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
92 case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
93 case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4):
94 str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2;
95 str_mask = 0x00003800;
96 str_shift = 11;
97 break;
98
99 default:
100 PMU_MSG(("No SDIO Drive strength init done for chip %x rev %d pmurev %d\n",
101 sih->chip, sih->chiprev, sih->pmurev));
102
103 break;
104 }
105
106 if (str_tab != NULL) {
107 uint32 drivestrength_sel = 0;
108 uint32 cc_data_temp;
109 int i;
110
111 for (i = 0; str_tab[i].strength != 0; i ++) {
112 if (drivestrength >= str_tab[i].strength) {
113 drivestrength_sel = str_tab[i].sel;
114 break;
115 }
116 }
117
118 W_REG(osh, &cc->chipcontrol_addr, 1);
119 cc_data_temp = R_REG(osh, &cc->chipcontrol_data);
120 cc_data_temp &= ~str_mask;
121 drivestrength_sel <<= str_shift;
122 cc_data_temp |= drivestrength_sel;
123 W_REG(osh, &cc->chipcontrol_data, cc_data_temp);
124
125 PMU_MSG(("SDIO: %dmA drive strength selected, set to 0x%08x\n",
126 drivestrength, cc_data_temp));
127 }
128
129 /* Return to original core */
130 si_restore_core(sih, origidx, intr_val);
131}
diff --git a/drivers/net/wireless/bcm4329/include/Makefile b/drivers/net/wireless/bcm4329/include/Makefile
new file mode 100644
index 00000000000..439ead14a0e
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/Makefile
@@ -0,0 +1,21 @@
1#
2# include/Makefile
3#
4# Copyright 2005, Broadcom, Inc.
5#
6# $Id: Makefile,v 13.5 2005/02/17 19:11:31 Exp $
7#
8
9SRCBASE = ..
10
11TARGETS = epivers.h
12
13
14all release:
15 bash epivers.sh
16
17clean:
18 rm -rf ${TARGETS} *.prev
19
20
21.PHONY: all release clean
diff --git a/drivers/net/wireless/bcm4329/include/aidmp.h b/drivers/net/wireless/bcm4329/include/aidmp.h
new file mode 100644
index 00000000000..a927e5dae58
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/aidmp.h
@@ -0,0 +1,368 @@
1/*
2 * Broadcom AMBA Interconnect definitions.
3 *
4 * Copyright (C) 1999-2010, 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.2.10.1 2008/05/07 20:32:12 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#define AI_IOCTRLSET 0x400
307#define AI_IOCTRLCLEAR 0x404
308#define AI_IOCTRL 0x408
309#define AI_IOSTATUS 0x500
310#define AI_IOCTRLWIDTH 0x700
311#define AI_IOSTATUSWIDTH 0x704
312#define AI_RESETCTRL 0x800
313#define AI_RESETSTATUS 0x804
314#define AI_RESETREADID 0x808
315#define AI_RESETWRITEID 0x80c
316#define AI_ERRLOGCTRL 0xa00
317#define AI_ERRLOGDONE 0xa04
318#define AI_ERRLOGSTATUS 0xa08
319#define AI_ERRLOGADDRLO 0xa0c
320#define AI_ERRLOGADDRHI 0xa10
321#define AI_ERRLOGID 0xa14
322#define AI_ERRLOGUSER 0xa18
323#define AI_ERRLOGFLAGS 0xa1c
324#define AI_INTSTATUS 0xa00
325#define AI_CONFIG 0xe00
326#define AI_ITCR 0xf00
327#define AI_ITIPOOBA 0xf10
328#define AI_ITIPOOBB 0xf14
329#define AI_ITIPOOBC 0xf18
330#define AI_ITIPOOBD 0xf1c
331#define AI_ITIPOOBAOUT 0xf30
332#define AI_ITIPOOBBOUT 0xf34
333#define AI_ITIPOOBCOUT 0xf38
334#define AI_ITIPOOBDOUT 0xf3c
335#define AI_ITOPOOBA 0xf50
336#define AI_ITOPOOBB 0xf54
337#define AI_ITOPOOBC 0xf58
338#define AI_ITOPOOBD 0xf5c
339#define AI_ITOPOOBAIN 0xf70
340#define AI_ITOPOOBBIN 0xf74
341#define AI_ITOPOOBCIN 0xf78
342#define AI_ITOPOOBDIN 0xf7c
343#define AI_ITOPRESET 0xf90
344#define AI_PERIPHERIALID4 0xfd0
345#define AI_PERIPHERIALID5 0xfd4
346#define AI_PERIPHERIALID6 0xfd8
347#define AI_PERIPHERIALID7 0xfdc
348#define AI_PERIPHERIALID0 0xfe0
349#define AI_PERIPHERIALID1 0xfe4
350#define AI_PERIPHERIALID2 0xfe8
351#define AI_PERIPHERIALID3 0xfec
352#define AI_COMPONENTID0 0xff0
353#define AI_COMPONENTID1 0xff4
354#define AI_COMPONENTID2 0xff8
355#define AI_COMPONENTID3 0xffc
356
357
358#define AIRC_RESET 1
359
360
361#define AICFG_OOB 0x00000020
362#define AICFG_IOS 0x00000010
363#define AICFG_IOC 0x00000008
364#define AICFG_TO 0x00000004
365#define AICFG_ERRL 0x00000002
366#define AICFG_RST 0x00000001
367
368#endif
diff --git a/drivers/net/wireless/bcm4329/include/bcmcdc.h b/drivers/net/wireless/bcm4329/include/bcmcdc.h
new file mode 100644
index 00000000000..c2a860beab2
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmcdc.h
@@ -0,0 +1,100 @@
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-2010, 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.14.16.3.16.4 2009/04/12 16:58:45 Exp $
28 */
29#include <proto/ethernet.h>
30
31typedef struct cdc_ioctl {
32 uint32 cmd; /* ioctl command value */
33 uint32 len; /* lower 16: output buflen; upper 16: input buflen (excludes header) */
34 uint32 flags; /* flag defns given below */
35 uint32 status; /* status code returned from the device */
36} cdc_ioctl_t;
37
38/* Max valid buffer size that can be sent to the dongle */
39#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN
40
41/* len field is divided into input and output buffer lengths */
42#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF /* maximum or expected response length, */
43 /* excluding IOCTL header */
44#define CDCL_IOC_OUTLEN_SHIFT 0
45#define CDCL_IOC_INLEN_MASK 0xFFFF0000 /* input buffer length, excluding IOCTL header */
46#define CDCL_IOC_INLEN_SHIFT 16
47
48/* CDC flag definitions */
49#define CDCF_IOC_ERROR 0x01 /* 0=success, 1=ioctl cmd failed */
50#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */
51#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */
52#define CDCF_IOC_IF_SHIFT 12
53#define CDCF_IOC_ID_MASK 0xFFFF0000 /* used to uniquely id an ioctl req/resp pairing */
54#define CDCF_IOC_ID_SHIFT 16 /* # of bits of shift for ID Mask */
55
56#define CDC_IOC_IF_IDX(flags) (((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)
57#define CDC_IOC_ID(flags) (((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT)
58
59#define CDC_GET_IF_IDX(hdr) \
60 ((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT))
61#define CDC_SET_IF_IDX(hdr, idx) \
62 ((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | ((idx) << CDCF_IOC_IF_SHIFT)))
63
64/*
65 * BDC header
66 *
67 * The BDC header is used on data packets to convey priority across USB.
68 */
69
70#define BDC_HEADER_LEN 4
71
72#define BDC_PROTO_VER 1 /* Protocol version */
73
74#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */
75#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */
76
77#define BDC_FLAG__UNUSED 0x03 /* Unassigned */
78#define BDC_FLAG_SUM_GOOD 0x04 /* Dongle has verified good RX checksums */
79#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */
80
81#define BDC_PRIORITY_MASK 0x7
82
83#define BDC_FLAG2_FC_FLAG 0x10 /* flag to indicate if pkt contains */
84 /* FLOW CONTROL info only */
85#define BDC_PRIORITY_FC_SHIFT 4 /* flow control info shift */
86
87#define BDC_FLAG2_IF_MASK 0x0f /* APSTA: interface on which the packet was received */
88#define BDC_FLAG2_IF_SHIFT 0
89
90#define BDC_GET_IF_IDX(hdr) \
91 ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT))
92#define BDC_SET_IF_IDX(hdr, idx) \
93 ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | ((idx) << BDC_FLAG2_IF_SHIFT)))
94
95struct bdc_header {
96 uint8 flags; /* Flags */
97 uint8 priority; /* 802.1d Priority 0:2 bits, 4:7 flow control info for usb */
98 uint8 flags2;
99 uint8 rssi;
100};
diff --git a/drivers/net/wireless/bcm4329/include/bcmdefs.h b/drivers/net/wireless/bcm4329/include/bcmdefs.h
new file mode 100644
index 00000000000..f4e99461971
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmdefs.h
@@ -0,0 +1,114 @@
1/*
2 * Misc system wide definitions
3 *
4 * Copyright (C) 1999-2010, 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: bcmdefs.h,v 13.38.4.10.2.7.6.11 2010/02/01 05:51:55 Exp $
24 */
25
26
27#ifndef _bcmdefs_h_
28#define _bcmdefs_h_
29
30#define STATIC static
31
32#define SI_BUS 0
33#define PCI_BUS 1
34#define PCMCIA_BUS 2
35#define SDIO_BUS 3
36#define JTAG_BUS 4
37#define USB_BUS 5
38#define SPI_BUS 6
39
40
41#ifdef BCMBUSTYPE
42#define BUSTYPE(bus) (BCMBUSTYPE)
43#else
44#define BUSTYPE(bus) (bus)
45#endif
46
47
48#ifdef BCMCHIPTYPE
49#define CHIPTYPE(bus) (BCMCHIPTYPE)
50#else
51#define CHIPTYPE(bus) (bus)
52#endif
53
54
55
56#if defined(BCMSPROMBUS)
57#define SPROMBUS (BCMSPROMBUS)
58#elif defined(SI_PCMCIA_SROM)
59#define SPROMBUS (PCMCIA_BUS)
60#else
61#define SPROMBUS (PCI_BUS)
62#endif
63
64
65#ifdef BCMCHIPID
66#define CHIPID(chip) (BCMCHIPID)
67#else
68#define CHIPID(chip) (chip)
69#endif
70
71
72#define DMADDR_MASK_32 0x0
73#define DMADDR_MASK_30 0xc0000000
74#define DMADDR_MASK_0 0xffffffff
75
76#define DMADDRWIDTH_30 30
77#define DMADDRWIDTH_32 32
78#define DMADDRWIDTH_63 63
79#define DMADDRWIDTH_64 64
80
81
82#define BCMEXTRAHDROOM 164
83
84
85#define BCMDONGLEHDRSZ 12
86#define BCMDONGLEPADSZ 16
87
88#define BCMDONGLEOVERHEAD (BCMDONGLEHDRSZ + BCMDONGLEPADSZ)
89
90
91
92#define BITFIELD_MASK(width) \
93 (((unsigned)1 << (width)) - 1)
94#define GFIELD(val, field) \
95 (((val) >> field ## _S) & field ## _M)
96#define SFIELD(val, field, bits) \
97 (((val) & (~(field ## _M << field ## _S))) | \
98 ((unsigned)(bits) << field ## _S))
99
100
101#ifdef BCMSMALL
102#undef BCMSPACE
103#define bcmspace FALSE
104#else
105#define BCMSPACE
106#define bcmspace TRUE
107#endif
108
109
110#define MAXSZ_NVRAM_VARS 4096
111
112#define LOCATOR_EXTERN static
113
114#endif
diff --git a/drivers/net/wireless/bcm4329/include/bcmdevs.h b/drivers/net/wireless/bcm4329/include/bcmdevs.h
new file mode 100644
index 00000000000..14853f17795
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmdevs.h
@@ -0,0 +1,124 @@
1/*
2 * Broadcom device-specific manifest constants.
3 *
4 * Copyright (C) 1999-2010, 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.172.4.5.4.10.2.36 2010/05/25 08:33:44 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#define VENDOR_BROADCOM_PCMCIA 0x02d0
41
42
43#define VENDOR_BROADCOM_SDIO 0x00BF
44
45
46#define BCM_DNGL_VID 0xa5c
47#define BCM_DNGL_BL_PID_4320 0xbd11
48#define BCM_DNGL_BL_PID_4328 0xbd12
49#define BCM_DNGL_BL_PID_4322 0xbd13
50#define BCM_DNGL_BL_PID_4325 0xbd14
51#define BCM_DNGL_BL_PID_4315 0xbd15
52#define BCM_DNGL_BL_PID_4319 0xbd16
53#define BCM_DNGL_BDC_PID 0xbdc
54
55#define BCM4325_D11DUAL_ID 0x431b
56#define BCM4325_D11G_ID 0x431c
57#define BCM4325_D11A_ID 0x431d
58#define BCM4329_D11NDUAL_ID 0x432e
59#define BCM4329_D11N2G_ID 0x432f
60#define BCM4329_D11N5G_ID 0x4330
61#define BCM4336_D11N_ID 0x4343
62#define BCM4315_D11DUAL_ID 0x4334
63#define BCM4315_D11G_ID 0x4335
64#define BCM4315_D11A_ID 0x4336
65#define BCM4319_D11N_ID 0x4337
66#define BCM4319_D11N2G_ID 0x4338
67#define BCM4319_D11N5G_ID 0x4339
68
69
70#define SDIOH_FPGA_ID 0x43f2
71#define SPIH_FPGA_ID 0x43f5
72#define BCM4710_DEVICE_ID 0x4710
73#define BCM27XX_SDIOH_ID 0x2702
74#define PCIXX21_FLASHMEDIA0_ID 0x8033
75#define PCIXX21_SDIOH0_ID 0x8034
76#define PCIXX21_FLASHMEDIA_ID 0x803b
77#define PCIXX21_SDIOH_ID 0x803c
78#define R5C822_SDIOH_ID 0x0822
79#define JMICRON_SDIOH_ID 0x2381
80
81
82#define BCM4306_CHIP_ID 0x4306
83#define BCM4311_CHIP_ID 0x4311
84#define BCM4312_CHIP_ID 0x4312
85#define BCM4315_CHIP_ID 0x4315
86#define BCM4318_CHIP_ID 0x4318
87#define BCM4319_CHIP_ID 0x4319
88#define BCM4320_CHIP_ID 0x4320
89#define BCM4321_CHIP_ID 0x4321
90#define BCM4322_CHIP_ID 0x4322
91#define BCM4325_CHIP_ID 0x4325
92#define BCM4328_CHIP_ID 0x4328
93#define BCM4329_CHIP_ID 0x4329
94#define BCM4336_CHIP_ID 0x4336
95#define BCM4402_CHIP_ID 0x4402
96#define BCM4704_CHIP_ID 0x4704
97#define BCM4710_CHIP_ID 0x4710
98#define BCM4712_CHIP_ID 0x4712
99#define BCM4785_CHIP_ID 0x4785
100#define BCM5350_CHIP_ID 0x5350
101#define BCM5352_CHIP_ID 0x5352
102#define BCM5354_CHIP_ID 0x5354
103#define BCM5365_CHIP_ID 0x5365
104
105
106
107#define BCM4303_PKG_ID 2
108#define BCM4309_PKG_ID 1
109#define BCM4712LARGE_PKG_ID 0
110#define BCM4712SMALL_PKG_ID 1
111#define BCM4712MID_PKG_ID 2
112#define BCM4328USBD11G_PKG_ID 2
113#define BCM4328USBDUAL_PKG_ID 3
114#define BCM4328SDIOD11G_PKG_ID 4
115#define BCM4328SDIODUAL_PKG_ID 5
116#define BCM4329_289PIN_PKG_ID 0
117#define BCM4329_182PIN_PKG_ID 1
118#define BCM5354E_PKG_ID 1
119#define HDLSIM5350_PKG_ID 1
120#define HDLSIM_PKG_ID 14
121#define HWSIM_PKG_ID 15
122
123
124#endif
diff --git a/drivers/net/wireless/bcm4329/include/bcmendian.h b/drivers/net/wireless/bcm4329/include/bcmendian.h
new file mode 100644
index 00000000000..ae468383aa7
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmendian.h
@@ -0,0 +1,205 @@
1/*
2 * Byte order utilities
3 *
4 * Copyright (C) 1999-2010, 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.31.302.1.16.1 2009/02/03 18:34:31 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
54static INLINE uint16
55bcmswap16(uint16 val)
56{
57 return BCMSWAP16(val);
58}
59
60static INLINE uint32
61bcmswap32(uint32 val)
62{
63 return BCMSWAP32(val);
64}
65
66static INLINE uint32
67bcmswap32by16(uint32 val)
68{
69 return BCMSWAP32BY16(val);
70}
71
72
73
74
75static INLINE void
76bcmswap16_buf(uint16 *buf, uint len)
77{
78 len = len / 2;
79
80 while (len--) {
81 *buf = bcmswap16(*buf);
82 buf++;
83 }
84}
85
86#ifndef hton16
87#ifndef IL_BIGENDIAN
88#define HTON16(i) BCMSWAP16(i)
89#define HTON32(i) BCMSWAP32(i)
90#define hton16(i) bcmswap16(i)
91#define hton32(i) bcmswap32(i)
92#define ntoh16(i) bcmswap16(i)
93#define ntoh32(i) bcmswap32(i)
94#define HTOL16(i) (i)
95#define HTOL32(i) (i)
96#define ltoh16(i) (i)
97#define ltoh32(i) (i)
98#define htol16(i) (i)
99#define htol32(i) (i)
100#else
101#define HTON16(i) (i)
102#define HTON32(i) (i)
103#define hton16(i) (i)
104#define hton32(i) (i)
105#define ntoh16(i) (i)
106#define ntoh32(i) (i)
107#define HTOL16(i) BCMSWAP16(i)
108#define HTOL32(i) BCMSWAP32(i)
109#define ltoh16(i) bcmswap16(i)
110#define ltoh32(i) bcmswap32(i)
111#define htol16(i) bcmswap16(i)
112#define htol32(i) bcmswap32(i)
113#endif
114#endif
115
116#ifndef IL_BIGENDIAN
117#define ltoh16_buf(buf, i)
118#define htol16_buf(buf, i)
119#else
120#define ltoh16_buf(buf, i) bcmswap16_buf((uint16 *)buf, i)
121#define htol16_buf(buf, i) bcmswap16_buf((uint16 *)buf, i)
122#endif
123
124
125static INLINE void
126htol16_ua_store(uint16 val, uint8 *bytes)
127{
128 bytes[0] = val & 0xff;
129 bytes[1] = val >> 8;
130}
131
132
133static INLINE void
134htol32_ua_store(uint32 val, uint8 *bytes)
135{
136 bytes[0] = val & 0xff;
137 bytes[1] = (val >> 8) & 0xff;
138 bytes[2] = (val >> 16) & 0xff;
139 bytes[3] = val >> 24;
140}
141
142
143static INLINE void
144hton16_ua_store(uint16 val, uint8 *bytes)
145{
146 bytes[0] = val >> 8;
147 bytes[1] = val & 0xff;
148}
149
150
151static INLINE void
152hton32_ua_store(uint32 val, uint8 *bytes)
153{
154 bytes[0] = val >> 24;
155 bytes[1] = (val >> 16) & 0xff;
156 bytes[2] = (val >> 8) & 0xff;
157 bytes[3] = val & 0xff;
158}
159
160#define _LTOH16_UA(cp) ((cp)[0] | ((cp)[1] << 8))
161#define _LTOH32_UA(cp) ((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24))
162#define _NTOH16_UA(cp) (((cp)[0] << 8) | (cp)[1])
163#define _NTOH32_UA(cp) (((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3])
164
165
166static INLINE uint16
167ltoh16_ua(const void *bytes)
168{
169 return _LTOH16_UA((const uint8 *)bytes);
170}
171
172
173static INLINE uint32
174ltoh32_ua(const void *bytes)
175{
176 return _LTOH32_UA((const uint8 *)bytes);
177}
178
179
180static INLINE uint16
181ntoh16_ua(const void *bytes)
182{
183 return _NTOH16_UA((const uint8 *)bytes);
184}
185
186
187static INLINE uint32
188ntoh32_ua(const void *bytes)
189{
190 return _NTOH32_UA((const uint8 *)bytes);
191}
192
193#define ltoh_ua(ptr) \
194 (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)ptr : \
195 sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)ptr) : \
196 sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)ptr) : \
197 0xfeedf00d)
198
199#define ntoh_ua(ptr) \
200 (sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)ptr : \
201 sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)ptr) : \
202 sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)ptr) : \
203 0xfeedf00d)
204
205#endif
diff --git a/drivers/net/wireless/bcm4329/include/bcmpcispi.h b/drivers/net/wireless/bcm4329/include/bcmpcispi.h
new file mode 100644
index 00000000000..7d98fb7cbdc
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmpcispi.h
@@ -0,0 +1,205 @@
1/*
2 * Broadcom PCI-SPI Host Controller Register Definitions
3 *
4 * Copyright (C) 1999-2010, 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.11.8.3 2008/07/09 21:23:29 Exp $
25 */
26
27/* cpp contortions to concatenate w/arg prescan */
28#ifndef PAD
29#define _PADLINE(line) pad ## line
30#define _XSTR(line) _PADLINE(line)
31#define PAD _XSTR(__LINE__)
32#endif /* PAD */
33
34/*
35+---------------------------------------------------------------------------+
36| |
37| 7 6 5 4 3 2 1 0 |
38| 0x0000 SPI_CTRL SPIE SPE 0 MSTR CPOL CPHA SPR1 SPR0 |
39| 0x0004 SPI_STAT SPIF WCOL ST1 ST0 WFFUL WFEMP RFFUL RFEMP |
40| 0x0008 SPI_DATA Bits 31:0, data to send out on MOSI |
41| 0x000C SPI_EXT ICNT1 ICNT0 BSWAP *HSMODE ESPR1 ESPR0 |
42| 0x0020 GPIO_OE 0=input, 1=output PWR_OE CS_OE |
43| 0x0024 GPIO_DATA CARD:1=missing, 0=present CARD PWR_DAT CS_DAT |
44| 0x0040 INT_EDGE 0=level, 1=edge DEV_E SPI_E |
45| 0x0044 INT_POL 1=active high, 0=active low DEV_P SPI_P |
46| 0x0048 INTMASK DEV SPI |
47| 0x004C INTSTATUS DEV SPI |
48| 0x0060 HEXDISP Reset value: 0x14e443f5. In hexdisp mode, value |
49| shows on the Raggedstone1 4-digit 7-segment display. |
50| 0x0064 CURRENT_MA Low 16 bits indicate card current consumption in mA |
51| 0x006C DISP_SEL Display mode (0=hexdisp, 1=current) DSP |
52| 0x00C0 PLL_CTL bit31=ext_clk, remainder unused. |
53| 0x00C4 PLL_STAT LOCK |
54| 0x00C8 CLK_FREQ |
55| 0x00CC CLK_CNT |
56| |
57| *Notes: HSMODE is not implemented, never set this bit! |
58| BSWAP is available in rev >= 8 |
59| |
60+---------------------------------------------------------------------------+
61*/
62
63typedef volatile struct {
64 uint32 spih_ctrl; /* 0x00 SPI Control Register */
65 uint32 spih_stat; /* 0x04 SPI Status Register */
66 uint32 spih_data; /* 0x08 SPI Data Register, 32-bits wide */
67 uint32 spih_ext; /* 0x0C SPI Extension Register */
68 uint32 PAD[4]; /* 0x10-0x1F PADDING */
69
70 uint32 spih_gpio_ctrl; /* 0x20 SPI GPIO Control Register */
71 uint32 spih_gpio_data; /* 0x24 SPI GPIO Data Register */
72 uint32 PAD[6]; /* 0x28-0x3F PADDING */
73
74 uint32 spih_int_edge; /* 0x40 SPI Interrupt Edge Register (0=Level, 1=Edge) */
75 uint32 spih_int_pol; /* 0x44 SPI Interrupt Polarity Register (0=Active Low, */
76 /* 1=Active High) */
77 uint32 spih_int_mask; /* 0x48 SPI Interrupt Mask */
78 uint32 spih_int_status; /* 0x4C SPI Interrupt Status */
79 uint32 PAD[4]; /* 0x50-0x5F PADDING */
80
81 uint32 spih_hex_disp; /* 0x60 SPI 4-digit hex display value */
82 uint32 spih_current_ma; /* 0x64 SPI SD card current consumption in mA */
83 uint32 PAD[1]; /* 0x68 PADDING */
84 uint32 spih_disp_sel; /* 0x6c SPI 4-digit hex display mode select (1=current) */
85 uint32 PAD[4]; /* 0x70-0x7F PADDING */
86 uint32 PAD[8]; /* 0x80-0x9F PADDING */
87 uint32 PAD[8]; /* 0xA0-0xBF PADDING */
88 uint32 spih_pll_ctrl; /* 0xC0 PLL Control Register */
89 uint32 spih_pll_status; /* 0xC4 PLL Status Register */
90 uint32 spih_xtal_freq; /* 0xC8 External Clock Frequency in units of 10000Hz */
91 uint32 spih_clk_count; /* 0xCC External Clock Count Register */
92
93} spih_regs_t;
94
95typedef volatile struct {
96 uint32 cfg_space[0x40]; /* 0x000-0x0FF PCI Configuration Space (Read Only) */
97 uint32 P_IMG_CTRL0; /* 0x100 PCI Image0 Control Register */
98
99 uint32 P_BA0; /* 0x104 32 R/W PCI Image0 Base Address register */
100 uint32 P_AM0; /* 0x108 32 R/W PCI Image0 Address Mask register */
101 uint32 P_TA0; /* 0x10C 32 R/W PCI Image0 Translation Address register */
102 uint32 P_IMG_CTRL1; /* 0x110 32 R/W PCI Image1 Control register */
103 uint32 P_BA1; /* 0x114 32 R/W PCI Image1 Base Address register */
104 uint32 P_AM1; /* 0x118 32 R/W PCI Image1 Address Mask register */
105 uint32 P_TA1; /* 0x11C 32 R/W PCI Image1 Translation Address register */
106 uint32 P_IMG_CTRL2; /* 0x120 32 R/W PCI Image2 Control register */
107 uint32 P_BA2; /* 0x124 32 R/W PCI Image2 Base Address register */
108 uint32 P_AM2; /* 0x128 32 R/W PCI Image2 Address Mask register */
109 uint32 P_TA2; /* 0x12C 32 R/W PCI Image2 Translation Address register */
110 uint32 P_IMG_CTRL3; /* 0x130 32 R/W PCI Image3 Control register */
111 uint32 P_BA3; /* 0x134 32 R/W PCI Image3 Base Address register */
112 uint32 P_AM3; /* 0x138 32 R/W PCI Image3 Address Mask register */
113 uint32 P_TA3; /* 0x13C 32 R/W PCI Image3 Translation Address register */
114 uint32 P_IMG_CTRL4; /* 0x140 32 R/W PCI Image4 Control register */
115 uint32 P_BA4; /* 0x144 32 R/W PCI Image4 Base Address register */
116 uint32 P_AM4; /* 0x148 32 R/W PCI Image4 Address Mask register */
117 uint32 P_TA4; /* 0x14C 32 R/W PCI Image4 Translation Address register */
118 uint32 P_IMG_CTRL5; /* 0x150 32 R/W PCI Image5 Control register */
119 uint32 P_BA5; /* 0x154 32 R/W PCI Image5 Base Address register */
120 uint32 P_AM5; /* 0x158 32 R/W PCI Image5 Address Mask register */
121 uint32 P_TA5; /* 0x15C 32 R/W PCI Image5 Translation Address register */
122 uint32 P_ERR_CS; /* 0x160 32 R/W PCI Error Control and Status register */
123 uint32 P_ERR_ADDR; /* 0x164 32 R PCI Erroneous Address register */
124 uint32 P_ERR_DATA; /* 0x168 32 R PCI Erroneous Data register */
125
126 uint32 PAD[5]; /* 0x16C-0x17F PADDING */
127
128 uint32 WB_CONF_SPC_BAR; /* 0x180 32 R WISHBONE Configuration Space Base Address */
129 uint32 W_IMG_CTRL1; /* 0x184 32 R/W WISHBONE Image1 Control register */
130 uint32 W_BA1; /* 0x188 32 R/W WISHBONE Image1 Base Address register */
131 uint32 W_AM1; /* 0x18C 32 R/W WISHBONE Image1 Address Mask register */
132 uint32 W_TA1; /* 0x190 32 R/W WISHBONE Image1 Translation Address reg */
133 uint32 W_IMG_CTRL2; /* 0x194 32 R/W WISHBONE Image2 Control register */
134 uint32 W_BA2; /* 0x198 32 R/W WISHBONE Image2 Base Address register */
135 uint32 W_AM2; /* 0x19C 32 R/W WISHBONE Image2 Address Mask register */
136 uint32 W_TA2; /* 0x1A0 32 R/W WISHBONE Image2 Translation Address reg */
137 uint32 W_IMG_CTRL3; /* 0x1A4 32 R/W WISHBONE Image3 Control register */
138 uint32 W_BA3; /* 0x1A8 32 R/W WISHBONE Image3 Base Address register */
139 uint32 W_AM3; /* 0x1AC 32 R/W WISHBONE Image3 Address Mask register */
140 uint32 W_TA3; /* 0x1B0 32 R/W WISHBONE Image3 Translation Address reg */
141 uint32 W_IMG_CTRL4; /* 0x1B4 32 R/W WISHBONE Image4 Control register */
142 uint32 W_BA4; /* 0x1B8 32 R/W WISHBONE Image4 Base Address register */
143 uint32 W_AM4; /* 0x1BC 32 R/W WISHBONE Image4 Address Mask register */
144 uint32 W_TA4; /* 0x1C0 32 R/W WISHBONE Image4 Translation Address reg */
145 uint32 W_IMG_CTRL5; /* 0x1C4 32 R/W WISHBONE Image5 Control register */
146 uint32 W_BA5; /* 0x1C8 32 R/W WISHBONE Image5 Base Address register */
147 uint32 W_AM5; /* 0x1CC 32 R/W WISHBONE Image5 Address Mask register */
148 uint32 W_TA5; /* 0x1D0 32 R/W WISHBONE Image5 Translation Address reg */
149 uint32 W_ERR_CS; /* 0x1D4 32 R/W WISHBONE Error Control and Status reg */
150 uint32 W_ERR_ADDR; /* 0x1D8 32 R WISHBONE Erroneous Address register */
151 uint32 W_ERR_DATA; /* 0x1DC 32 R WISHBONE Erroneous Data register */
152 uint32 CNF_ADDR; /* 0x1E0 32 R/W Configuration Cycle register */
153 uint32 CNF_DATA; /* 0x1E4 32 R/W Configuration Cycle Generation Data reg */
154
155 uint32 INT_ACK; /* 0x1E8 32 R Interrupt Acknowledge register */
156 uint32 ICR; /* 0x1EC 32 R/W Interrupt Control register */
157 uint32 ISR; /* 0x1F0 32 R/W Interrupt Status register */
158} spih_pciregs_t;
159
160/*
161 * PCI Core interrupt enable and status bit definitions.
162 */
163
164/* PCI Core ICR Register bit definitions */
165#define PCI_INT_PROP_EN (1 << 0) /* Interrupt Propagation Enable */
166#define PCI_WB_ERR_INT_EN (1 << 1) /* Wishbone Error Interrupt Enable */
167#define PCI_PCI_ERR_INT_EN (1 << 2) /* PCI Error Interrupt Enable */
168#define PCI_PAR_ERR_INT_EN (1 << 3) /* Parity Error Interrupt Enable */
169#define PCI_SYS_ERR_INT_EN (1 << 4) /* System Error Interrupt Enable */
170#define PCI_SOFTWARE_RESET (1U << 31) /* Software reset of the PCI Core. */
171
172
173/* PCI Core ISR Register bit definitions */
174#define PCI_INT_PROP_ST (1 << 0) /* Interrupt Propagation Status */
175#define PCI_WB_ERR_INT_ST (1 << 1) /* Wishbone Error Interrupt Status */
176#define PCI_PCI_ERR_INT_ST (1 << 2) /* PCI Error Interrupt Status */
177#define PCI_PAR_ERR_INT_ST (1 << 3) /* Parity Error Interrupt Status */
178#define PCI_SYS_ERR_INT_ST (1 << 4) /* System Error Interrupt Status */
179
180
181/* Registers on the Wishbone bus */
182#define SPIH_CTLR_INTR (1 << 0) /* SPI Host Controller Core Interrupt */
183#define SPIH_DEV_INTR (1 << 1) /* SPI Device Interrupt */
184#define SPIH_WFIFO_INTR (1 << 2) /* SPI Tx FIFO Empty Intr (FPGA Rev >= 8) */
185
186/* GPIO Bit definitions */
187#define SPIH_CS (1 << 0) /* SPI Chip Select (active low) */
188#define SPIH_SLOT_POWER (1 << 1) /* SD Card Slot Power Enable */
189#define SPIH_CARD_DETECT (1 << 2) /* SD Card Detect */
190
191/* SPI Status Register Bit definitions */
192#define SPIH_STATE_MASK 0x30 /* SPI Transfer State Machine state mask */
193#define SPIH_STATE_SHIFT 4 /* SPI Transfer State Machine state shift */
194#define SPIH_WFFULL (1 << 3) /* SPI Write FIFO Full */
195#define SPIH_WFEMPTY (1 << 2) /* SPI Write FIFO Empty */
196#define SPIH_RFFULL (1 << 1) /* SPI Read FIFO Full */
197#define SPIH_RFEMPTY (1 << 0) /* SPI Read FIFO Empty */
198
199#define SPIH_EXT_CLK (1U << 31) /* Use External Clock as PLL Clock source. */
200
201#define SPIH_PLL_NO_CLK (1 << 1) /* Set to 1 if the PLL's input clock is lost. */
202#define SPIH_PLL_LOCKED (1 << 3) /* Set to 1 when the PLL is locked. */
203
204/* Spin bit loop bound check */
205#define SPI_SPIN_BOUND 0xf4240 /* 1 million */
diff --git a/drivers/net/wireless/bcm4329/include/bcmperf.h b/drivers/net/wireless/bcm4329/include/bcmperf.h
new file mode 100644
index 00000000000..2a78784e85d
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmperf.h
@@ -0,0 +1,36 @@
1/*
2 * Performance counters software interface.
3 *
4 * Copyright (C) 1999-2010, 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/bcm4329/include/bcmsdbus.h b/drivers/net/wireless/bcm4329/include/bcmsdbus.h
new file mode 100644
index 00000000000..b7b67bc6624
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmsdbus.h
@@ -0,0 +1,117 @@
1/*
2 * Definitions for API from sdio common code (bcmsdh) to individual
3 * host controller drivers.
4 *
5 * Copyright (C) 1999-2010, 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.11.14.2.6.6 2009/10/27 17:20:28 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/* Reset and re-initialize the device */
110extern int sdioh_sdio_reset(sdioh_info_t *si);
111
112/* Helper function */
113void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh);
114
115
116
117#endif /* _sdio_api_h_ */
diff --git a/drivers/net/wireless/bcm4329/include/bcmsdh.h b/drivers/net/wireless/bcm4329/include/bcmsdh.h
new file mode 100644
index 00000000000..caf0b9988aa
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmsdh.h
@@ -0,0 +1,208 @@
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-2010, 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.35.14.7.6.8 2009/10/14 04:22:25 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/* Returns the "Device ID" of target device on the SDIO bus. */
161extern int bcmsdh_query_device(void *sdh);
162
163/* Returns the number of IO functions reported by the device */
164extern uint bcmsdh_query_iofnum(void *sdh);
165
166/* Miscellaneous knob tweaker. */
167extern int bcmsdh_iovar_op(void *sdh, const char *name,
168 void *params, int plen, void *arg, int len, bool set);
169
170/* Reset and reinitialize the device */
171extern int bcmsdh_reset(bcmsdh_info_t *sdh);
172
173/* helper functions */
174
175extern void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh);
176
177/* callback functions */
178typedef struct {
179 /* attach to device */
180 void *(*attach)(uint16 vend_id, uint16 dev_id, uint16 bus, uint16 slot,
181 uint16 func, uint bustype, void * regsva, osl_t * osh,
182 void * param, void *dev);
183 /* detach from device */
184 void (*detach)(void *ch);
185} bcmsdh_driver_t;
186
187/* platform specific/high level functions */
188extern int bcmsdh_register(bcmsdh_driver_t *driver);
189extern void bcmsdh_unregister(void);
190extern bool bcmsdh_chipmatch(uint16 vendor, uint16 device);
191extern void bcmsdh_device_remove(void * sdh);
192
193#if defined(OOB_INTR_ONLY)
194extern int bcmsdh_register_oob_intr(void * dhdp);
195extern void bcmsdh_unregister_oob_intr(void);
196extern void bcmsdh_oob_intr_set(bool enable);
197#endif /* defined(OOB_INTR_ONLY) */
198/* Function to pass device-status bits to DHD. */
199extern uint32 bcmsdh_get_dstatus(void *sdh);
200
201/* Function to return current window addr */
202extern uint32 bcmsdh_cur_sbwad(void *sdh);
203
204/* Function to pass chipid and rev to lower layers for controlling pr's */
205extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev);
206
207
208#endif /* _bcmsdh_h_ */
diff --git a/drivers/net/wireless/bcm4329/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcm4329/include/bcmsdh_sdmmc.h
new file mode 100644
index 00000000000..4e6d1b5bd94
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/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-2010, 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.1.2.1.8.7 2009/10/27 18:22:52 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/bcm4329/include/bcmsdpcm.h b/drivers/net/wireless/bcm4329/include/bcmsdpcm.h
new file mode 100644
index 00000000000..77aca4500ad
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmsdpcm.h
@@ -0,0 +1,263 @@
1/*
2 * Broadcom SDIO/PCMCIA
3 * Software-specific definitions shared between device and host side
4 *
5 * Copyright (C) 1999-2010, 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 1.1.2.4 2010/07/02 01:15:46 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/* tosbmailbox bits corresponding to intstatus bits */
42#define SMB_NAK (1 << 0) /* To SB Mailbox Frame NAK */
43#define SMB_INT_ACK (1 << 1) /* To SB Mailbox Host Interrupt ACK */
44#define SMB_USE_OOB (1 << 2) /* To SB Mailbox Use OOB Wakeup */
45#define SMB_DEV_INT (1 << 3) /* To SB Mailbox Miscellaneous Interrupt */
46#define SMB_MASK 0x0000000f /* To SB Mailbox Mask */
47
48/* tosbmailboxdata */
49#define SMB_DATA_VERSION_MASK 0x00ff0000 /* host protocol version (sent with F2 enable) */
50#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version (sent with F2 enable) */
51
52/*
53 * Software allocation of To Host Mailbox resources
54 */
55
56/* intstatus bits */
57#define I_HMB_FC_STATE I_HMB_SW0 /* To Host Mailbox Flow Control State */
58#define I_HMB_FC_CHANGE I_HMB_SW1 /* To Host Mailbox Flow Control State Changed */
59#define I_HMB_FRAME_IND I_HMB_SW2 /* To Host Mailbox Frame Indication */
60#define I_HMB_HOST_INT I_HMB_SW3 /* To Host Mailbox Miscellaneous Interrupt */
61
62/* tohostmailbox bits corresponding to intstatus bits */
63#define HMB_FC_ON (1 << 0) /* To Host Mailbox Flow Control State */
64#define HMB_FC_CHANGE (1 << 1) /* To Host Mailbox Flow Control State Changed */
65#define HMB_FRAME_IND (1 << 2) /* To Host Mailbox Frame Indication */
66#define HMB_HOST_INT (1 << 3) /* To Host Mailbox Miscellaneous Interrupt */
67#define HMB_MASK 0x0000000f /* To Host Mailbox Mask */
68
69/* tohostmailboxdata */
70#define HMB_DATA_NAKHANDLED 1 /* we're ready to retransmit NAK'd frame to host */
71#define HMB_DATA_DEVREADY 2 /* we're ready to to talk to host after enable */
72#define HMB_DATA_FC 4 /* per prio flowcontrol update flag to host */
73#define HMB_DATA_FWREADY 8 /* firmware is ready for protocol activity */
74
75#define HMB_DATA_FCDATA_MASK 0xff000000 /* per prio flowcontrol data */
76#define HMB_DATA_FCDATA_SHIFT 24 /* per prio flowcontrol data */
77
78#define HMB_DATA_VERSION_MASK 0x00ff0000 /* device protocol version (with devready) */
79#define HMB_DATA_VERSION_SHIFT 16 /* device protocol version (with devready) */
80
81/*
82 * Software-defined protocol header
83 */
84
85/* Current protocol version */
86#define SDPCM_PROT_VERSION 4
87
88/* SW frame header */
89#define SDPCM_SEQUENCE_MASK 0x000000ff /* Sequence Number Mask */
90#define SDPCM_PACKET_SEQUENCE(p) (((uint8 *)p)[0] & 0xff) /* p starts w/SW Header */
91
92#define SDPCM_CHANNEL_MASK 0x00000f00 /* Channel Number Mask */
93#define SDPCM_CHANNEL_SHIFT 8 /* Channel Number Shift */
94#define SDPCM_PACKET_CHANNEL(p) (((uint8 *)p)[1] & 0x0f) /* p starts w/SW Header */
95
96#define SDPCM_FLAGS_MASK 0x0000f000 /* Mask of flag bits */
97#define SDPCM_FLAGS_SHIFT 12 /* Flag bits shift */
98#define SDPCM_PACKET_FLAGS(p) ((((uint8 *)p)[1] & 0xf0) >> 4) /* p starts w/SW Header */
99
100/* Next Read Len: lookahead length of next frame, in 16-byte units (rounded up) */
101#define SDPCM_NEXTLEN_MASK 0x00ff0000 /* Next Read Len Mask */
102#define SDPCM_NEXTLEN_SHIFT 16 /* Next Read Len Shift */
103#define SDPCM_NEXTLEN_VALUE(p) ((((uint8 *)p)[2] & 0xff) << 4) /* p starts w/SW Header */
104#define SDPCM_NEXTLEN_OFFSET 2
105
106/* Data Offset from SOF (HW Tag, SW Tag, Pad) */
107#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */
108#define SDPCM_DOFFSET_VALUE(p) (((uint8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff)
109#define SDPCM_DOFFSET_MASK 0xff000000
110#define SDPCM_DOFFSET_SHIFT 24
111
112#define SDPCM_FCMASK_OFFSET 4 /* Flow control */
113#define SDPCM_FCMASK_VALUE(p) (((uint8 *)p)[SDPCM_FCMASK_OFFSET ] & 0xff)
114#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */
115#define SDPCM_WINDOW_VALUE(p) (((uint8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff)
116#define SDPCM_VERSION_OFFSET 6 /* Version # */
117#define SDPCM_VERSION_VALUE(p) (((uint8 *)p)[SDPCM_VERSION_OFFSET] & 0xff)
118#define SDPCM_UNUSED_OFFSET 7 /* Spare */
119#define SDPCM_UNUSED_VALUE(p) (((uint8 *)p)[SDPCM_UNUSED_OFFSET] & 0xff)
120
121#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */
122
123/* logical channel numbers */
124#define SDPCM_CONTROL_CHANNEL 0 /* Control Request/Response Channel Id */
125#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */
126#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */
127#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets (superframes) */
128#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */
129#define SDPCM_MAX_CHANNEL 15
130
131#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for eight-bit frame seq number */
132
133#define SDPCM_FLAG_RESVD0 0x01
134#define SDPCM_FLAG_RESVD1 0x02
135#define SDPCM_FLAG_GSPI_TXENAB 0x04
136#define SDPCM_FLAG_GLOMDESC 0x08 /* Superframe descriptor mask */
137
138/* For GLOM_CHANNEL frames, use a flag to indicate descriptor frame */
139#define SDPCM_GLOMDESC_FLAG (SDPCM_FLAG_GLOMDESC << SDPCM_FLAGS_SHIFT)
140
141#define SDPCM_GLOMDESC(p) (((uint8 *)p)[1] & 0x80)
142
143/* For TEST_CHANNEL packets, define another 4-byte header */
144#define SDPCM_TEST_HDRLEN 4 /* Generally: Cmd(1), Ext(1), Len(2);
145 * Semantics of Ext byte depend on command.
146 * Len is current or requested frame length, not
147 * including test header; sent little-endian.
148 */
149#define SDPCM_TEST_DISCARD 0x01 /* Receiver discards. Ext is a pattern id. */
150#define SDPCM_TEST_ECHOREQ 0x02 /* Echo request. Ext is a pattern id. */
151#define SDPCM_TEST_ECHORSP 0x03 /* Echo response. Ext is a pattern id. */
152#define SDPCM_TEST_BURST 0x04 /* Receiver to send a burst. Ext is a frame count */
153#define SDPCM_TEST_SEND 0x05 /* Receiver sets send mode. Ext is boolean on/off */
154
155/* Handy macro for filling in datagen packets with a pattern */
156#define SDPCM_TEST_FILL(byteno, id) ((uint8)(id + byteno))
157
158/*
159 * Software counters (first part matches hardware counters)
160 */
161
162typedef volatile struct {
163 uint32 cmd52rd; /* Cmd52RdCount, SDIO: cmd52 reads */
164 uint32 cmd52wr; /* Cmd52WrCount, SDIO: cmd52 writes */
165 uint32 cmd53rd; /* Cmd53RdCount, SDIO: cmd53 reads */
166 uint32 cmd53wr; /* Cmd53WrCount, SDIO: cmd53 writes */
167 uint32 abort; /* AbortCount, SDIO: aborts */
168 uint32 datacrcerror; /* DataCrcErrorCount, SDIO: frames w/CRC error */
169 uint32 rdoutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Rd Frm out of sync */
170 uint32 wroutofsync; /* RdOutOfSyncCount, SDIO/PCMCIA: Wr Frm out of sync */
171 uint32 writebusy; /* WriteBusyCount, SDIO: device asserted "busy" */
172 uint32 readwait; /* ReadWaitCount, SDIO: no data ready for a read cmd */
173 uint32 readterm; /* ReadTermCount, SDIO: read frame termination cmds */
174 uint32 writeterm; /* WriteTermCount, SDIO: write frames termination cmds */
175 uint32 rxdescuflo; /* receive descriptor underflows */
176 uint32 rxfifooflo; /* receive fifo overflows */
177 uint32 txfifouflo; /* transmit fifo underflows */
178 uint32 runt; /* runt (too short) frames recv'd from bus */
179 uint32 badlen; /* frame's rxh len does not match its hw tag len */
180 uint32 badcksum; /* frame's hw tag chksum doesn't agree with len value */
181 uint32 seqbreak; /* break in sequence # space from one rx frame to the next */
182 uint32 rxfcrc; /* frame rx header indicates crc error */
183 uint32 rxfwoos; /* frame rx header indicates write out of sync */
184 uint32 rxfwft; /* frame rx header indicates write frame termination */
185 uint32 rxfabort; /* frame rx header indicates frame aborted */
186 uint32 woosint; /* write out of sync interrupt */
187 uint32 roosint; /* read out of sync interrupt */
188 uint32 rftermint; /* read frame terminate interrupt */
189 uint32 wftermint; /* write frame terminate interrupt */
190} sdpcmd_cnt_t;
191
192/*
193 * Register Access Macros
194 */
195
196#define SDIODREV_IS(var, val) ((var) == (val))
197#define SDIODREV_GE(var, val) ((var) >= (val))
198#define SDIODREV_GT(var, val) ((var) > (val))
199#define SDIODREV_LT(var, val) ((var) < (val))
200#define SDIODREV_LE(var, val) ((var) <= (val))
201
202#define SDIODDMAREG32(h, dir, chnl) \
203 ((dir) == DMA_TX ? \
204 (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].xmt) : \
205 (void *)(uintptr)&((h)->regs->dma.sdiod32.dma32regs[chnl].rcv))
206
207#define SDIODDMAREG64(h, dir, chnl) \
208 ((dir) == DMA_TX ? \
209 (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].xmt) : \
210 (void *)(uintptr)&((h)->regs->dma.sdiod64.dma64regs[chnl].rcv))
211
212#define SDIODDMAREG(h, dir, chnl) \
213 (SDIODREV_LT((h)->corerev, 1) ? \
214 SDIODDMAREG32((h), (dir), (chnl)) : \
215 SDIODDMAREG64((h), (dir), (chnl)))
216
217#define PCMDDMAREG(h, dir, chnl) \
218 ((dir) == DMA_TX ? \
219 (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.xmt) : \
220 (void *)(uintptr)&((h)->regs->dma.pcm32.dmaregs.rcv))
221
222#define SDPCMDMAREG(h, dir, chnl, coreid) \
223 ((coreid) == SDIOD_CORE_ID ? \
224 SDIODDMAREG(h, dir, chnl) : \
225 PCMDDMAREG(h, dir, chnl))
226
227#define SDIODFIFOREG(h, corerev) \
228 (SDIODREV_LT((corerev), 1) ? \
229 ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod32.dmafifo)) : \
230 ((dma32diag_t *)(uintptr)&((h)->regs->dma.sdiod64.dmafifo)))
231
232#define PCMDFIFOREG(h) \
233 ((dma32diag_t *)(uintptr)&((h)->regs->dma.pcm32.dmafifo))
234
235#define SDPCMFIFOREG(h, coreid, corerev) \
236 ((coreid) == SDIOD_CORE_ID ? \
237 SDIODFIFOREG(h, corerev) : \
238 PCMDFIFOREG(h))
239
240/*
241 * Shared structure between dongle and the host
242 * The structure contains pointers to trap or assert information shared with the host
243 */
244#define SDPCM_SHARED_VERSION 0x0002
245#define SDPCM_SHARED_VERSION_MASK 0x00FF
246#define SDPCM_SHARED_ASSERT_BUILT 0x0100
247#define SDPCM_SHARED_ASSERT 0x0200
248#define SDPCM_SHARED_TRAP 0x0400
249
250typedef struct {
251 uint32 flags;
252 uint32 trap_addr;
253 uint32 assert_exp_addr;
254 uint32 assert_file_addr;
255 uint32 assert_line;
256 uint32 console_addr; /* Address of hndrte_cons_t */
257 uint32 msgtrace_addr;
258 uint8 tag[32];
259} sdpcm_shared_t;
260
261extern sdpcm_shared_t sdpcm_shared;
262
263#endif /* _bcmsdpcm_h_ */
diff --git a/drivers/net/wireless/bcm4329/include/bcmsdspi.h b/drivers/net/wireless/bcm4329/include/bcmsdspi.h
new file mode 100644
index 00000000000..eaae10d8bf1
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmsdspi.h
@@ -0,0 +1,131 @@
1/*
2 * SD-SPI Protocol Conversion - BCMSDH->SPI Translation Layer
3 *
4 * Copyright (C) 1999-2010, 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.8.10.2 2008/06/30 21:09:40 Exp $
25 */
26
27/* global msglevel for debug messages - bitvals come from sdiovar.h */
28
29#define sd_err(x)
30#define sd_trace(x)
31#define sd_info(x)
32#define sd_debug(x)
33#define sd_data(x)
34#define sd_ctrl(x)
35
36#define sd_log(x)
37
38#define SDIOH_ASSERT(exp) \
39 do { if (!(exp)) \
40 printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \
41 } while (0)
42
43#define BLOCK_SIZE_4318 64
44#define BLOCK_SIZE_4328 512
45
46/* internal return code */
47#define SUCCESS 0
48#undef ERROR
49#define ERROR 1
50
51/* private bus modes */
52#define SDIOH_MODE_SPI 0
53
54#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */
55#define USE_MULTIBLOCK 0x4
56
57struct sdioh_info {
58 uint cfg_bar; /* pci cfg address for bar */
59 uint32 caps; /* cached value of capabilities reg */
60 uint bar0; /* BAR0 for PCI Device */
61 osl_t *osh; /* osh handler */
62 void *controller; /* Pointer to SPI Controller's private data struct */
63
64 uint lockcount; /* nest count of sdspi_lock() calls */
65 bool client_intr_enabled; /* interrupt connnected flag */
66 bool intr_handler_valid; /* client driver interrupt handler valid */
67 sdioh_cb_fn_t intr_handler; /* registered interrupt handler */
68 void *intr_handler_arg; /* argument to call interrupt handler */
69 bool initialized; /* card initialized */
70 uint32 target_dev; /* Target device ID */
71 uint32 intmask; /* Current active interrupts */
72 void *sdos_info; /* Pointer to per-OS private data */
73
74 uint32 controller_type; /* Host controller type */
75 uint8 version; /* Host Controller Spec Compliance Version */
76 uint irq; /* Client irq */
77 uint32 intrcount; /* Client interrupts */
78 uint32 local_intrcount; /* Controller interrupts */
79 bool host_init_done; /* Controller initted */
80 bool card_init_done; /* Client SDIO interface initted */
81 bool polled_mode; /* polling for command completion */
82
83 bool sd_use_dma; /* DMA on CMD53 */
84 bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */
85 /* Must be on for sd_multiblock to be effective */
86 bool use_client_ints; /* If this is false, make sure to restore */
87 bool got_hcint; /* Host Controller interrupt. */
88 /* polling hack in wl_linux.c:wl_timer() */
89 int adapter_slot; /* Maybe dealing with multiple slots/controllers */
90 int sd_mode; /* SD1/SD4/SPI */
91 int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */
92 uint32 data_xfer_count; /* Current register transfer size */
93 uint32 cmd53_wr_data; /* Used to pass CMD53 write data */
94 uint32 card_response; /* Used to pass back response status byte */
95 uint32 card_rsp_data; /* Used to pass back response data word */
96 uint16 card_rca; /* Current Address */
97 uint8 num_funcs; /* Supported funcs on client */
98 uint32 com_cis_ptr;
99 uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
100 void *dma_buf;
101 ulong dma_phys;
102 int r_cnt; /* rx count */
103 int t_cnt; /* tx_count */
104};
105
106/************************************************************
107 * Internal interfaces: per-port references into bcmsdspi.c
108 */
109
110/* Global message bits */
111extern uint sd_msglevel;
112
113/**************************************************************
114 * Internal interfaces: bcmsdspi.c references to per-port code
115 */
116
117/* Register mapping routines */
118extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size);
119extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size);
120
121/* Interrupt (de)registration routines */
122extern int spi_register_irq(sdioh_info_t *sd, uint irq);
123extern void spi_free_irq(uint irq, sdioh_info_t *sd);
124
125/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */
126extern void spi_lock(sdioh_info_t *sd);
127extern void spi_unlock(sdioh_info_t *sd);
128
129/* Allocate/init/free per-OS private data */
130extern int spi_osinit(sdioh_info_t *sd);
131extern void spi_osfree(sdioh_info_t *sd);
diff --git a/drivers/net/wireless/bcm4329/include/bcmsdstd.h b/drivers/net/wireless/bcm4329/include/bcmsdstd.h
new file mode 100644
index 00000000000..974b3d41698
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmsdstd.h
@@ -0,0 +1,223 @@
1/*
2 * 'Standard' SDIO HOST CONTROLLER driver
3 *
4 * Copyright (C) 1999-2010, 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.16.18.1.16.3 2009/12/10 01:09:23 Exp $
25 */
26
27/* global msglevel for debug messages - bitvals come from sdiovar.h */
28
29#define sd_err(x) do { if (sd_msglevel & SDH_ERROR_VAL) printf x; } while (0)
30#define sd_trace(x)
31#define sd_info(x)
32#define sd_debug(x)
33#define sd_data(x)
34#define sd_ctrl(x)
35#define sd_dma(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/* Allocate/init/free per-OS private data */
42extern int sdstd_osinit(sdioh_info_t *sd);
43extern void sdstd_osfree(sdioh_info_t *sd);
44
45#define sd_log(x)
46
47#define SDIOH_ASSERT(exp) \
48 do { if (!(exp)) \
49 printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \
50 } while (0)
51
52#define BLOCK_SIZE_4318 64
53#define BLOCK_SIZE_4328 512
54
55/* internal return code */
56#define SUCCESS 0
57#define ERROR 1
58
59/* private bus modes */
60#define SDIOH_MODE_SPI 0
61#define SDIOH_MODE_SD1 1
62#define SDIOH_MODE_SD4 2
63
64#define MAX_SLOTS 6 /* For PCI: Only 6 BAR entries => 6 slots */
65#define SDIOH_REG_WINSZ 0x100 /* Number of registers in Standard Host Controller */
66
67#define SDIOH_TYPE_ARASAN_HDK 1
68#define SDIOH_TYPE_BCM27XX 2
69#define SDIOH_TYPE_TI_PCIXX21 4 /* TI PCIxx21 Standard Host Controller */
70#define SDIOH_TYPE_RICOH_R5C822 5 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host Adapter */
71#define SDIOH_TYPE_JMICRON 6 /* JMicron Standard SDIO Host Controller */
72
73/* For linux, allow yielding for dongle */
74#define BCMSDYIELD
75
76/* Expected card status value for CMD7 */
77#define SDIOH_CMD7_EXP_STATUS 0x00001E00
78
79#define RETRIES_LARGE 100000
80#define RETRIES_SMALL 100
81
82
83#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */
84#define USE_MULTIBLOCK 0x4
85
86#define USE_FIFO 0x8 /* Fifo vs non-fifo */
87
88#define CLIENT_INTR 0x100 /* Get rid of this! */
89
90
91struct sdioh_info {
92 uint cfg_bar; /* pci cfg address for bar */
93 uint32 caps; /* cached value of capabilities reg */
94 uint32 curr_caps; /* max current capabilities reg */
95
96 osl_t *osh; /* osh handler */
97 volatile char *mem_space; /* pci device memory va */
98 uint lockcount; /* nest count of sdstd_lock() calls */
99 bool client_intr_enabled; /* interrupt connnected flag */
100 bool intr_handler_valid; /* client driver interrupt handler valid */
101 sdioh_cb_fn_t intr_handler; /* registered interrupt handler */
102 void *intr_handler_arg; /* argument to call interrupt handler */
103 bool initialized; /* card initialized */
104 uint target_dev; /* Target device ID */
105 uint16 intmask; /* Current active interrupts */
106 void *sdos_info; /* Pointer to per-OS private data */
107
108 uint32 controller_type; /* Host controller type */
109 uint8 version; /* Host Controller Spec Compliance Version */
110 uint irq; /* Client irq */
111 int intrcount; /* Client interrupts */
112 int local_intrcount; /* Controller interrupts */
113 bool host_init_done; /* Controller initted */
114 bool card_init_done; /* Client SDIO interface initted */
115 bool polled_mode; /* polling for command completion */
116
117 bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */
118 /* Must be on for sd_multiblock to be effective */
119 bool use_client_ints; /* If this is false, make sure to restore */
120 /* polling hack in wl_linux.c:wl_timer() */
121 int adapter_slot; /* Maybe dealing with multiple slots/controllers */
122 int sd_mode; /* SD1/SD4/SPI */
123 int client_block_size[SDIOD_MAX_IOFUNCS]; /* Blocksize */
124 uint32 data_xfer_count; /* Current transfer */
125 uint16 card_rca; /* Current Address */
126 int8 sd_dma_mode; /* DMA Mode (PIO, SDMA, ... ADMA2) on CMD53 */
127 uint8 num_funcs; /* Supported funcs on client */
128 uint32 com_cis_ptr;
129 uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
130 void *dma_buf; /* DMA Buffer virtual address */
131 ulong dma_phys; /* DMA Buffer physical address */
132 void *adma2_dscr_buf; /* ADMA2 Descriptor Buffer virtual address */
133 ulong adma2_dscr_phys; /* ADMA2 Descriptor Buffer physical address */
134
135 /* adjustments needed to make the dma align properly */
136 void *dma_start_buf;
137 ulong dma_start_phys;
138 uint alloced_dma_size;
139 void *adma2_dscr_start_buf;
140 ulong adma2_dscr_start_phys;
141 uint alloced_adma2_dscr_size;
142
143 int r_cnt; /* rx count */
144 int t_cnt; /* tx_count */
145 bool got_hcint; /* local interrupt flag */
146 uint16 last_intrstatus; /* to cache intrstatus */
147};
148
149#define DMA_MODE_NONE 0
150#define DMA_MODE_SDMA 1
151#define DMA_MODE_ADMA1 2
152#define DMA_MODE_ADMA2 3
153#define DMA_MODE_ADMA2_64 4
154#define DMA_MODE_AUTO -1
155
156#define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE))
157
158/* SDIO Host Control Register DMA Mode Definitions */
159#define SDIOH_SDMA_MODE 0
160#define SDIOH_ADMA1_MODE 1
161#define SDIOH_ADMA2_MODE 2
162#define SDIOH_ADMA2_64_MODE 3
163
164#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */
165#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */
166#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */
167#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */
168#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */
169#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */
170#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */
171#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */
172
173/* ADMA2 Descriptor Table Entry for 32-bit Address */
174typedef struct adma2_dscr_32b {
175 uint32 len_attr;
176 uint32 phys_addr;
177} adma2_dscr_32b_t;
178
179/* ADMA1 Descriptor Table Entry */
180typedef struct adma1_dscr {
181 uint32 phys_addr_attr;
182} adma1_dscr_t;
183
184/************************************************************
185 * Internal interfaces: per-port references into bcmsdstd.c
186 */
187
188/* Global message bits */
189extern uint sd_msglevel;
190
191/* OS-independent interrupt handler */
192extern bool check_client_intr(sdioh_info_t *sd);
193
194/* Core interrupt enable/disable of device interrupts */
195extern void sdstd_devintr_on(sdioh_info_t *sd);
196extern void sdstd_devintr_off(sdioh_info_t *sd);
197
198/* Enable/disable interrupts for local controller events */
199extern void sdstd_intrs_on(sdioh_info_t *sd, uint16 norm, uint16 err);
200extern void sdstd_intrs_off(sdioh_info_t *sd, uint16 norm, uint16 err);
201
202/* Wait for specified interrupt and error bits to be set */
203extern void sdstd_spinbits(sdioh_info_t *sd, uint16 norm, uint16 err);
204
205
206/**************************************************************
207 * Internal interfaces: bcmsdstd.c references to per-port code
208 */
209
210/* Register mapping routines */
211extern uint32 *sdstd_reg_map(osl_t *osh, int32 addr, int size);
212extern void sdstd_reg_unmap(osl_t *osh, int32 addr, int size);
213
214/* Interrupt (de)registration routines */
215extern int sdstd_register_irq(sdioh_info_t *sd, uint irq);
216extern void sdstd_free_irq(uint irq, sdioh_info_t *sd);
217
218/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */
219extern void sdstd_lock(sdioh_info_t *sd);
220extern void sdstd_unlock(sdioh_info_t *sd);
221
222/* OS-specific wait-for-interrupt-or-status */
223extern uint16 sdstd_waitbits(sdioh_info_t *sd, uint16 norm, uint16 err, bool yield);
diff --git a/drivers/net/wireless/bcm4329/include/bcmspi.h b/drivers/net/wireless/bcm4329/include/bcmspi.h
new file mode 100644
index 00000000000..2e2bc935716
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmspi.h
@@ -0,0 +1,36 @@
1/*
2 * Broadcom SPI Low-Level Hardware Driver API
3 *
4 * Copyright (C) 1999-2010, 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.3.10.2 2008/06/30 21:09:40 Exp $
25 */
26
27extern void spi_devintr_off(sdioh_info_t *sd);
28extern void spi_devintr_on(sdioh_info_t *sd);
29extern bool spi_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor);
30extern bool spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode);
31extern bool spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr);
32extern bool spi_hw_attach(sdioh_info_t *sd);
33extern bool spi_hw_detach(sdioh_info_t *sd);
34extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen);
35extern void spi_spinbits(sdioh_info_t *sd);
36extern void spi_waitbits(sdioh_info_t *sd, bool yield);
diff --git a/drivers/net/wireless/bcm4329/include/bcmspibrcm.h b/drivers/net/wireless/bcm4329/include/bcmspibrcm.h
new file mode 100644
index 00000000000..9dce878d11e
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmspibrcm.h
@@ -0,0 +1,134 @@
1/*
2 * SD-SPI Protocol Conversion - BCMSDH->gSPI Translation Layer
3 *
4 * Copyright (C) 2010, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
11 *
12 * $Id: bcmspibrcm.h,v 1.4.4.1.4.3.6.1 2008/09/27 17:03:25 Exp $
13 */
14
15/* global msglevel for debug messages - bitvals come from sdiovar.h */
16
17#define sd_err(x)
18#define sd_trace(x)
19#define sd_info(x)
20#define sd_debug(x)
21#define sd_data(x)
22#define sd_ctrl(x)
23
24#define sd_log(x)
25
26#define SDIOH_ASSERT(exp) \
27 do { if (!(exp)) \
28 printf("!!!ASSERT fail: file %s lines %d", __FILE__, __LINE__); \
29 } while (0)
30
31#define BLOCK_SIZE_F1 64
32#define BLOCK_SIZE_F2 2048
33#define BLOCK_SIZE_F3 2048
34
35/* internal return code */
36#define SUCCESS 0
37#undef ERROR
38#define ERROR 1
39#define ERROR_UF 2
40#define ERROR_OF 3
41
42/* private bus modes */
43#define SDIOH_MODE_SPI 0
44
45#define USE_BLOCKMODE 0x2 /* Block mode can be single block or multi */
46#define USE_MULTIBLOCK 0x4
47
48struct sdioh_info {
49 uint cfg_bar; /* pci cfg address for bar */
50 uint32 caps; /* cached value of capabilities reg */
51 void *bar0; /* BAR0 for PCI Device */
52 osl_t *osh; /* osh handler */
53 void *controller; /* Pointer to SPI Controller's private data struct */
54
55 uint lockcount; /* nest count of spi_lock() calls */
56 bool client_intr_enabled; /* interrupt connnected flag */
57 bool intr_handler_valid; /* client driver interrupt handler valid */
58 sdioh_cb_fn_t intr_handler; /* registered interrupt handler */
59 void *intr_handler_arg; /* argument to call interrupt handler */
60 bool initialized; /* card initialized */
61 uint32 target_dev; /* Target device ID */
62 uint32 intmask; /* Current active interrupts */
63 void *sdos_info; /* Pointer to per-OS private data */
64
65 uint32 controller_type; /* Host controller type */
66 uint8 version; /* Host Controller Spec Compliance Version */
67 uint irq; /* Client irq */
68 uint32 intrcount; /* Client interrupts */
69 uint32 local_intrcount; /* Controller interrupts */
70 bool host_init_done; /* Controller initted */
71 bool card_init_done; /* Client SDIO interface initted */
72 bool polled_mode; /* polling for command completion */
73
74 bool sd_use_dma; /* DMA on CMD53 */
75 bool sd_blockmode; /* sd_blockmode == FALSE => 64 Byte Cmd 53s. */
76 /* Must be on for sd_multiblock to be effective */
77 bool use_client_ints; /* If this is false, make sure to restore */
78 /* polling hack in wl_linux.c:wl_timer() */
79 int adapter_slot; /* Maybe dealing with multiple slots/controllers */
80 int sd_mode; /* SD1/SD4/SPI */
81 int client_block_size[SPI_MAX_IOFUNCS]; /* Blocksize */
82 uint32 data_xfer_count; /* Current transfer */
83 uint16 card_rca; /* Current Address */
84 uint8 num_funcs; /* Supported funcs on client */
85 uint32 card_dstatus; /* 32bit device status */
86 uint32 com_cis_ptr;
87 uint32 func_cis_ptr[SPI_MAX_IOFUNCS];
88 void *dma_buf;
89 ulong dma_phys;
90 int r_cnt; /* rx count */
91 int t_cnt; /* tx_count */
92 uint32 wordlen; /* host processor 16/32bits */
93 uint32 prev_fun;
94 uint32 chip;
95 uint32 chiprev;
96 bool resp_delay_all;
97 bool dwordmode;
98
99 struct spierrstats_t spierrstats;
100};
101
102/************************************************************
103 * Internal interfaces: per-port references into bcmspibrcm.c
104 */
105
106/* Global message bits */
107extern uint sd_msglevel;
108
109/**************************************************************
110 * Internal interfaces: bcmspibrcm.c references to per-port code
111 */
112
113/* Interrupt (de)registration routines */
114extern int spi_register_irq(sdioh_info_t *sd, uint irq);
115extern void spi_free_irq(uint irq, sdioh_info_t *sd);
116
117/* OS-specific interrupt wrappers (atomic interrupt enable/disable) */
118extern void spi_lock(sdioh_info_t *sd);
119extern void spi_unlock(sdioh_info_t *sd);
120
121/* Allocate/init/free per-OS private data */
122extern int spi_osinit(sdioh_info_t *sd);
123extern void spi_osfree(sdioh_info_t *sd);
124
125#define SPI_RW_FLAG_M BITFIELD_MASK(1) /* Bit [31] - R/W Command Bit */
126#define SPI_RW_FLAG_S 31
127#define SPI_ACCESS_M BITFIELD_MASK(1) /* Bit [30] - Fixed/Incr Access */
128#define SPI_ACCESS_S 30
129#define SPI_FUNCTION_M BITFIELD_MASK(2) /* Bit [29:28] - Function Number */
130#define SPI_FUNCTION_S 28
131#define SPI_REG_ADDR_M BITFIELD_MASK(17) /* Bit [27:11] - Address */
132#define SPI_REG_ADDR_S 11
133#define SPI_LEN_M BITFIELD_MASK(11) /* Bit [10:0] - Packet length */
134#define SPI_LEN_S 0
diff --git a/drivers/net/wireless/bcm4329/include/bcmutils.h b/drivers/net/wireless/bcm4329/include/bcmutils.h
new file mode 100644
index 00000000000..f85ed351d66
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmutils.h
@@ -0,0 +1,637 @@
1/*
2 * Misc useful os-independent macros and functions.
3 *
4 * Copyright (C) 1999-2010, 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.h,v 13.184.4.6.2.1.18.25 2010/04/26 06:05:24 Exp $
24 */
25
26
27#ifndef _bcmutils_h_
28#define _bcmutils_h_
29
30#ifdef __cplusplus
31extern "C" {
32#endif
33
34
35#define _BCM_U 0x01
36#define _BCM_L 0x02
37#define _BCM_D 0x04
38#define _BCM_C 0x08
39#define _BCM_P 0x10
40#define _BCM_S 0x20
41#define _BCM_X 0x40
42#define _BCM_SP 0x80
43
44extern const unsigned char bcm_ctype[];
45#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)])
46
47#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0)
48#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0)
49#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0)
50#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0)
51#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0)
52#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0)
53#define bcm_isprint(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0)
54#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0)
55#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0)
56#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0)
57#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0)
58#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
59#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c))
60
61
62
63struct bcmstrbuf {
64 char *buf;
65 unsigned int size;
66 char *origbuf;
67 unsigned int origsize;
68};
69
70
71#ifdef BCMDRIVER
72#include <osl.h>
73
74#define GPIO_PIN_NOTDEFINED 0x20
75
76
77#define SPINWAIT(exp, us) { \
78 uint countdown = (us) + 9; \
79 while ((exp) && (countdown >= 10)) {\
80 OSL_DELAY(10); \
81 countdown -= 10; \
82 } \
83}
84
85
86
87#ifndef PKTQ_LEN_DEFAULT
88#define PKTQ_LEN_DEFAULT 128
89#endif
90#ifndef PKTQ_MAX_PREC
91#define PKTQ_MAX_PREC 16
92#endif
93
94typedef struct pktq_prec {
95 void *head;
96 void *tail;
97 uint16 len;
98 uint16 max;
99} pktq_prec_t;
100
101
102
103struct pktq {
104 uint16 num_prec;
105 uint16 hi_prec;
106 uint16 max;
107 uint16 len;
108
109 struct pktq_prec q[PKTQ_MAX_PREC];
110};
111
112
113struct spktq {
114 uint16 num_prec;
115 uint16 hi_prec;
116 uint16 max;
117 uint16 len;
118
119 struct pktq_prec q[1];
120};
121
122#define PKTQ_PREC_ITER(pq, prec) for (prec = (pq)->num_prec - 1; prec >= 0; prec--)
123
124
125
126
127struct ether_addr;
128
129extern int ether_isbcast(const void *ea);
130extern int ether_isnulladdr(const void *ea);
131
132
133
134#define pktq_psetmax(pq, prec, _max) ((pq)->q[prec].max = (_max))
135#define pktq_plen(pq, prec) ((pq)->q[prec].len)
136#define pktq_pavail(pq, prec) ((pq)->q[prec].max - (pq)->q[prec].len)
137#define pktq_pfull(pq, prec) ((pq)->q[prec].len >= (pq)->q[prec].max)
138#define pktq_pempty(pq, prec) ((pq)->q[prec].len == 0)
139
140#define pktq_ppeek(pq, prec) ((pq)->q[prec].head)
141#define pktq_ppeek_tail(pq, prec) ((pq)->q[prec].tail)
142
143extern void *pktq_penq(struct pktq *pq, int prec, void *p);
144extern void *pktq_penq_head(struct pktq *pq, int prec, void *p);
145extern void *pktq_pdeq(struct pktq *pq, int prec);
146extern void *pktq_pdeq_tail(struct pktq *pq, int prec);
147
148extern bool pktq_pdel(struct pktq *pq, void *p, int prec);
149
150
151extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir);
152
153extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir);
154
155
156
157extern int pktq_mlen(struct pktq *pq, uint prec_bmp);
158extern void *pktq_mdeq(struct pktq *pq, uint prec_bmp, int *prec_out);
159
160
161
162#define pktq_len(pq) ((int)(pq)->len)
163#define pktq_max(pq) ((int)(pq)->max)
164#define pktq_avail(pq) ((int)((pq)->max - (pq)->len))
165#define pktq_full(pq) ((pq)->len >= (pq)->max)
166#define pktq_empty(pq) ((pq)->len == 0)
167
168
169#define pktenq(pq, p) pktq_penq(((struct pktq *)pq), 0, (p))
170#define pktenq_head(pq, p) pktq_penq_head(((struct pktq *)pq), 0, (p))
171#define pktdeq(pq) pktq_pdeq(((struct pktq *)pq), 0)
172#define pktdeq_tail(pq) pktq_pdeq_tail(((struct pktq *)pq), 0)
173#define pktqinit(pq, len) pktq_init(((struct pktq *)pq), 1, len)
174
175extern void pktq_init(struct pktq *pq, int num_prec, int max_len);
176
177extern void *pktq_deq(struct pktq *pq, int *prec_out);
178extern void *pktq_deq_tail(struct pktq *pq, int *prec_out);
179extern void *pktq_peek(struct pktq *pq, int *prec_out);
180extern void *pktq_peek_tail(struct pktq *pq, int *prec_out);
181
182
183
184extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf);
185extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf);
186extern uint pkttotlen(osl_t *osh, void *p);
187extern void *pktlast(osl_t *osh, void *p);
188extern uint pktsegcnt(osl_t *osh, void *p);
189
190
191extern uint pktsetprio(void *pkt, bool update_vtag);
192#define PKTPRIO_VDSCP 0x100
193#define PKTPRIO_VLAN 0x200
194#define PKTPRIO_UPD 0x400
195#define PKTPRIO_DSCP 0x800
196
197
198extern int bcm_atoi(char *s);
199extern ulong bcm_strtoul(char *cp, char **endp, uint base);
200extern char *bcmstrstr(char *haystack, char *needle);
201extern char *bcmstrcat(char *dest, const char *src);
202extern char *bcmstrncat(char *dest, const char *src, uint size);
203extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen);
204char* bcmstrtok(char **string, const char *delimiters, char *tokdelim);
205int bcmstricmp(const char *s1, const char *s2);
206int bcmstrnicmp(const char* s1, const char* s2, int cnt);
207
208
209
210extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf);
211extern int bcm_ether_atoe(char *p, struct ether_addr *ea);
212
213
214struct ipv4_addr;
215extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf);
216
217
218extern void bcm_mdelay(uint ms);
219
220extern char *getvar(char *vars, const char *name);
221extern int getintvar(char *vars, const char *name);
222extern uint getgpiopin(char *vars, char *pin_name, uint def_pin);
223#define bcm_perf_enable()
224#define bcmstats(fmt)
225#define bcmlog(fmt, a1, a2)
226#define bcmdumplog(buf, size) *buf = '\0'
227#define bcmdumplogent(buf, idx) -1
228
229#define bcmtslog(tstamp, fmt, a1, a2)
230#define bcmprinttslogs()
231#define bcmprinttstamp(us)
232
233
234
235
236typedef struct bcm_iovar {
237 const char *name;
238 uint16 varid;
239 uint16 flags;
240 uint16 type;
241 uint16 minlen;
242} bcm_iovar_t;
243
244
245
246
247#define IOV_GET 0
248#define IOV_SET 1
249
250
251#define IOV_GVAL(id) ((id)*2)
252#define IOV_SVAL(id) (((id)*2)+IOV_SET)
253#define IOV_ISSET(actionid) ((actionid & IOV_SET) == IOV_SET)
254
255
256
257extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name);
258extern int bcm_iovar_lencheck(const bcm_iovar_t *table, void *arg, int len, bool set);
259
260#endif
261
262
263#define IOVT_VOID 0
264#define IOVT_BOOL 1
265#define IOVT_INT8 2
266#define IOVT_UINT8 3
267#define IOVT_INT16 4
268#define IOVT_UINT16 5
269#define IOVT_INT32 6
270#define IOVT_UINT32 7
271#define IOVT_BUFFER 8
272#define BCM_IOVT_VALID(type) (((unsigned int)(type)) <= IOVT_BUFFER)
273
274
275#define BCM_IOV_TYPE_INIT { \
276 "void", \
277 "bool", \
278 "int8", \
279 "uint8", \
280 "int16", \
281 "uint16", \
282 "int32", \
283 "uint32", \
284 "buffer", \
285 "" }
286
287#define BCM_IOVT_IS_INT(type) (\
288 (type == IOVT_BOOL) || \
289 (type == IOVT_INT8) || \
290 (type == IOVT_UINT8) || \
291 (type == IOVT_INT16) || \
292 (type == IOVT_UINT16) || \
293 (type == IOVT_INT32) || \
294 (type == IOVT_UINT32))
295
296
297
298#define BCME_STRLEN 64
299#define VALID_BCMERROR(e) ((e <= 0) && (e >= BCME_LAST))
300
301
302
303
304#define BCME_OK 0
305#define BCME_ERROR -1
306#define BCME_BADARG -2
307#define BCME_BADOPTION -3
308#define BCME_NOTUP -4
309#define BCME_NOTDOWN -5
310#define BCME_NOTAP -6
311#define BCME_NOTSTA -7
312#define BCME_BADKEYIDX -8
313#define BCME_RADIOOFF -9
314#define BCME_NOTBANDLOCKED -10
315#define BCME_NOCLK -11
316#define BCME_BADRATESET -12
317#define BCME_BADBAND -13
318#define BCME_BUFTOOSHORT -14
319#define BCME_BUFTOOLONG -15
320#define BCME_BUSY -16
321#define BCME_NOTASSOCIATED -17
322#define BCME_BADSSIDLEN -18
323#define BCME_OUTOFRANGECHAN -19
324#define BCME_BADCHAN -20
325#define BCME_BADADDR -21
326#define BCME_NORESOURCE -22
327#define BCME_UNSUPPORTED -23
328#define BCME_BADLEN -24
329#define BCME_NOTREADY -25
330#define BCME_EPERM -26
331#define BCME_NOMEM -27
332#define BCME_ASSOCIATED -28
333#define BCME_RANGE -29
334#define BCME_NOTFOUND -30
335#define BCME_WME_NOT_ENABLED -31
336#define BCME_TSPEC_NOTFOUND -32
337#define BCME_ACM_NOTSUPPORTED -33
338#define BCME_NOT_WME_ASSOCIATION -34
339#define BCME_SDIO_ERROR -35
340#define BCME_DONGLE_DOWN -36
341#define BCME_VERSION -37
342#define BCME_TXFAIL -38
343#define BCME_RXFAIL -39
344#define BCME_NODEVICE -40
345#define BCME_UNFINISHED -41
346#define BCME_LAST BCME_UNFINISHED
347
348
349#define BCMERRSTRINGTABLE { \
350 "OK", \
351 "Undefined error", \
352 "Bad Argument", \
353 "Bad Option", \
354 "Not up", \
355 "Not down", \
356 "Not AP", \
357 "Not STA", \
358 "Bad Key Index", \
359 "Radio Off", \
360 "Not band locked", \
361 "No clock", \
362 "Bad Rate valueset", \
363 "Bad Band", \
364 "Buffer too short", \
365 "Buffer too long", \
366 "Busy", \
367 "Not Associated", \
368 "Bad SSID len", \
369 "Out of Range Channel", \
370 "Bad Channel", \
371 "Bad Address", \
372 "Not Enough Resources", \
373 "Unsupported", \
374 "Bad length", \
375 "Not Ready", \
376 "Not Permitted", \
377 "No Memory", \
378 "Associated", \
379 "Not In Range", \
380 "Not Found", \
381 "WME Not Enabled", \
382 "TSPEC Not Found", \
383 "ACM Not Supported", \
384 "Not WME Association", \
385 "SDIO Bus Error", \
386 "Dongle Not Accessible", \
387 "Incorrect version", \
388 "TX Failure", \
389 "RX Failure", \
390 "Device Not Present", \
391 "Command not finished", \
392}
393
394#ifndef ABS
395#define ABS(a) (((a) < 0)?-(a):(a))
396#endif
397
398#ifndef MIN
399#define MIN(a, b) (((a) < (b))?(a):(b))
400#endif
401
402#ifndef MAX
403#define MAX(a, b) (((a) > (b))?(a):(b))
404#endif
405
406#define CEIL(x, y) (((x) + ((y)-1)) / (y))
407#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
408#define ISALIGNED(a, x) (((a) & ((x)-1)) == 0)
409#define ALIGN_ADDR(addr, boundary) (void *)(((uintptr)(addr) + (boundary) - 1) \
410 & ~((boundary) - 1))
411#define ISPOWEROF2(x) ((((x)-1)&(x)) == 0)
412#define VALID_MASK(mask) !((mask) & ((mask) + 1))
413#ifndef OFFSETOF
414#define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member)
415#endif
416#ifndef ARRAYSIZE
417#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
418#endif
419
420
421#ifndef setbit
422#ifndef NBBY
423#define NBBY 8
424#endif
425#define setbit(a, i) (((uint8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY))
426#define clrbit(a, i) (((uint8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
427#define isset(a, i) (((const uint8 *)a)[(i)/NBBY] & (1<<((i)%NBBY)))
428#define isclr(a, i) ((((const uint8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
429#endif
430
431#define NBITS(type) (sizeof(type) * 8)
432#define NBITVAL(nbits) (1 << (nbits))
433#define MAXBITVAL(nbits) ((1 << (nbits)) - 1)
434#define NBITMASK(nbits) MAXBITVAL(nbits)
435#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8)
436
437
438#define MUX(pred, true, false) ((pred) ? (true) : (false))
439
440
441#define MODDEC(x, bound) MUX((x) == 0, (bound) - 1, (x) - 1)
442#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1)
443
444
445#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1))
446#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1))
447
448
449#define MODADD(x, y, bound) \
450 MUX((x) + (y) >= (bound), (x) + (y) - (bound), (x) + (y))
451#define MODSUB(x, y, bound) \
452 MUX(((int)(x)) - ((int)(y)) < 0, (x) - (y) + (bound), (x) - (y))
453
454
455#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1))
456#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1))
457
458
459#define CRC8_INIT_VALUE 0xff
460#define CRC8_GOOD_VALUE 0x9f
461#define CRC16_INIT_VALUE 0xffff
462#define CRC16_GOOD_VALUE 0xf0b8
463#define CRC32_INIT_VALUE 0xffffffff
464#define CRC32_GOOD_VALUE 0xdebb20e3
465
466
467typedef struct bcm_bit_desc {
468 uint32 bit;
469 const char* name;
470} bcm_bit_desc_t;
471
472
473typedef struct bcm_tlv {
474 uint8 id;
475 uint8 len;
476 uint8 data[1];
477} bcm_tlv_t;
478
479
480#define bcm_valid_tlv(elt, buflen) ((buflen) >= 2 && (int)(buflen) >= (int)(2 + (elt)->len))
481
482
483#define ETHER_ADDR_STR_LEN 18
484
485
486#ifdef IL_BIGENDIAN
487static INLINE uint32
488load32_ua(uint8 *a)
489{
490 return ((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]);
491}
492
493static INLINE void
494store32_ua(uint8 *a, uint32 v)
495{
496 a[0] = (v >> 24) & 0xff;
497 a[1] = (v >> 16) & 0xff;
498 a[2] = (v >> 8) & 0xff;
499 a[3] = v & 0xff;
500}
501
502static INLINE uint16
503load16_ua(uint8 *a)
504{
505 return ((a[0] << 8) | a[1]);
506}
507
508static INLINE void
509store16_ua(uint8 *a, uint16 v)
510{
511 a[0] = (v >> 8) & 0xff;
512 a[1] = v & 0xff;
513}
514
515#else
516
517static INLINE uint32
518load32_ua(uint8 *a)
519{
520 return ((a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]);
521}
522
523static INLINE void
524store32_ua(uint8 *a, uint32 v)
525{
526 a[3] = (v >> 24) & 0xff;
527 a[2] = (v >> 16) & 0xff;
528 a[1] = (v >> 8) & 0xff;
529 a[0] = v & 0xff;
530}
531
532static INLINE uint16
533load16_ua(uint8 *a)
534{
535 return ((a[1] << 8) | a[0]);
536}
537
538static INLINE void
539store16_ua(uint8 *a, uint16 v)
540{
541 a[1] = (v >> 8) & 0xff;
542 a[0] = v & 0xff;
543}
544
545#endif
546
547
548
549static INLINE void
550xor_128bit_block(const uint8 *src1, const uint8 *src2, uint8 *dst)
551{
552 if (
553#ifdef __i386__
554 1 ||
555#endif
556 (((uintptr)src1 | (uintptr)src2 | (uintptr)dst) & 3) == 0) {
557
558
559 ((uint32 *)dst)[0] = ((uint32 *)src1)[0] ^ ((uint32 *)src2)[0];
560 ((uint32 *)dst)[1] = ((uint32 *)src1)[1] ^ ((uint32 *)src2)[1];
561 ((uint32 *)dst)[2] = ((uint32 *)src1)[2] ^ ((uint32 *)src2)[2];
562 ((uint32 *)dst)[3] = ((uint32 *)src1)[3] ^ ((uint32 *)src2)[3];
563 } else {
564
565 int k;
566 for (k = 0; k < 16; k++)
567 dst[k] = src1[k] ^ src2[k];
568 }
569}
570
571
572
573extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc);
574extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc);
575extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc);
576
577#if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \
578 defined(WLMSG_ASSOC)
579extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len);
580extern int bcm_format_hex(char *str, const void *bytes, int len);
581extern void prhex(const char *msg, uchar *buf, uint len);
582#endif
583extern char *bcm_brev_str(uint32 brev, char *buf);
584extern void printbig(char *buf);
585
586
587extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen);
588extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key);
589extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key);
590
591
592extern const char *bcmerrorstr(int bcmerror);
593
594
595typedef uint32 mbool;
596#define mboolset(mb, bit) ((mb) |= (bit))
597#define mboolclr(mb, bit) ((mb) &= ~(bit))
598#define mboolisset(mb, bit) (((mb) & (bit)) != 0)
599#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val)))
600
601
602extern uint16 bcm_qdbm_to_mw(uint8 qdbm);
603extern uint8 bcm_mw_to_qdbm(uint16 mw);
604
605
606struct fielddesc {
607 const char *nameandfmt;
608 uint32 offset;
609 uint32 len;
610};
611
612extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size);
613extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...);
614extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount);
615extern int bcm_cmp_bytes(uchar *arg1, uchar *arg2, uint8 nbytes);
616extern void bcm_print_bytes(char *name, const uchar *cdata, int len);
617
618typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset);
619extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str,
620 char *buf, uint32 bufsize);
621
622extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len);
623extern uint bcm_bitcount(uint8 *bitmap, uint bytelength);
624
625#if defined(WLTINYDUMP) || defined(WLMSG_INFORM) || defined(WLMSG_ASSOC) || \
626 defined(WLMSG_PRPKT) || defined(WLMSG_WSEC)
627extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len);
628#endif
629
630
631#define SSID_FMT_BUF_LEN ((4 * DOT11_MAX_SSID_LEN) + 1)
632
633#ifdef __cplusplus
634 }
635#endif
636
637#endif
diff --git a/drivers/net/wireless/bcm4329/include/bcmwifi.h b/drivers/net/wireless/bcm4329/include/bcmwifi.h
new file mode 100644
index 00000000000..038aedcdb3c
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/bcmwifi.h
@@ -0,0 +1,154 @@
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-2010, 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.h,v 1.15.30.4 2010/03/10 20:10:52 Exp $
26 */
27
28
29#ifndef _bcmwifi_h_
30#define _bcmwifi_h_
31
32
33
34typedef uint16 chanspec_t;
35
36
37#define CH_UPPER_SB 0x01
38#define CH_LOWER_SB 0x02
39#define CH_EWA_VALID 0x04
40#define CH_20MHZ_APART 4
41#define CH_10MHZ_APART 2
42#define CH_5MHZ_APART 1
43#define CH_MAX_2G_CHANNEL 14
44#define WLC_MAX_2G_CHANNEL CH_MAX_2G_CHANNEL
45#define MAXCHANNEL 224
46
47#define WL_CHANSPEC_CHAN_MASK 0x00ff
48#define WL_CHANSPEC_CHAN_SHIFT 0
49
50#define WL_CHANSPEC_CTL_SB_MASK 0x0300
51#define WL_CHANSPEC_CTL_SB_SHIFT 8
52#define WL_CHANSPEC_CTL_SB_LOWER 0x0100
53#define WL_CHANSPEC_CTL_SB_UPPER 0x0200
54#define WL_CHANSPEC_CTL_SB_NONE 0x0300
55
56#define WL_CHANSPEC_BW_MASK 0x0C00
57#define WL_CHANSPEC_BW_SHIFT 10
58#define WL_CHANSPEC_BW_10 0x0400
59#define WL_CHANSPEC_BW_20 0x0800
60#define WL_CHANSPEC_BW_40 0x0C00
61
62#define WL_CHANSPEC_BAND_MASK 0xf000
63#define WL_CHANSPEC_BAND_SHIFT 12
64#define WL_CHANSPEC_BAND_5G 0x1000
65#define WL_CHANSPEC_BAND_2G 0x2000
66#define INVCHANSPEC 255
67
68
69#define WF_CHAN_FACTOR_2_4_G 4814
70#define WF_CHAN_FACTOR_5_G 10000
71#define WF_CHAN_FACTOR_4_G 8000
72
73
74#define LOWER_20_SB(channel) ((channel > CH_10MHZ_APART) ? (channel - CH_10MHZ_APART) : 0)
75#define UPPER_20_SB(channel) ((channel < (MAXCHANNEL - CH_10MHZ_APART)) ? \
76 (channel + CH_10MHZ_APART) : 0)
77#define CHSPEC_WLCBANDUNIT(chspec) (CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX)
78#define CH20MHZ_CHSPEC(channel) (chanspec_t)((chanspec_t)(channel) | WL_CHANSPEC_BW_20 | \
79 WL_CHANSPEC_CTL_SB_NONE | (((channel) <= CH_MAX_2G_CHANNEL) ? \
80 WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G))
81#define NEXT_20MHZ_CHAN(channel) ((channel < (MAXCHANNEL - CH_20MHZ_APART)) ? \
82 (channel + CH_20MHZ_APART) : 0)
83#define CH40MHZ_CHSPEC(channel, ctlsb) (chanspec_t) \
84 ((channel) | (ctlsb) | WL_CHANSPEC_BW_40 | \
85 ((channel) <= CH_MAX_2G_CHANNEL ? WL_CHANSPEC_BAND_2G : \
86 WL_CHANSPEC_BAND_5G))
87#define CHSPEC_CHANNEL(chspec) ((uint8)(chspec & WL_CHANSPEC_CHAN_MASK))
88#define CHSPEC_BAND(chspec) (chspec & WL_CHANSPEC_BAND_MASK)
89
90#ifdef WL20MHZ_ONLY
91
92#define CHSPEC_CTL_SB(chspec) WL_CHANSPEC_CTL_SB_NONE
93#define CHSPEC_BW(chspec) WL_CHANSPEC_BW_20
94#define CHSPEC_IS10(chspec) 0
95#define CHSPEC_IS20(chspec) 1
96#ifndef CHSPEC_IS40
97#define CHSPEC_IS40(chspec) 0
98#endif
99
100#else
101
102#define CHSPEC_CTL_SB(chspec) (chspec & WL_CHANSPEC_CTL_SB_MASK)
103#define CHSPEC_BW(chspec) (chspec & WL_CHANSPEC_BW_MASK)
104#define CHSPEC_IS10(chspec) ((chspec & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10)
105#define CHSPEC_IS20(chspec) ((chspec & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20)
106#ifndef CHSPEC_IS40
107#define CHSPEC_IS40(chspec) (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40)
108#endif
109
110#endif
111
112#define CHSPEC_IS5G(chspec) ((chspec & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G)
113#define CHSPEC_IS2G(chspec) ((chspec & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G)
114#define CHSPEC_SB_NONE(chspec) ((chspec & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE)
115#define CHSPEC_SB_UPPER(chspec) ((chspec & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER)
116#define CHSPEC_SB_LOWER(chspec) ((chspec & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER)
117#define CHSPEC_CTL_CHAN(chspec) ((CHSPEC_SB_LOWER(chspec)) ? \
118 (LOWER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \
119 (UPPER_20_SB(((chspec) & WL_CHANSPEC_CHAN_MASK))))
120
121#define CHSPEC2WLC_BAND(chspec) (CHSPEC_IS5G((chspec))? WLC_BAND_5G: WLC_BAND_2G)
122
123#define CHANSPEC_STR_LEN 8
124
125
126#define WLC_MAXRATE 108
127#define WLC_RATE_1M 2
128#define WLC_RATE_2M 4
129#define WLC_RATE_5M5 11
130#define WLC_RATE_11M 22
131#define WLC_RATE_6M 12
132#define WLC_RATE_9M 18
133#define WLC_RATE_12M 24
134#define WLC_RATE_18M 36
135#define WLC_RATE_24M 48
136#define WLC_RATE_36M 72
137#define WLC_RATE_48M 96
138#define WLC_RATE_54M 108
139
140#define WLC_2G_25MHZ_OFFSET 5
141
142
143extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf);
144
145
146extern chanspec_t wf_chspec_aton(char *a);
147
148
149extern int wf_mhz2channel(uint freq, uint start_factor);
150
151
152extern int wf_channel2mhz(uint channel, uint start_factor);
153
154#endif
diff --git a/drivers/net/wireless/bcm4329/include/dhdioctl.h b/drivers/net/wireless/bcm4329/include/dhdioctl.h
new file mode 100644
index 00000000000..980a1430100
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/dhdioctl.h
@@ -0,0 +1,123 @@
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-2010, 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.7.8.1.4.1.16.5 2010/05/21 21:49:38 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/* per-driver magic numbers */
54#define DHD_IOCTL_MAGIC 0x00444944
55
56/* bump this number if you change the ioctl interface */
57#define DHD_IOCTL_VERSION 1
58
59#define DHD_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */
60#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */
61
62/* common ioctl definitions */
63#define DHD_GET_MAGIC 0
64#define DHD_GET_VERSION 1
65#define DHD_GET_VAR 2
66#define DHD_SET_VAR 3
67
68/* message levels */
69#define DHD_ERROR_VAL 0x0001
70#define DHD_TRACE_VAL 0x0002
71#define DHD_INFO_VAL 0x0004
72#define DHD_DATA_VAL 0x0008
73#define DHD_CTL_VAL 0x0010
74#define DHD_TIMER_VAL 0x0020
75#define DHD_HDRS_VAL 0x0040
76#define DHD_BYTES_VAL 0x0080
77#define DHD_INTR_VAL 0x0100
78#define DHD_LOG_VAL 0x0200
79#define DHD_GLOM_VAL 0x0400
80#define DHD_EVENT_VAL 0x0800
81#define DHD_BTA_VAL 0x1000
82#define DHD_ISCAN_VAL 0x2000
83
84#ifdef SDTEST
85/* For pktgen iovar */
86typedef struct dhd_pktgen {
87 uint version; /* To allow structure change tracking */
88 uint freq; /* Max ticks between tx/rx attempts */
89 uint count; /* Test packets to send/rcv each attempt */
90 uint print; /* Print counts every <print> attempts */
91 uint total; /* Total packets (or bursts) */
92 uint minlen; /* Minimum length of packets to send */
93 uint maxlen; /* Maximum length of packets to send */
94 uint numsent; /* Count of test packets sent */
95 uint numrcvd; /* Count of test packets received */
96 uint numfail; /* Count of test send failures */
97 uint mode; /* Test mode (type of test packets) */
98 uint stop; /* Stop after this many tx failures */
99} dhd_pktgen_t;
100
101/* Version in case structure changes */
102#define DHD_PKTGEN_VERSION 2
103
104/* Type of test packets to use */
105#define DHD_PKTGEN_ECHO 1 /* Send echo requests */
106#define DHD_PKTGEN_SEND 2 /* Send discard packets */
107#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */
108#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous tx dongle */
109#endif /* SDTEST */
110
111/* Enter idle immediately (no timeout) */
112#define DHD_IDLE_IMMEDIATE (-1)
113
114/* Values for idleclock iovar: other values are the sd_divisor to use when idle */
115#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change when idle */
116#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped (and use SD1 mode) */
117
118
119/* require default structure packing */
120#include <packed_section_end.h>
121
122
123#endif /* _dhdioctl_h_ */
diff --git a/drivers/net/wireless/bcm4329/include/epivers.h b/drivers/net/wireless/bcm4329/include/epivers.h
new file mode 100644
index 00000000000..cd66a9501cb
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/epivers.h
@@ -0,0 +1,48 @@
1/*
2 * Copyright (C) 1999-2010, 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.25 2005/10/28 18:35:33 Exp $
23 *
24*/
25
26
27#ifndef _epivers_h_
28#define _epivers_h_
29
30#define EPI_MAJOR_VERSION 4
31
32#define EPI_MINOR_VERSION 218
33
34#define EPI_RC_NUMBER 248
35
36#define EPI_INCREMENTAL_NUMBER 23
37
38#define EPI_BUILD_NUMBER 0
39
40#define EPI_VERSION 4, 218, 248, 23
41
42#define EPI_VERSION_NUM 0x04daf817
43
44
45#define EPI_VERSION_STR "4.218.248.23"
46#define EPI_ROUTER_VERSION_STR "4.219.248.23"
47
48#endif
diff --git a/drivers/net/wireless/bcm4329/include/hndpmu.h b/drivers/net/wireless/bcm4329/include/hndpmu.h
new file mode 100644
index 00000000000..e829b3df2d0
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/hndpmu.h
@@ -0,0 +1,34 @@
1/*
2 * HND SiliconBackplane PMU support.
3 *
4 * Copyright (C) 1999-2010, 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.14.4.3.4.3.8.7 2010/04/09 13:20:51 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/bcm4329/include/hndrte_armtrap.h b/drivers/net/wireless/bcm4329/include/hndrte_armtrap.h
new file mode 100644
index 00000000000..ca3281b6d90
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/hndrte_armtrap.h
@@ -0,0 +1,88 @@
1/*
2 * HNDRTE arm trap handling.
3 *
4 * Copyright (C) 1999-2010, 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.3.196.2 2010/07/15 19:06:11 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/bcm4329/include/hndrte_cons.h b/drivers/net/wireless/bcm4329/include/hndrte_cons.h
new file mode 100644
index 00000000000..a42417478a1
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/hndrte_cons.h
@@ -0,0 +1,63 @@
1/*
2 * Console support for hndrte.
3 *
4 * Copyright (C) 1999-2010, 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.1.2.4 2010/07/15 19:06:11 Exp $
25 */
26
27#include <typedefs.h>
28
29#define CBUF_LEN (128)
30
31#define LOG_BUF_LEN 1024
32
33typedef struct {
34 uint32 buf; /* Can't be pointer on (64-bit) hosts */
35 uint buf_size;
36 uint idx;
37 char *_buf_compat; /* Redundant pointer for backward compat. */
38} hndrte_log_t;
39
40typedef struct {
41 /* Virtual UART
42 * When there is no UART (e.g. Quickturn), the host should write a complete
43 * input line directly into cbuf and then write the length into vcons_in.
44 * This may also be used when there is a real UART (at risk of conflicting with
45 * the real UART). vcons_out is currently unused.
46 */
47 volatile uint vcons_in;
48 volatile uint vcons_out;
49
50 /* Output (logging) buffer
51 * Console output is written to a ring buffer log_buf at index log_idx.
52 * The host may read the output when it sees log_idx advance.
53 * Output will be lost if the output wraps around faster than the host polls.
54 */
55 hndrte_log_t log;
56
57 /* Console input line buffer
58 * Characters are read one at a time into cbuf until <CR> is received, then
59 * the buffer is processed as a command line. Also used for virtual UART.
60 */
61 uint cbuf_idx;
62 char cbuf[CBUF_LEN];
63} hndrte_cons_t;
diff --git a/drivers/net/wireless/bcm4329/include/hndsoc.h b/drivers/net/wireless/bcm4329/include/hndsoc.h
new file mode 100644
index 00000000000..35424175f55
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/hndsoc.h
@@ -0,0 +1,195 @@
1/*
2 * Broadcom HND chip & on-chip-interconnect-related definitions.
3 *
4 * Copyright (C) 1999-2010, 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.3.10.3 2008/08/06 03:43:25 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
44#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */
45#define SI_CORE_SIZE 0x1000 /* each core gets 4Kbytes for registers */
46#ifndef SI_MAXCORES
47#define SI_MAXCORES 16 /* Max cores (this is arbitrary, for software
48 * convenience and could be changed if we
49 * make any larger chips
50 */
51#endif
52
53#define SI_FASTRAM 0x19000000 /* On-chip RAM on chips that also have DDR */
54
55#define SI_FLASH2 0x1c000000 /* Flash Region 2 (region 1 shadowed here) */
56#define SI_FLASH2_SZ 0x02000000 /* Size of Flash Region 2 */
57#define SI_ARMCM3_ROM 0x1e000000 /* ARM Cortex-M3 ROM */
58#define SI_FLASH1 0x1fc00000 /* MIPS Flash Region 1 */
59#define SI_FLASH1_SZ 0x00400000 /* MIPS Size of Flash Region 1 */
60#define SI_ARM7S_ROM 0x20000000 /* ARM7TDMI-S ROM */
61#define SI_ARMCM3_SRAM2 0x60000000 /* ARM Cortex-M3 SRAM Region 2 */
62#define SI_ARM7S_SRAM2 0x80000000 /* ARM7TDMI-S SRAM Region 2 */
63#define SI_ARM_FLASH1 0xffff0000 /* ARM Flash Region 1 */
64#define SI_ARM_FLASH1_SZ 0x00010000 /* ARM Size of Flash Region 1 */
65
66#define SI_PCI_DMA 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */
67#define SI_PCI_DMA2 0x80000000 /* Client Mode sb2pcitranslation2 (1 GB) */
68#define SI_PCI_DMA_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */
69#define SI_PCIE_DMA_L32 0x00000000 /* PCIE Client Mode sb2pcitranslation2
70 * (2 ZettaBytes), low 32 bits
71 */
72#define SI_PCIE_DMA_H32 0x80000000 /* PCIE Client Mode sb2pcitranslation2
73 * (2 ZettaBytes), high 32 bits
74 */
75
76/* core codes */
77#define NODEV_CORE_ID 0x700 /* Invalid coreid */
78#define CC_CORE_ID 0x800 /* chipcommon core */
79#define ILINE20_CORE_ID 0x801 /* iline20 core */
80#define SRAM_CORE_ID 0x802 /* sram core */
81#define SDRAM_CORE_ID 0x803 /* sdram core */
82#define PCI_CORE_ID 0x804 /* pci core */
83#define MIPS_CORE_ID 0x805 /* mips core */
84#define ENET_CORE_ID 0x806 /* enet mac core */
85#define CODEC_CORE_ID 0x807 /* v90 codec core */
86#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */
87#define ADSL_CORE_ID 0x809 /* ADSL core */
88#define ILINE100_CORE_ID 0x80a /* iline100 core */
89#define IPSEC_CORE_ID 0x80b /* ipsec core */
90#define UTOPIA_CORE_ID 0x80c /* utopia core */
91#define PCMCIA_CORE_ID 0x80d /* pcmcia core */
92#define SOCRAM_CORE_ID 0x80e /* internal memory core */
93#define MEMC_CORE_ID 0x80f /* memc sdram core */
94#define OFDM_CORE_ID 0x810 /* OFDM phy core */
95#define EXTIF_CORE_ID 0x811 /* external interface core */
96#define D11_CORE_ID 0x812 /* 802.11 MAC core */
97#define APHY_CORE_ID 0x813 /* 802.11a phy core */
98#define BPHY_CORE_ID 0x814 /* 802.11b phy core */
99#define GPHY_CORE_ID 0x815 /* 802.11g phy core */
100#define MIPS33_CORE_ID 0x816 /* mips3302 core */
101#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */
102#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */
103#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */
104#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */
105#define SDIOH_CORE_ID 0x81b /* sdio host core */
106#define ROBO_CORE_ID 0x81c /* roboswitch core */
107#define ATA100_CORE_ID 0x81d /* parallel ATA core */
108#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */
109#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */
110#define PCIE_CORE_ID 0x820 /* pci express core */
111#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */
112#define SRAMC_CORE_ID 0x822 /* SRAM controller core */
113#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */
114#define ARM11_CORE_ID 0x824 /* ARM 1176 core */
115#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */
116#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */
117#define PMU_CORE_ID 0x827 /* PMU core */
118#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */
119#define SDIOD_CORE_ID 0x829 /* SDIO device core */
120#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */
121#define QNPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */
122#define MIPS74K_CORE_ID 0x82c /* mips 74k core */
123#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */
124#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */
125#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */
126#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */
127#define SC_CORE_ID 0x831 /* shared common core */
128#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */
129#define SPIH_CORE_ID 0x833 /* SPI host core */
130#define I2S_CORE_ID 0x834 /* I2S core */
131#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */
132#define DEF_AI_COMP 0xfff /* Default component, in ai chips it maps all
133 * unused address ranges
134 */
135
136/* There are TWO constants on all HND chips: SI_ENUM_BASE above,
137 * and chipcommon being the first core:
138 */
139#define SI_CC_IDX 0
140
141/* SOC Interconnect types (aka chip types) */
142#define SOCI_SB 0
143#define SOCI_AI 1
144
145/* Common core control flags */
146#define SICF_BIST_EN 0x8000
147#define SICF_PME_EN 0x4000
148#define SICF_CORE_BITS 0x3ffc
149#define SICF_FGC 0x0002
150#define SICF_CLOCK_EN 0x0001
151
152/* Common core status flags */
153#define SISF_BIST_DONE 0x8000
154#define SISF_BIST_ERROR 0x4000
155#define SISF_GATED_CLK 0x2000
156#define SISF_DMA64 0x1000
157#define SISF_CORE_BITS 0x0fff
158
159/* A register that is common to all cores to
160 * communicate w/PMU regarding clock control.
161 */
162#define SI_CLK_CTL_ST 0x1e0 /* clock control and status */
163
164/* clk_ctl_st register */
165#define CCS_FORCEALP 0x00000001 /* force ALP request */
166#define CCS_FORCEHT 0x00000002 /* force HT request */
167#define CCS_FORCEILP 0x00000004 /* force ILP request */
168#define CCS_ALPAREQ 0x00000008 /* ALP Avail Request */
169#define CCS_HTAREQ 0x00000010 /* HT Avail Request */
170#define CCS_FORCEHWREQOFF 0x00000020 /* Force HW Clock Request Off */
171#define CCS_ALPAVAIL 0x00010000 /* ALP is available */
172#define CCS_HTAVAIL 0x00020000 /* HT is available */
173#define CCS0_HTAVAIL 0x00010000 /* HT avail in chipc and pcmcia on 4328a0 */
174#define CCS0_ALPAVAIL 0x00020000 /* ALP avail in chipc and pcmcia on 4328a0 */
175
176/* Not really related to SOC Interconnect, but a couple of software
177 * conventions for the use the flash space:
178 */
179
180/* Minumum amount of flash we support */
181#define FLASH_MIN 0x00020000 /* Minimum flash size */
182
183/* A boot/binary may have an embedded block that describes its size */
184#define BISZ_OFFSET 0x3e0 /* At this offset into the binary */
185#define BISZ_MAGIC 0x4249535a /* Marked with this value: 'BISZ' */
186#define BISZ_MAGIC_IDX 0 /* Word 0: magic */
187#define BISZ_TXTST_IDX 1 /* 1: text start */
188#define BISZ_TXTEND_IDX 2 /* 2: text end */
189#define BISZ_DATAST_IDX 3 /* 3: data start */
190#define BISZ_DATAEND_IDX 4 /* 4: data end */
191#define BISZ_BSSST_IDX 5 /* 5: bss start */
192#define BISZ_BSSEND_IDX 6 /* 6: bss end */
193#define BISZ_SIZE 7 /* descriptor size in 32-bit intergers */
194
195#endif /* _HNDSOC_H */
diff --git a/drivers/net/wireless/bcm4329/include/linux_osl.h b/drivers/net/wireless/bcm4329/include/linux_osl.h
new file mode 100644
index 00000000000..b059c2adb17
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/linux_osl.h
@@ -0,0 +1,322 @@
1/*
2 * Linux OS Independent Layer
3 *
4 * Copyright (C) 1999-2010, 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.131.30.8 2010/04/26 05:42:18 Exp $
25 */
26
27
28#ifndef _linux_osl_h_
29#define _linux_osl_h_
30
31#include <typedefs.h>
32
33
34#include <linuxver.h>
35
36
37#ifdef __GNUC__
38#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
39#if GCC_VERSION > 30100
40#define ASSERT(exp) do {} while (0)
41#else
42
43#define ASSERT(exp)
44#endif
45#endif
46
47
48#define OSL_DELAY(usec) osl_delay(usec)
49extern void osl_delay(uint usec);
50
51
52
53#define OSL_PCMCIA_READ_ATTR(osh, offset, buf, size) \
54 osl_pcmcia_read_attr((osh), (offset), (buf), (size))
55#define OSL_PCMCIA_WRITE_ATTR(osh, offset, buf, size) \
56 osl_pcmcia_write_attr((osh), (offset), (buf), (size))
57extern void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size);
58extern void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size);
59
60
61#define OSL_PCI_READ_CONFIG(osh, offset, size) \
62 osl_pci_read_config((osh), (offset), (size))
63#define OSL_PCI_WRITE_CONFIG(osh, offset, size, val) \
64 osl_pci_write_config((osh), (offset), (size), (val))
65extern uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size);
66extern void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val);
67
68
69#define OSL_PCI_BUS(osh) osl_pci_bus(osh)
70#define OSL_PCI_SLOT(osh) osl_pci_slot(osh)
71extern uint osl_pci_bus(osl_t *osh);
72extern uint osl_pci_slot(osl_t *osh);
73
74
75typedef struct {
76 bool pkttag;
77 uint pktalloced;
78 bool mmbus;
79 pktfree_cb_fn_t tx_fn;
80 void *tx_ctx;
81} osl_pubinfo_t;
82
83
84extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag);
85extern void osl_detach(osl_t *osh);
86
87#define PKTFREESETCB(osh, _tx_fn, _tx_ctx) \
88 do { \
89 ((osl_pubinfo_t*)osh)->tx_fn = _tx_fn; \
90 ((osl_pubinfo_t*)osh)->tx_ctx = _tx_ctx; \
91 } while (0)
92
93
94#define BUS_SWAP32(v) (v)
95
96
97#define MALLOC(osh, size) osl_malloc((osh), (size))
98#define MFREE(osh, addr, size) osl_mfree((osh), (addr), (size))
99#define MALLOCED(osh) osl_malloced((osh))
100
101
102#define MALLOC_FAILED(osh) osl_malloc_failed((osh))
103
104extern void *osl_malloc(osl_t *osh, uint size);
105extern void osl_mfree(osl_t *osh, void *addr, uint size);
106extern uint osl_malloced(osl_t *osh);
107extern uint osl_malloc_failed(osl_t *osh);
108
109
110#define DMA_CONSISTENT_ALIGN PAGE_SIZE
111#define DMA_ALLOC_CONSISTENT(osh, size, pap, dmah, alignbits) \
112 osl_dma_alloc_consistent((osh), (size), (pap))
113#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \
114 osl_dma_free_consistent((osh), (void*)(va), (size), (pa))
115extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap);
116extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa);
117
118
119#define DMA_TX 1
120#define DMA_RX 2
121
122
123#define DMA_MAP(osh, va, size, direction, p, dmah) \
124 osl_dma_map((osh), (va), (size), (direction))
125#define DMA_UNMAP(osh, pa, size, direction, p, dmah) \
126 osl_dma_unmap((osh), (pa), (size), (direction))
127extern uint osl_dma_map(osl_t *osh, void *va, uint size, int direction);
128extern void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction);
129
130
131#define OSL_DMADDRWIDTH(osh, addrwidth) do {} while (0)
132
133
134#include <bcmsdh.h>
135#define OSL_WRITE_REG(osh, r, v) (bcmsdh_reg_write(NULL, (uintptr)(r), sizeof(*(r)), (v)))
136#define OSL_READ_REG(osh, r) (bcmsdh_reg_read(NULL, (uintptr)(r), sizeof(*(r))))
137
138#define SELECT_BUS_WRITE(osh, mmap_op, bus_op) if (((osl_pubinfo_t*)(osh))->mmbus) \
139 mmap_op else bus_op
140#define SELECT_BUS_READ(osh, mmap_op, bus_op) (((osl_pubinfo_t*)(osh))->mmbus) ? \
141 mmap_op : bus_op
142
143
144
145
146#ifndef printf
147#define printf(fmt, args...) printk(fmt, ## args)
148#endif
149#include <linux/kernel.h>
150#include <linux/string.h>
151
152
153#ifndef IL_BIGENDIAN
154#define R_REG(osh, r) (\
155 SELECT_BUS_READ(osh, sizeof(*(r)) == sizeof(uint8) ? readb((volatile uint8*)(r)) : \
156 sizeof(*(r)) == sizeof(uint16) ? readw((volatile uint16*)(r)) : \
157 readl((volatile uint32*)(r)), OSL_READ_REG(osh, r)) \
158)
159#define W_REG(osh, r, v) do { \
160 SELECT_BUS_WRITE(osh, \
161 switch (sizeof(*(r))) { \
162 case sizeof(uint8): writeb((uint8)(v), (volatile uint8*)(r)); break; \
163 case sizeof(uint16): writew((uint16)(v), (volatile uint16*)(r)); break; \
164 case sizeof(uint32): writel((uint32)(v), (volatile uint32*)(r)); break; \
165 }, \
166 (OSL_WRITE_REG(osh, r, v))); \
167 } while (0)
168#else
169#define R_REG(osh, r) (\
170 SELECT_BUS_READ(osh, \
171 ({ \
172 __typeof(*(r)) __osl_v; \
173 switch (sizeof(*(r))) { \
174 case sizeof(uint8): __osl_v = \
175 readb((volatile uint8*)((uintptr)(r)^3)); break; \
176 case sizeof(uint16): __osl_v = \
177 readw((volatile uint16*)((uintptr)(r)^2)); break; \
178 case sizeof(uint32): __osl_v = \
179 readl((volatile uint32*)(r)); break; \
180 } \
181 __osl_v; \
182 }), \
183 OSL_READ_REG(osh, r)) \
184)
185#define W_REG(osh, r, v) do { \
186 SELECT_BUS_WRITE(osh, \
187 switch (sizeof(*(r))) { \
188 case sizeof(uint8): writeb((uint8)(v), \
189 (volatile uint8*)((uintptr)(r)^3)); break; \
190 case sizeof(uint16): writew((uint16)(v), \
191 (volatile uint16*)((uintptr)(r)^2)); break; \
192 case sizeof(uint32): writel((uint32)(v), \
193 (volatile uint32*)(r)); break; \
194 }, \
195 (OSL_WRITE_REG(osh, r, v))); \
196 } while (0)
197#endif
198
199#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v))
200#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v))
201
202
203#define bcopy(src, dst, len) memcpy((dst), (src), (len))
204#define bcmp(b1, b2, len) memcmp((b1), (b2), (len))
205#define bzero(b, len) memset((b), '\0', (len))
206
207
208#define OSL_UNCACHED(va) ((void*)va)
209
210
211#if defined(__i386__)
212#define OSL_GETCYCLES(x) rdtscl((x))
213#else
214#define OSL_GETCYCLES(x) ((x) = 0)
215#endif
216
217
218#define BUSPROBE(val, addr) ({ (val) = R_REG(NULL, (addr)); 0; })
219
220
221#if !defined(CONFIG_MMC_MSM7X00A)
222#define REG_MAP(pa, size) ioremap_nocache((unsigned long)(pa), (unsigned long)(size))
223#else
224#define REG_MAP(pa, size) (void *)(0)
225#endif
226#define REG_UNMAP(va) iounmap((va))
227
228
229#define R_SM(r) *(r)
230#define W_SM(r, v) (*(r) = (v))
231#define BZERO_SM(r, len) memset((r), '\0', (len))
232
233
234#define PKTGET(osh, len, send) osl_pktget((osh), (len))
235#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send))
236#ifdef DHD_USE_STATIC_BUF
237#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len))
238#define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send))
239#endif
240#define PKTDATA(osh, skb) (((struct sk_buff*)(skb))->data)
241#define PKTLEN(osh, skb) (((struct sk_buff*)(skb))->len)
242#define PKTHEADROOM(osh, skb) (PKTDATA(osh, skb)-(((struct sk_buff*)(skb))->head))
243#define PKTTAILROOM(osh, skb) ((((struct sk_buff*)(skb))->end)-(((struct sk_buff*)(skb))->tail))
244#define PKTNEXT(osh, skb) (((struct sk_buff*)(skb))->next)
245#define PKTSETNEXT(osh, skb, x) (((struct sk_buff*)(skb))->next = (struct sk_buff*)(x))
246#define PKTSETLEN(osh, skb, len) __skb_trim((struct sk_buff*)(skb), (len))
247#define PKTPUSH(osh, skb, bytes) skb_push((struct sk_buff*)(skb), (bytes))
248#define PKTPULL(osh, skb, bytes) skb_pull((struct sk_buff*)(skb), (bytes))
249#define PKTDUP(osh, skb) osl_pktdup((osh), (skb))
250#define PKTTAG(skb) ((void*)(((struct sk_buff*)(skb))->cb))
251#define PKTALLOCED(osh) ((osl_pubinfo_t *)(osh))->pktalloced
252#define PKTSETPOOL(osh, skb, x, y) do {} while (0)
253#define PKTPOOL(osh, skb) FALSE
254#define PKTPOOLLEN(osh, pktp) (0)
255#define PKTPOOLAVAIL(osh, pktp) (0)
256#define PKTPOOLADD(osh, pktp, p) BCME_ERROR
257#define PKTPOOLGET(osh, pktp) NULL
258#define PKTLIST_DUMP(osh, buf)
259
260extern void *osl_pktget(osl_t *osh, uint len);
261extern void osl_pktfree(osl_t *osh, void *skb, bool send);
262extern void *osl_pktget_static(osl_t *osh, uint len);
263extern void osl_pktfree_static(osl_t *osh, void *skb, bool send);
264extern void *osl_pktdup(osl_t *osh, void *skb);
265
266
267
268static INLINE void *
269osl_pkt_frmnative(osl_pubinfo_t *osh, struct sk_buff *skb)
270{
271 struct sk_buff *nskb;
272
273 if (osh->pkttag)
274 bzero((void*)skb->cb, OSL_PKTTAG_SZ);
275
276
277 for (nskb = skb; nskb; nskb = nskb->next) {
278 osh->pktalloced++;
279 }
280
281 return (void *)skb;
282}
283#define PKTFRMNATIVE(osh, skb) osl_pkt_frmnative(((osl_pubinfo_t *)osh), (struct sk_buff*)(skb))
284
285
286static INLINE struct sk_buff *
287osl_pkt_tonative(osl_pubinfo_t *osh, void *pkt)
288{
289 struct sk_buff *nskb;
290
291 if (osh->pkttag)
292 bzero(((struct sk_buff*)pkt)->cb, OSL_PKTTAG_SZ);
293
294
295 for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next) {
296 osh->pktalloced--;
297 }
298
299 return (struct sk_buff *)pkt;
300}
301#define PKTTONATIVE(osh, pkt) osl_pkt_tonative((osl_pubinfo_t *)(osh), (pkt))
302
303#define PKTLINK(skb) (((struct sk_buff*)(skb))->prev)
304#define PKTSETLINK(skb, x) (((struct sk_buff*)(skb))->prev = (struct sk_buff*)(x))
305#define PKTPRIO(skb) (((struct sk_buff*)(skb))->priority)
306#define PKTSETPRIO(skb, x) (((struct sk_buff*)(skb))->priority = (x))
307#define PKTSUMNEEDED(skb) (((struct sk_buff*)(skb))->ip_summed == CHECKSUM_HW)
308#define PKTSETSUMGOOD(skb, x) (((struct sk_buff*)(skb))->ip_summed = \
309 ((x) ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE))
310
311#define PKTSHARED(skb) (((struct sk_buff*)(skb))->cloned)
312
313
314#define OSL_ERROR(bcmerror) osl_error(bcmerror)
315extern int osl_error(int bcmerror);
316
317
318#define PKTBUFSZ 2048
319
320
321#define OSL_SYSUPTIME() ((uint32)jiffies * (1000 / HZ))
322#endif
diff --git a/drivers/net/wireless/bcm4329/include/linuxver.h b/drivers/net/wireless/bcm4329/include/linuxver.h
new file mode 100644
index 00000000000..6ed22658a72
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/linuxver.h
@@ -0,0 +1,447 @@
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-2010, 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.38.8.1.8.6 2010/04/29 05:00:46 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#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33))
36#include <linux/autoconf.h>
37#endif
38#include <linux/module.h>
39
40#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0))
41
42#ifdef __UNDEF_NO_VERSION__
43#undef __NO_VERSION__
44#else
45#define __NO_VERSION__
46#endif
47#endif
48
49#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
50#define module_param(_name_, _type_, _perm_) MODULE_PARM(_name_, "i")
51#define module_param_string(_name_, _string_, _size_, _perm_) \
52 MODULE_PARM(_string_, "c" __MODULE_STRING(_size_))
53#endif
54
55
56#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9))
57#include <linux/malloc.h>
58#else
59#include <linux/slab.h>
60#endif
61
62#include <linux/types.h>
63#include <linux/init.h>
64#include <linux/mm.h>
65#include <linux/string.h>
66#include <linux/pci.h>
67#include <linux/interrupt.h>
68#include <linux/netdevice.h>
69#include <linux/semaphore.h>
70#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
71#undef IP_TOS
72#endif
73#include <asm/io.h>
74
75#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 41))
76#include <linux/workqueue.h>
77#else
78#include <linux/tqueue.h>
79#ifndef work_struct
80#define work_struct tq_struct
81#endif
82#ifndef INIT_WORK
83#define INIT_WORK(_work, _func, _data) INIT_TQUEUE((_work), (_func), (_data))
84#endif
85#ifndef schedule_work
86#define schedule_work(_work) schedule_task((_work))
87#endif
88#ifndef flush_scheduled_work
89#define flush_scheduled_work() flush_scheduled_tasks()
90#endif
91#endif
92
93#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
94#define MY_INIT_WORK(_work, _func, _data) INIT_WORK(_work, _func)
95#else
96#define MY_INIT_WORK(_work, _func, _data) INIT_WORK(_work, _func, _data)
97typedef void (*work_func_t)(void *work);
98#endif
99
100#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
101
102#ifndef IRQ_NONE
103typedef void irqreturn_t;
104#define IRQ_NONE
105#define IRQ_HANDLED
106#define IRQ_RETVAL(x)
107#endif
108#else
109typedef irqreturn_t(*FN_ISR) (int irq, void *dev_id, struct pt_regs *ptregs);
110#endif
111
112#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
113#define IRQF_SHARED SA_SHIRQ
114#endif
115
116#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 17)
117#ifdef CONFIG_NET_RADIO
118#define CONFIG_WIRELESS_EXT
119#endif
120#endif
121
122#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 67)
123#ifndef SANDGATE2G
124#define MOD_INC_USE_COUNT
125#endif
126#endif
127
128
129#ifndef __exit
130#define __exit
131#endif
132#ifndef __devexit
133#define __devexit
134#endif
135#ifndef __devinit
136#define __devinit __init
137#endif
138#ifndef __devinitdata
139#define __devinitdata
140#endif
141#ifndef __devexit_p
142#define __devexit_p(x) x
143#endif
144
145#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0))
146
147#define pci_get_drvdata(dev) (dev)->sysdata
148#define pci_set_drvdata(dev, value) (dev)->sysdata = (value)
149
150
151
152struct pci_device_id {
153 unsigned int vendor, device;
154 unsigned int subvendor, subdevice;
155 unsigned int class, class_mask;
156 unsigned long driver_data;
157};
158
159struct pci_driver {
160 struct list_head node;
161 char *name;
162 const struct pci_device_id *id_table;
163 int (*probe)(struct pci_dev *dev,
164 const struct pci_device_id *id);
165 void (*remove)(struct pci_dev *dev);
166 void (*suspend)(struct pci_dev *dev);
167 void (*resume)(struct pci_dev *dev);
168};
169
170#define MODULE_DEVICE_TABLE(type, name)
171#define PCI_ANY_ID (~0)
172
173
174#define pci_module_init pci_register_driver
175extern int pci_register_driver(struct pci_driver *drv);
176extern void pci_unregister_driver(struct pci_driver *drv);
177
178#endif
179
180#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18))
181#define pci_module_init pci_register_driver
182#endif
183
184#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 2, 18))
185#ifdef MODULE
186#define module_init(x) int init_module(void) { return x(); }
187#define module_exit(x) void cleanup_module(void) { x(); }
188#else
189#define module_init(x) __initcall(x);
190#define module_exit(x) __exitcall(x);
191#endif
192#endif
193
194#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 48))
195#define list_for_each(pos, head) \
196 for (pos = (head)->next; pos != (head); pos = pos->next)
197#endif
198
199#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 13))
200#define pci_resource_start(dev, bar) ((dev)->base_address[(bar)])
201#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 44))
202#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)
203#endif
204
205#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 23))
206#define pci_enable_device(dev) do { } while (0)
207#endif
208
209#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 14))
210#define net_device device
211#endif
212
213#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 42))
214
215
216
217#ifndef PCI_DMA_TODEVICE
218#define PCI_DMA_TODEVICE 1
219#define PCI_DMA_FROMDEVICE 2
220#endif
221
222typedef u32 dma_addr_t;
223
224
225static inline int get_order(unsigned long size)
226{
227 int order;
228
229 size = (size-1) >> (PAGE_SHIFT-1);
230 order = -1;
231 do {
232 size >>= 1;
233 order++;
234 } while (size);
235 return order;
236}
237
238static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
239 dma_addr_t *dma_handle)
240{
241 void *ret;
242 int gfp = GFP_ATOMIC | GFP_DMA;
243
244 ret = (void *)__get_free_pages(gfp, get_order(size));
245
246 if (ret != NULL) {
247 memset(ret, 0, size);
248 *dma_handle = virt_to_bus(ret);
249 }
250 return ret;
251}
252static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size,
253 void *vaddr, dma_addr_t dma_handle)
254{
255 free_pages((unsigned long)vaddr, get_order(size));
256}
257#define pci_map_single(cookie, address, size, dir) virt_to_bus(address)
258#define pci_unmap_single(cookie, address, size, dir)
259
260#endif
261
262#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 43))
263
264#define dev_kfree_skb_any(a) dev_kfree_skb(a)
265#define netif_down(dev) do { (dev)->start = 0; } while (0)
266
267
268#ifndef _COMPAT_NETDEVICE_H
269
270
271
272#define dev_kfree_skb_irq(a) dev_kfree_skb(a)
273#define netif_wake_queue(dev) \
274 do { clear_bit(0, &(dev)->tbusy); mark_bh(NET_BH); } while (0)
275#define netif_stop_queue(dev) set_bit(0, &(dev)->tbusy)
276
277static inline void netif_start_queue(struct net_device *dev)
278{
279 dev->tbusy = 0;
280 dev->interrupt = 0;
281 dev->start = 1;
282}
283
284#define netif_queue_stopped(dev) (dev)->tbusy
285#define netif_running(dev) (dev)->start
286
287#endif
288
289#define netif_device_attach(dev) netif_start_queue(dev)
290#define netif_device_detach(dev) netif_stop_queue(dev)
291
292
293#define tasklet_struct tq_struct
294static inline void tasklet_schedule(struct tasklet_struct *tasklet)
295{
296 queue_task(tasklet, &tq_immediate);
297 mark_bh(IMMEDIATE_BH);
298}
299
300static inline void tasklet_init(struct tasklet_struct *tasklet,
301 void (*func)(unsigned long),
302 unsigned long data)
303{
304 tasklet->next = NULL;
305 tasklet->sync = 0;
306 tasklet->routine = (void (*)(void *))func;
307 tasklet->data = (void *)data;
308}
309#define tasklet_kill(tasklet) { do {} while (0); }
310
311
312#define del_timer_sync(timer) del_timer(timer)
313
314#else
315
316#define netif_down(dev)
317
318#endif
319
320#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 3))
321
322
323#define PREPARE_TQUEUE(_tq, _routine, _data) \
324 do { \
325 (_tq)->routine = _routine; \
326 (_tq)->data = _data; \
327 } while (0)
328
329
330#define INIT_TQUEUE(_tq, _routine, _data) \
331 do { \
332 INIT_LIST_HEAD(&(_tq)->list); \
333 (_tq)->sync = 0; \
334 PREPARE_TQUEUE((_tq), (_routine), (_data)); \
335 } while (0)
336
337#endif
338
339#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 6))
340
341
342
343static inline int
344pci_save_state(struct pci_dev *dev, u32 *buffer)
345{
346 int i;
347 if (buffer) {
348 for (i = 0; i < 16; i++)
349 pci_read_config_dword(dev, i * 4, &buffer[i]);
350 }
351 return 0;
352}
353
354static inline int
355pci_restore_state(struct pci_dev *dev, u32 *buffer)
356{
357 int i;
358
359 if (buffer) {
360 for (i = 0; i < 16; i++)
361 pci_write_config_dword(dev, i * 4, buffer[i]);
362 }
363
364 else {
365 for (i = 0; i < 6; i ++)
366 pci_write_config_dword(dev,
367 PCI_BASE_ADDRESS_0 + (i * 4),
368 pci_resource_start(dev, i));
369 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
370 }
371 return 0;
372}
373
374#endif
375
376
377#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 19))
378#define read_c0_count() read_32bit_cp0_register(CP0_COUNT)
379#endif
380
381
382#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24))
383#ifndef SET_MODULE_OWNER
384#define SET_MODULE_OWNER(dev) do {} while (0)
385#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
386#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
387#else
388#define OLD_MOD_INC_USE_COUNT do {} while (0)
389#define OLD_MOD_DEC_USE_COUNT do {} while (0)
390#endif
391#else
392#ifndef SET_MODULE_OWNER
393#define SET_MODULE_OWNER(dev) do {} while (0)
394#endif
395#ifndef MOD_INC_USE_COUNT
396#define MOD_INC_USE_COUNT do {} while (0)
397#endif
398#ifndef MOD_DEC_USE_COUNT
399#define MOD_DEC_USE_COUNT do {} while (0)
400#endif
401#define OLD_MOD_INC_USE_COUNT MOD_INC_USE_COUNT
402#define OLD_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT
403#endif
404
405#ifndef SET_NETDEV_DEV
406#define SET_NETDEV_DEV(net, pdev) do {} while (0)
407#endif
408
409#ifndef HAVE_FREE_NETDEV
410#define free_netdev(dev) kfree(dev)
411#endif
412
413#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
414
415#define af_packet_priv data
416#endif
417
418
419#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
420#define DRV_SUSPEND_STATE_TYPE pm_message_t
421#else
422#define DRV_SUSPEND_STATE_TYPE uint32
423#endif
424
425#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
426#define CHECKSUM_HW CHECKSUM_PARTIAL
427#endif
428
429#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
430#define KILL_PROC(pid, sig) \
431{ \
432 struct task_struct *tsk; \
433 tsk = pid_task(find_vpid(pid), PIDTYPE_PID); \
434 if (tsk) send_sig(sig, tsk, 1); \
435}
436#else
437#define KILL_PROC(pid, sig) \
438{ \
439 kill_proc(pid, sig, 1); \
440}
441#endif
442
443#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0))
444#define netdev_priv(dev) dev->priv
445#endif
446
447#endif
diff --git a/drivers/net/wireless/bcm4329/include/miniopt.h b/drivers/net/wireless/bcm4329/include/miniopt.h
new file mode 100644
index 00000000000..3667fb1e215
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/miniopt.h
@@ -0,0 +1,77 @@
1/*
2 * Command line options parser.
3 *
4 * Copyright (C) 1999-2010, 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.1.6.2 2009/01/14 23:52:48 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/bcm4329/include/msgtrace.h b/drivers/net/wireless/bcm4329/include/msgtrace.h
new file mode 100644
index 00000000000..1479086dba3
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/msgtrace.h
@@ -0,0 +1,72 @@
1/*
2 * Trace messages sent over HBUS
3 *
4 * Copyright (C) 1999-2010, 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.1.2.4 2009/01/27 04:09:40 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);
64
65extern void msgtrace_sent(void);
66extern void msgtrace_put(char *buf, int count);
67extern void msgtrace_init(void *hdl1, void *hdl2, msgtrace_func_send_t func_send);
68
69/* This marks the end of a packed structure section. */
70#include <packed_section_end.h>
71
72#endif /* _MSGTRACE_H */
diff --git a/drivers/net/wireless/bcm4329/include/osl.h b/drivers/net/wireless/bcm4329/include/osl.h
new file mode 100644
index 00000000000..5599e536eee
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/osl.h
@@ -0,0 +1,55 @@
1/*
2 * OS Abstraction Layer
3 *
4 * Copyright (C) 1999-2010, 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: osl.h,v 13.37.32.1 2008/11/20 00:51:15 Exp $
24 */
25
26
27#ifndef _osl_h_
28#define _osl_h_
29
30
31typedef struct osl_info osl_t;
32typedef struct osl_dmainfo osldma_t;
33
34#define OSL_PKTTAG_SZ 32
35
36
37typedef void (*pktfree_cb_fn_t)(void *ctx, void *pkt, unsigned int status);
38
39#include <linux_osl.h>
40
41
42
43
44#define SET_REG(osh, r, mask, val) W_REG((osh), (r), ((R_REG((osh), r) & ~(mask)) | (val)))
45
46#ifndef AND_REG
47#define AND_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) & (v))
48#endif
49
50#ifndef OR_REG
51#define OR_REG(osh, r, v) W_REG(osh, (r), R_REG(osh, r) | (v))
52#endif
53
54
55#endif
diff --git a/drivers/net/wireless/bcm4329/include/packed_section_end.h b/drivers/net/wireless/bcm4329/include/packed_section_end.h
new file mode 100644
index 00000000000..5b61c18fcd0
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/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-2010, 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.1.6.3 2008/12/10 00:27:54 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/bcm4329/include/packed_section_start.h b/drivers/net/wireless/bcm4329/include/packed_section_start.h
new file mode 100644
index 00000000000..cb93aa64079
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/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-2010, 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.1.6.3 2008/12/10 00:27:54 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/bcm4329/include/pcicfg.h b/drivers/net/wireless/bcm4329/include/pcicfg.h
new file mode 100644
index 00000000000..898962c942a
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/pcicfg.h
@@ -0,0 +1,52 @@
1/*
2 * pcicfg.h: PCI configuration constants and structures.
3 *
4 * Copyright (C) 1999-2010, 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.41.12.3 2008/06/26 22:49:41 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/bcm4329/include/proto/802.11.h b/drivers/net/wireless/bcm4329/include/proto/802.11.h
new file mode 100644
index 00000000000..fd26317361d
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/proto/802.11.h
@@ -0,0 +1,1433 @@
1/*
2 * Copyright (C) 1999-2010, 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.219.4.1.4.5.6.11 2010/02/09 13:23:26 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
159BWL_PRE_PACKED_STRUCT struct dot11_action_wifi_vendor_specific {
160 uint8 category;
161 uint8 OUI[3];
162 uint8 type;
163 uint8 subtype;
164 uint8 data[1040];
165 struct dot11_action_wifi_vendor_specific* next_node;
166} BWL_POST_PACKED_STRUCT;
167
168typedef struct dot11_action_wifi_vendor_specific dot11_action_wifi_vendor_specific_t;
169
170#define DOT11_BA_CTL_POLICY_NORMAL 0x0000
171#define DOT11_BA_CTL_POLICY_NOACK 0x0001
172#define DOT11_BA_CTL_POLICY_MASK 0x0001
173
174#define DOT11_BA_CTL_MTID 0x0002
175#define DOT11_BA_CTL_COMPRESSED 0x0004
176
177#define DOT11_BA_CTL_NUMMSDU_MASK 0x0FC0
178#define DOT11_BA_CTL_NUMMSDU_SHIFT 6
179
180#define DOT11_BA_CTL_TID_MASK 0xF000
181#define DOT11_BA_CTL_TID_SHIFT 12
182
183
184BWL_PRE_PACKED_STRUCT struct dot11_ctl_header {
185 uint16 fc;
186 uint16 durid;
187 struct ether_addr ra;
188 struct ether_addr ta;
189} BWL_POST_PACKED_STRUCT;
190#define DOT11_CTL_HDR_LEN 16
191
192
193BWL_PRE_PACKED_STRUCT struct dot11_bar {
194 uint16 bar_control;
195 uint16 seqnum;
196} BWL_POST_PACKED_STRUCT;
197#define DOT11_BAR_LEN 4
198
199#define DOT11_BA_BITMAP_LEN 128
200#define DOT11_BA_CMP_BITMAP_LEN 8
201
202BWL_PRE_PACKED_STRUCT struct dot11_ba {
203 uint16 ba_control;
204 uint16 seqnum;
205 uint8 bitmap[DOT11_BA_BITMAP_LEN];
206} BWL_POST_PACKED_STRUCT;
207#define DOT11_BA_LEN 4
208
209
210BWL_PRE_PACKED_STRUCT struct dot11_management_header {
211 uint16 fc;
212 uint16 durid;
213 struct ether_addr da;
214 struct ether_addr sa;
215 struct ether_addr bssid;
216 uint16 seq;
217} BWL_POST_PACKED_STRUCT;
218#define DOT11_MGMT_HDR_LEN 24
219
220
221
222BWL_PRE_PACKED_STRUCT struct dot11_bcn_prb {
223 uint32 timestamp[2];
224 uint16 beacon_interval;
225 uint16 capability;
226} BWL_POST_PACKED_STRUCT;
227#define DOT11_BCN_PRB_LEN 12
228
229BWL_PRE_PACKED_STRUCT struct dot11_auth {
230 uint16 alg;
231 uint16 seq;
232 uint16 status;
233} BWL_POST_PACKED_STRUCT;
234#define DOT11_AUTH_FIXED_LEN 6
235
236BWL_PRE_PACKED_STRUCT struct dot11_assoc_req {
237 uint16 capability;
238 uint16 listen;
239} BWL_POST_PACKED_STRUCT;
240#define DOT11_ASSOC_REQ_FIXED_LEN 4
241
242BWL_PRE_PACKED_STRUCT struct dot11_reassoc_req {
243 uint16 capability;
244 uint16 listen;
245 struct ether_addr ap;
246} BWL_POST_PACKED_STRUCT;
247#define DOT11_REASSOC_REQ_FIXED_LEN 10
248
249BWL_PRE_PACKED_STRUCT struct dot11_assoc_resp {
250 uint16 capability;
251 uint16 status;
252 uint16 aid;
253} BWL_POST_PACKED_STRUCT;
254#define DOT11_ASSOC_RESP_FIXED_LEN 6
255
256BWL_PRE_PACKED_STRUCT struct dot11_action_measure {
257 uint8 category;
258 uint8 action;
259 uint8 token;
260 uint8 data[1];
261} BWL_POST_PACKED_STRUCT;
262#define DOT11_ACTION_MEASURE_LEN 3
263
264BWL_PRE_PACKED_STRUCT struct dot11_action_ht_ch_width {
265 uint8 category;
266 uint8 action;
267 uint8 ch_width;
268} BWL_POST_PACKED_STRUCT;
269
270BWL_PRE_PACKED_STRUCT struct dot11_action_ht_mimops {
271 uint8 category;
272 uint8 action;
273 uint8 control;
274} BWL_POST_PACKED_STRUCT;
275
276#define SM_PWRSAVE_ENABLE 1
277#define SM_PWRSAVE_MODE 2
278
279
280BWL_PRE_PACKED_STRUCT struct dot11_power_cnst {
281 uint8 id;
282 uint8 len;
283 uint8 power;
284} BWL_POST_PACKED_STRUCT;
285typedef struct dot11_power_cnst dot11_power_cnst_t;
286
287BWL_PRE_PACKED_STRUCT struct dot11_power_cap {
288 uint8 min;
289 uint8 max;
290} BWL_POST_PACKED_STRUCT;
291typedef struct dot11_power_cap dot11_power_cap_t;
292
293BWL_PRE_PACKED_STRUCT struct dot11_tpc_rep {
294 uint8 id;
295 uint8 len;
296 uint8 tx_pwr;
297 uint8 margin;
298} BWL_POST_PACKED_STRUCT;
299typedef struct dot11_tpc_rep dot11_tpc_rep_t;
300#define DOT11_MNG_IE_TPC_REPORT_LEN 2
301
302BWL_PRE_PACKED_STRUCT struct dot11_supp_channels {
303 uint8 id;
304 uint8 len;
305 uint8 first_channel;
306 uint8 num_channels;
307} BWL_POST_PACKED_STRUCT;
308typedef struct dot11_supp_channels dot11_supp_channels_t;
309
310
311BWL_PRE_PACKED_STRUCT struct dot11_extch {
312 uint8 id;
313 uint8 len;
314 uint8 extch;
315} BWL_POST_PACKED_STRUCT;
316typedef struct dot11_extch dot11_extch_ie_t;
317
318BWL_PRE_PACKED_STRUCT struct dot11_brcm_extch {
319 uint8 id;
320 uint8 len;
321 uint8 oui[3];
322 uint8 type;
323 uint8 extch;
324} BWL_POST_PACKED_STRUCT;
325typedef struct dot11_brcm_extch dot11_brcm_extch_ie_t;
326
327#define BRCM_EXTCH_IE_LEN 5
328#define BRCM_EXTCH_IE_TYPE 53
329#define DOT11_EXTCH_IE_LEN 1
330#define DOT11_EXT_CH_MASK 0x03
331#define DOT11_EXT_CH_UPPER 0x01
332#define DOT11_EXT_CH_LOWER 0x03
333#define DOT11_EXT_CH_NONE 0x00
334
335BWL_PRE_PACKED_STRUCT struct dot11_action_frmhdr {
336 uint8 category;
337 uint8 action;
338 uint8 data[1];
339} BWL_POST_PACKED_STRUCT;
340#define DOT11_ACTION_FRMHDR_LEN 2
341
342
343BWL_PRE_PACKED_STRUCT struct dot11_channel_switch {
344 uint8 id;
345 uint8 len;
346 uint8 mode;
347 uint8 channel;
348 uint8 count;
349} BWL_POST_PACKED_STRUCT;
350typedef struct dot11_channel_switch dot11_chan_switch_ie_t;
351
352#define DOT11_SWITCH_IE_LEN 3
353
354#define DOT11_CSA_MODE_ADVISORY 0
355#define DOT11_CSA_MODE_NO_TX 1
356
357BWL_PRE_PACKED_STRUCT struct dot11_action_switch_channel {
358 uint8 category;
359 uint8 action;
360 dot11_chan_switch_ie_t chan_switch_ie;
361 dot11_brcm_extch_ie_t extch_ie;
362} BWL_POST_PACKED_STRUCT;
363
364BWL_PRE_PACKED_STRUCT struct dot11_csa_body {
365 uint8 mode;
366 uint8 reg;
367 uint8 channel;
368 uint8 count;
369} BWL_POST_PACKED_STRUCT;
370
371
372BWL_PRE_PACKED_STRUCT struct dot11_ext_csa {
373 uint8 id;
374 uint8 len;
375 struct dot11_csa_body b;
376} BWL_POST_PACKED_STRUCT;
377
378BWL_PRE_PACKED_STRUCT struct dot11y_action_ext_csa {
379 uint8 category;
380 uint8 action;
381 struct dot11_csa_body b;
382} BWL_POST_PACKED_STRUCT;
383typedef struct dot11_ext_csa dot11_ext_csa_ie_t;
384#define DOT11_EXT_CSA_IE_LEN 4
385
386BWL_PRE_PACKED_STRUCT struct dot11_action_ext_csa {
387 uint8 category;
388 uint8 action;
389 dot11_ext_csa_ie_t chan_switch_ie;
390} BWL_POST_PACKED_STRUCT;
391
392BWL_PRE_PACKED_STRUCT struct dot11_obss_coex {
393 uint8 id;
394 uint8 len;
395 uint8 info;
396} BWL_POST_PACKED_STRUCT;
397typedef struct dot11_obss_coex dot11_obss_coex_t;
398#define DOT11_OBSS_COEXINFO_LEN 1
399
400#define DOT11_OBSS_COEX_INFO_REQ 0x01
401#define DOT11_OBSS_COEX_40MHZ_INTOLERANT 0x02
402#define DOT11_OBSS_COEX_20MHZ_WIDTH_REQ 0x04
403
404BWL_PRE_PACKED_STRUCT struct dot11_obss_chanlist {
405 uint8 id;
406 uint8 len;
407 uint8 regclass;
408 uint8 chanlist[1];
409} BWL_POST_PACKED_STRUCT;
410typedef struct dot11_obss_chanlist dot11_obss_chanlist_t;
411#define DOT11_OBSS_CHANLIST_FIXED_LEN 1
412
413BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie {
414 uint8 id;
415 uint8 len;
416 uint8 cap;
417} BWL_POST_PACKED_STRUCT;
418typedef struct dot11_extcap_ie dot11_extcap_ie_t;
419#define DOT11_EXTCAP_LEN 1
420
421
422
423#define DOT11_MEASURE_TYPE_BASIC 0
424#define DOT11_MEASURE_TYPE_CCA 1
425#define DOT11_MEASURE_TYPE_RPI 2
426
427
428#define DOT11_MEASURE_MODE_ENABLE (1<<1)
429#define DOT11_MEASURE_MODE_REQUEST (1<<2)
430#define DOT11_MEASURE_MODE_REPORT (1<<3)
431
432#define DOT11_MEASURE_MODE_LATE (1<<0)
433#define DOT11_MEASURE_MODE_INCAPABLE (1<<1)
434#define DOT11_MEASURE_MODE_REFUSED (1<<2)
435
436#define DOT11_MEASURE_BASIC_MAP_BSS ((uint8)(1<<0))
437#define DOT11_MEASURE_BASIC_MAP_OFDM ((uint8)(1<<1))
438#define DOT11_MEASURE_BASIC_MAP_UKNOWN ((uint8)(1<<2))
439#define DOT11_MEASURE_BASIC_MAP_RADAR ((uint8)(1<<3))
440#define DOT11_MEASURE_BASIC_MAP_UNMEAS ((uint8)(1<<4))
441
442BWL_PRE_PACKED_STRUCT struct dot11_meas_req {
443 uint8 id;
444 uint8 len;
445 uint8 token;
446 uint8 mode;
447 uint8 type;
448 uint8 channel;
449 uint8 start_time[8];
450 uint16 duration;
451} BWL_POST_PACKED_STRUCT;
452typedef struct dot11_meas_req dot11_meas_req_t;
453#define DOT11_MNG_IE_MREQ_LEN 14
454
455#define DOT11_MNG_IE_MREQ_FIXED_LEN 3
456
457BWL_PRE_PACKED_STRUCT struct dot11_meas_rep {
458 uint8 id;
459 uint8 len;
460 uint8 token;
461 uint8 mode;
462 uint8 type;
463 BWL_PRE_PACKED_STRUCT union
464 {
465 BWL_PRE_PACKED_STRUCT struct {
466 uint8 channel;
467 uint8 start_time[8];
468 uint16 duration;
469 uint8 map;
470 } BWL_POST_PACKED_STRUCT basic;
471 uint8 data[1];
472 } BWL_POST_PACKED_STRUCT rep;
473} BWL_POST_PACKED_STRUCT;
474typedef struct dot11_meas_rep dot11_meas_rep_t;
475
476
477#define DOT11_MNG_IE_MREP_FIXED_LEN 3
478
479BWL_PRE_PACKED_STRUCT struct dot11_meas_rep_basic {
480 uint8 channel;
481 uint8 start_time[8];
482 uint16 duration;
483 uint8 map;
484} BWL_POST_PACKED_STRUCT;
485typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t;
486#define DOT11_MEASURE_BASIC_REP_LEN 12
487
488BWL_PRE_PACKED_STRUCT struct dot11_quiet {
489 uint8 id;
490 uint8 len;
491 uint8 count;
492 uint8 period;
493 uint16 duration;
494 uint16 offset;
495} BWL_POST_PACKED_STRUCT;
496typedef struct dot11_quiet dot11_quiet_t;
497
498BWL_PRE_PACKED_STRUCT struct chan_map_tuple {
499 uint8 channel;
500 uint8 map;
501} BWL_POST_PACKED_STRUCT;
502typedef struct chan_map_tuple chan_map_tuple_t;
503
504BWL_PRE_PACKED_STRUCT struct dot11_ibss_dfs {
505 uint8 id;
506 uint8 len;
507 uint8 eaddr[ETHER_ADDR_LEN];
508 uint8 interval;
509 chan_map_tuple_t map[1];
510} BWL_POST_PACKED_STRUCT;
511typedef struct dot11_ibss_dfs dot11_ibss_dfs_t;
512
513
514#define WME_OUI "\x00\x50\xf2"
515#define WME_VER 1
516#define WME_TYPE 2
517#define WME_SUBTYPE_IE 0
518#define WME_SUBTYPE_PARAM_IE 1
519#define WME_SUBTYPE_TSPEC 2
520
521
522#define AC_BE 0
523#define AC_BK 1
524#define AC_VI 2
525#define AC_VO 3
526#define AC_COUNT 4
527
528typedef uint8 ac_bitmap_t;
529
530#define AC_BITMAP_NONE 0x0
531#define AC_BITMAP_ALL 0xf
532#define AC_BITMAP_TST(ab, ac) (((ab) & (1 << (ac))) != 0)
533#define AC_BITMAP_SET(ab, ac) (((ab) |= (1 << (ac))))
534#define AC_BITMAP_RESET(ab, ac) (((ab) &= ~(1 << (ac))))
535
536
537BWL_PRE_PACKED_STRUCT struct wme_ie {
538 uint8 oui[3];
539 uint8 type;
540 uint8 subtype;
541 uint8 version;
542 uint8 qosinfo;
543} BWL_POST_PACKED_STRUCT;
544typedef struct wme_ie wme_ie_t;
545#define WME_IE_LEN 7
546
547BWL_PRE_PACKED_STRUCT struct edcf_acparam {
548 uint8 ACI;
549 uint8 ECW;
550 uint16 TXOP;
551} BWL_POST_PACKED_STRUCT;
552typedef struct edcf_acparam edcf_acparam_t;
553
554
555BWL_PRE_PACKED_STRUCT struct wme_param_ie {
556 uint8 oui[3];
557 uint8 type;
558 uint8 subtype;
559 uint8 version;
560 uint8 qosinfo;
561 uint8 rsvd;
562 edcf_acparam_t acparam[AC_COUNT];
563} BWL_POST_PACKED_STRUCT;
564typedef struct wme_param_ie wme_param_ie_t;
565#define WME_PARAM_IE_LEN 24
566
567
568#define WME_QI_AP_APSD_MASK 0x80
569#define WME_QI_AP_APSD_SHIFT 7
570#define WME_QI_AP_COUNT_MASK 0x0f
571#define WME_QI_AP_COUNT_SHIFT 0
572
573
574#define WME_QI_STA_MAXSPLEN_MASK 0x60
575#define WME_QI_STA_MAXSPLEN_SHIFT 5
576#define WME_QI_STA_APSD_ALL_MASK 0xf
577#define WME_QI_STA_APSD_ALL_SHIFT 0
578#define WME_QI_STA_APSD_BE_MASK 0x8
579#define WME_QI_STA_APSD_BE_SHIFT 3
580#define WME_QI_STA_APSD_BK_MASK 0x4
581#define WME_QI_STA_APSD_BK_SHIFT 2
582#define WME_QI_STA_APSD_VI_MASK 0x2
583#define WME_QI_STA_APSD_VI_SHIFT 1
584#define WME_QI_STA_APSD_VO_MASK 0x1
585#define WME_QI_STA_APSD_VO_SHIFT 0
586
587
588#define EDCF_AIFSN_MIN 1
589#define EDCF_AIFSN_MAX 15
590#define EDCF_AIFSN_MASK 0x0f
591#define EDCF_ACM_MASK 0x10
592#define EDCF_ACI_MASK 0x60
593#define EDCF_ACI_SHIFT 5
594#define EDCF_AIFSN_SHIFT 12
595
596
597#define EDCF_ECW_MIN 0
598#define EDCF_ECW_MAX 15
599#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1)
600#define EDCF_ECWMIN_MASK 0x0f
601#define EDCF_ECWMAX_MASK 0xf0
602#define EDCF_ECWMAX_SHIFT 4
603
604
605#define EDCF_TXOP_MIN 0
606#define EDCF_TXOP_MAX 65535
607#define EDCF_TXOP2USEC(txop) ((txop) << 5)
608
609
610#define NON_EDCF_AC_BE_ACI_STA 0x02
611
612
613#define EDCF_AC_BE_ACI_STA 0x03
614#define EDCF_AC_BE_ECW_STA 0xA4
615#define EDCF_AC_BE_TXOP_STA 0x0000
616#define EDCF_AC_BK_ACI_STA 0x27
617#define EDCF_AC_BK_ECW_STA 0xA4
618#define EDCF_AC_BK_TXOP_STA 0x0000
619#define EDCF_AC_VI_ACI_STA 0x42
620#define EDCF_AC_VI_ECW_STA 0x43
621#define EDCF_AC_VI_TXOP_STA 0x005e
622#define EDCF_AC_VO_ACI_STA 0x62
623#define EDCF_AC_VO_ECW_STA 0x32
624#define EDCF_AC_VO_TXOP_STA 0x002f
625
626
627#define EDCF_AC_BE_ACI_AP 0x03
628#define EDCF_AC_BE_ECW_AP 0x64
629#define EDCF_AC_BE_TXOP_AP 0x0000
630#define EDCF_AC_BK_ACI_AP 0x27
631#define EDCF_AC_BK_ECW_AP 0xA4
632#define EDCF_AC_BK_TXOP_AP 0x0000
633#define EDCF_AC_VI_ACI_AP 0x41
634#define EDCF_AC_VI_ECW_AP 0x43
635#define EDCF_AC_VI_TXOP_AP 0x005e
636#define EDCF_AC_VO_ACI_AP 0x61
637#define EDCF_AC_VO_ECW_AP 0x32
638#define EDCF_AC_VO_TXOP_AP 0x002f
639
640
641BWL_PRE_PACKED_STRUCT struct edca_param_ie {
642 uint8 qosinfo;
643 uint8 rsvd;
644 edcf_acparam_t acparam[AC_COUNT];
645} BWL_POST_PACKED_STRUCT;
646typedef struct edca_param_ie edca_param_ie_t;
647#define EDCA_PARAM_IE_LEN 18
648
649
650BWL_PRE_PACKED_STRUCT struct qos_cap_ie {
651 uint8 qosinfo;
652} BWL_POST_PACKED_STRUCT;
653typedef struct qos_cap_ie qos_cap_ie_t;
654
655BWL_PRE_PACKED_STRUCT struct dot11_qbss_load_ie {
656 uint8 id;
657 uint8 length;
658 uint16 station_count;
659 uint8 channel_utilization;
660 uint16 aac;
661} BWL_POST_PACKED_STRUCT;
662typedef struct dot11_qbss_load_ie dot11_qbss_load_ie_t;
663
664
665#define FIXED_MSDU_SIZE 0x8000
666#define MSDU_SIZE_MASK 0x7fff
667
668
669
670#define INTEGER_SHIFT 13
671#define FRACTION_MASK 0x1FFF
672
673
674BWL_PRE_PACKED_STRUCT struct dot11_management_notification {
675 uint8 category;
676 uint8 action;
677 uint8 token;
678 uint8 status;
679 uint8 data[1];
680} BWL_POST_PACKED_STRUCT;
681#define DOT11_MGMT_NOTIFICATION_LEN 4
682
683
684#define WME_ADDTS_REQUEST 0
685#define WME_ADDTS_RESPONSE 1
686#define WME_DELTS_REQUEST 2
687
688
689#define WME_ADMISSION_ACCEPTED 0
690#define WME_INVALID_PARAMETERS 1
691#define WME_ADMISSION_REFUSED 3
692
693
694#define BCN_PRB_SSID(body) ((char*)(body) + DOT11_BCN_PRB_LEN)
695
696
697#define DOT11_OPEN_SYSTEM 0
698#define DOT11_SHARED_KEY 1
699
700#define DOT11_OPEN_SHARED 2
701#define DOT11_CHALLENGE_LEN 128
702
703
704#define FC_PVER_MASK 0x3
705#define FC_PVER_SHIFT 0
706#define FC_TYPE_MASK 0xC
707#define FC_TYPE_SHIFT 2
708#define FC_SUBTYPE_MASK 0xF0
709#define FC_SUBTYPE_SHIFT 4
710#define FC_TODS 0x100
711#define FC_TODS_SHIFT 8
712#define FC_FROMDS 0x200
713#define FC_FROMDS_SHIFT 9
714#define FC_MOREFRAG 0x400
715#define FC_MOREFRAG_SHIFT 10
716#define FC_RETRY 0x800
717#define FC_RETRY_SHIFT 11
718#define FC_PM 0x1000
719#define FC_PM_SHIFT 12
720#define FC_MOREDATA 0x2000
721#define FC_MOREDATA_SHIFT 13
722#define FC_WEP 0x4000
723#define FC_WEP_SHIFT 14
724#define FC_ORDER 0x8000
725#define FC_ORDER_SHIFT 15
726
727
728#define SEQNUM_SHIFT 4
729#define SEQNUM_MAX 0x1000
730#define FRAGNUM_MASK 0xF
731
732
733
734
735#define FC_TYPE_MNG 0
736#define FC_TYPE_CTL 1
737#define FC_TYPE_DATA 2
738
739
740#define FC_SUBTYPE_ASSOC_REQ 0
741#define FC_SUBTYPE_ASSOC_RESP 1
742#define FC_SUBTYPE_REASSOC_REQ 2
743#define FC_SUBTYPE_REASSOC_RESP 3
744#define FC_SUBTYPE_PROBE_REQ 4
745#define FC_SUBTYPE_PROBE_RESP 5
746#define FC_SUBTYPE_BEACON 8
747#define FC_SUBTYPE_ATIM 9
748#define FC_SUBTYPE_DISASSOC 10
749#define FC_SUBTYPE_AUTH 11
750#define FC_SUBTYPE_DEAUTH 12
751#define FC_SUBTYPE_ACTION 13
752#define FC_SUBTYPE_ACTION_NOACK 14
753
754
755#define FC_SUBTYPE_CTL_WRAPPER 7
756#define FC_SUBTYPE_BLOCKACK_REQ 8
757#define FC_SUBTYPE_BLOCKACK 9
758#define FC_SUBTYPE_PS_POLL 10
759#define FC_SUBTYPE_RTS 11
760#define FC_SUBTYPE_CTS 12
761#define FC_SUBTYPE_ACK 13
762#define FC_SUBTYPE_CF_END 14
763#define FC_SUBTYPE_CF_END_ACK 15
764
765
766#define FC_SUBTYPE_DATA 0
767#define FC_SUBTYPE_DATA_CF_ACK 1
768#define FC_SUBTYPE_DATA_CF_POLL 2
769#define FC_SUBTYPE_DATA_CF_ACK_POLL 3
770#define FC_SUBTYPE_NULL 4
771#define FC_SUBTYPE_CF_ACK 5
772#define FC_SUBTYPE_CF_POLL 6
773#define FC_SUBTYPE_CF_ACK_POLL 7
774#define FC_SUBTYPE_QOS_DATA 8
775#define FC_SUBTYPE_QOS_DATA_CF_ACK 9
776#define FC_SUBTYPE_QOS_DATA_CF_POLL 10
777#define FC_SUBTYPE_QOS_DATA_CF_ACK_POLL 11
778#define FC_SUBTYPE_QOS_NULL 12
779#define FC_SUBTYPE_QOS_CF_POLL 14
780#define FC_SUBTYPE_QOS_CF_ACK_POLL 15
781
782
783#define FC_SUBTYPE_ANY_QOS(s) (((s) & 8) != 0)
784#define FC_SUBTYPE_ANY_NULL(s) (((s) & 4) != 0)
785#define FC_SUBTYPE_ANY_CF_POLL(s) (((s) & 2) != 0)
786#define FC_SUBTYPE_ANY_CF_ACK(s) (((s) & 1) != 0)
787
788
789#define FC_KIND_MASK (FC_TYPE_MASK | FC_SUBTYPE_MASK)
790
791#define FC_KIND(t, s) (((t) << FC_TYPE_SHIFT) | ((s) << FC_SUBTYPE_SHIFT))
792
793#define FC_SUBTYPE(fc) (((fc) & FC_SUBTYPE_MASK) >> FC_SUBTYPE_SHIFT)
794#define FC_TYPE(fc) (((fc) & FC_TYPE_MASK) >> FC_TYPE_SHIFT)
795
796#define FC_ASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_REQ)
797#define FC_ASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ASSOC_RESP)
798#define FC_REASSOC_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_REQ)
799#define FC_REASSOC_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_REASSOC_RESP)
800#define FC_PROBE_REQ FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_REQ)
801#define FC_PROBE_RESP FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_PROBE_RESP)
802#define FC_BEACON FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_BEACON)
803#define FC_DISASSOC FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DISASSOC)
804#define FC_AUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_AUTH)
805#define FC_DEAUTH FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_DEAUTH)
806#define FC_ACTION FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION)
807#define FC_ACTION_NOACK FC_KIND(FC_TYPE_MNG, FC_SUBTYPE_ACTION_NOACK)
808
809#define FC_CTL_WRAPPER FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTL_WRAPPER)
810#define FC_BLOCKACK_REQ FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK_REQ)
811#define FC_BLOCKACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_BLOCKACK)
812#define FC_PS_POLL FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_PS_POLL)
813#define FC_RTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_RTS)
814#define FC_CTS FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CTS)
815#define FC_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_ACK)
816#define FC_CF_END FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END)
817#define FC_CF_END_ACK FC_KIND(FC_TYPE_CTL, FC_SUBTYPE_CF_END_ACK)
818
819#define FC_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA)
820#define FC_NULL_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_NULL)
821#define FC_DATA_CF_ACK FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_DATA_CF_ACK)
822#define FC_QOS_DATA FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_DATA)
823#define FC_QOS_NULL FC_KIND(FC_TYPE_DATA, FC_SUBTYPE_QOS_NULL)
824
825
826
827
828#define QOS_PRIO_SHIFT 0
829#define QOS_PRIO_MASK 0x0007
830#define QOS_PRIO(qos) (((qos) & QOS_PRIO_MASK) >> QOS_PRIO_SHIFT)
831
832
833#define QOS_TID_SHIFT 0
834#define QOS_TID_MASK 0x000f
835#define QOS_TID(qos) (((qos) & QOS_TID_MASK) >> QOS_TID_SHIFT)
836
837
838#define QOS_EOSP_SHIFT 4
839#define QOS_EOSP_MASK 0x0010
840#define QOS_EOSP(qos) (((qos) & QOS_EOSP_MASK) >> QOS_EOSP_SHIFT)
841
842
843#define QOS_ACK_NORMAL_ACK 0
844#define QOS_ACK_NO_ACK 1
845#define QOS_ACK_NO_EXP_ACK 2
846#define QOS_ACK_BLOCK_ACK 3
847#define QOS_ACK_SHIFT 5
848#define QOS_ACK_MASK 0x0060
849#define QOS_ACK(qos) (((qos) & QOS_ACK_MASK) >> QOS_ACK_SHIFT)
850
851
852#define QOS_AMSDU_SHIFT 7
853#define QOS_AMSDU_MASK 0x0080
854
855
856
857
858
859
860#define DOT11_MNG_AUTH_ALGO_LEN 2
861#define DOT11_MNG_AUTH_SEQ_LEN 2
862#define DOT11_MNG_BEACON_INT_LEN 2
863#define DOT11_MNG_CAP_LEN 2
864#define DOT11_MNG_AP_ADDR_LEN 6
865#define DOT11_MNG_LISTEN_INT_LEN 2
866#define DOT11_MNG_REASON_LEN 2
867#define DOT11_MNG_AID_LEN 2
868#define DOT11_MNG_STATUS_LEN 2
869#define DOT11_MNG_TIMESTAMP_LEN 8
870
871
872#define DOT11_AID_MASK 0x3fff
873
874
875#define DOT11_RC_RESERVED 0
876#define DOT11_RC_UNSPECIFIED 1
877#define DOT11_RC_AUTH_INVAL 2
878#define DOT11_RC_DEAUTH_LEAVING 3
879#define DOT11_RC_INACTIVITY 4
880#define DOT11_RC_BUSY 5
881#define DOT11_RC_INVAL_CLASS_2 6
882#define DOT11_RC_INVAL_CLASS_3 7
883#define DOT11_RC_DISASSOC_LEAVING 8
884#define DOT11_RC_NOT_AUTH 9
885#define DOT11_RC_BAD_PC 10
886#define DOT11_RC_BAD_CHANNELS 11
887
888
889
890#define DOT11_RC_UNSPECIFIED_QOS 32
891#define DOT11_RC_INSUFFCIENT_BW 33
892#define DOT11_RC_EXCESSIVE_FRAMES 34
893#define DOT11_RC_TX_OUTSIDE_TXOP 35
894#define DOT11_RC_LEAVING_QBSS 36
895#define DOT11_RC_BAD_MECHANISM 37
896#define DOT11_RC_SETUP_NEEDED 38
897#define DOT11_RC_TIMEOUT 39
898
899#define DOT11_RC_MAX 23
900
901
902#define DOT11_SC_SUCCESS 0
903#define DOT11_SC_FAILURE 1
904#define DOT11_SC_CAP_MISMATCH 10
905#define DOT11_SC_REASSOC_FAIL 11
906#define DOT11_SC_ASSOC_FAIL 12
907#define DOT11_SC_AUTH_MISMATCH 13
908#define DOT11_SC_AUTH_SEQ 14
909#define DOT11_SC_AUTH_CHALLENGE_FAIL 15
910#define DOT11_SC_AUTH_TIMEOUT 16
911#define DOT11_SC_ASSOC_BUSY_FAIL 17
912#define DOT11_SC_ASSOC_RATE_MISMATCH 18
913#define DOT11_SC_ASSOC_SHORT_REQUIRED 19
914#define DOT11_SC_ASSOC_PBCC_REQUIRED 20
915#define DOT11_SC_ASSOC_AGILITY_REQUIRED 21
916#define DOT11_SC_ASSOC_SPECTRUM_REQUIRED 22
917#define DOT11_SC_ASSOC_BAD_POWER_CAP 23
918#define DOT11_SC_ASSOC_BAD_SUP_CHANNELS 24
919#define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25
920#define DOT11_SC_ASSOC_ERPBCC_REQUIRED 26
921#define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27
922
923#define DOT11_SC_DECLINED 37
924#define DOT11_SC_INVALID_PARAMS 38
925
926
927#define DOT11_MNG_DS_PARAM_LEN 1
928#define DOT11_MNG_IBSS_PARAM_LEN 2
929
930
931#define DOT11_MNG_TIM_FIXED_LEN 3
932#define DOT11_MNG_TIM_DTIM_COUNT 0
933#define DOT11_MNG_TIM_DTIM_PERIOD 1
934#define DOT11_MNG_TIM_BITMAP_CTL 2
935#define DOT11_MNG_TIM_PVB 3
936
937
938#define TLV_TAG_OFF 0
939#define TLV_LEN_OFF 1
940#define TLV_HDR_LEN 2
941#define TLV_BODY_OFF 2
942
943
944#define DOT11_MNG_SSID_ID 0
945#define DOT11_MNG_RATES_ID 1
946#define DOT11_MNG_FH_PARMS_ID 2
947#define DOT11_MNG_DS_PARMS_ID 3
948#define DOT11_MNG_CF_PARMS_ID 4
949#define DOT11_MNG_TIM_ID 5
950#define DOT11_MNG_IBSS_PARMS_ID 6
951#define DOT11_MNG_COUNTRY_ID 7
952#define DOT11_MNG_HOPPING_PARMS_ID 8
953#define DOT11_MNG_HOPPING_TABLE_ID 9
954#define DOT11_MNG_REQUEST_ID 10
955#define DOT11_MNG_QBSS_LOAD_ID 11
956#define DOT11_MNG_EDCA_PARAM_ID 12
957#define DOT11_MNG_CHALLENGE_ID 16
958#define DOT11_MNG_PWR_CONSTRAINT_ID 32
959#define DOT11_MNG_PWR_CAP_ID 33
960#define DOT11_MNG_TPC_REQUEST_ID 34
961#define DOT11_MNG_TPC_REPORT_ID 35
962#define DOT11_MNG_SUPP_CHANNELS_ID 36
963#define DOT11_MNG_CHANNEL_SWITCH_ID 37
964#define DOT11_MNG_MEASURE_REQUEST_ID 38
965#define DOT11_MNG_MEASURE_REPORT_ID 39
966#define DOT11_MNG_QUIET_ID 40
967#define DOT11_MNG_IBSS_DFS_ID 41
968#define DOT11_MNG_ERP_ID 42
969#define DOT11_MNG_TS_DELAY_ID 43
970#define DOT11_MNG_HT_CAP 45
971#define DOT11_MNG_QOS_CAP_ID 46
972#define DOT11_MNG_NONERP_ID 47
973#define DOT11_MNG_RSN_ID 48
974#define DOT11_MNG_EXT_RATES_ID 50
975#define DOT11_MNG_REGCLASS_ID 59
976#define DOT11_MNG_EXT_CSA_ID 60
977#define DOT11_MNG_HT_ADD 61
978#define DOT11_MNG_EXT_CHANNEL_OFFSET 62
979#define DOT11_MNG_WAPI_ID 68
980#define DOT11_MNG_HT_BSS_COEXINFO_ID 72
981#define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73
982#define DOT11_MNG_HT_OBSS_ID 74
983#define DOT11_MNG_EXT_CAP 127
984#define DOT11_MNG_WPA_ID 221
985#define DOT11_MNG_PROPR_ID 221
986
987
988#define DOT11_RATE_BASIC 0x80
989#define DOT11_RATE_MASK 0x7F
990
991
992#define DOT11_MNG_ERP_LEN 1
993#define DOT11_MNG_NONERP_PRESENT 0x01
994#define DOT11_MNG_USE_PROTECTION 0x02
995#define DOT11_MNG_BARKER_PREAMBLE 0x04
996
997#define DOT11_MGN_TS_DELAY_LEN 4
998#define TS_DELAY_FIELD_SIZE 4
999
1000
1001#define DOT11_CAP_ESS 0x0001
1002#define DOT11_CAP_IBSS 0x0002
1003#define DOT11_CAP_POLLABLE 0x0004
1004#define DOT11_CAP_POLL_RQ 0x0008
1005#define DOT11_CAP_PRIVACY 0x0010
1006#define DOT11_CAP_SHORT 0x0020
1007#define DOT11_CAP_PBCC 0x0040
1008#define DOT11_CAP_AGILITY 0x0080
1009#define DOT11_CAP_SPECTRUM 0x0100
1010#define DOT11_CAP_SHORTSLOT 0x0400
1011#define DOT11_CAP_CCK_OFDM 0x2000
1012
1013
1014#define DOT11_OBSS_COEX_MNG_SUPPORT 0x01
1015
1016
1017#define DOT11_ACTION_HDR_LEN 2
1018#define DOT11_ACTION_CAT_ERR_MASK 0x80
1019#define DOT11_ACTION_CAT_MASK 0x7F
1020#define DOT11_ACTION_CAT_SPECT_MNG 0
1021#define DOT11_ACTION_CAT_BLOCKACK 3
1022#define DOT11_ACTION_CAT_PUBLIC 4
1023#define DOT11_ACTION_CAT_HT 7
1024#define DOT11_ACTION_CAT_VS 127
1025#define DOT11_ACTION_NOTIFICATION 0x11
1026
1027#define DOT11_ACTION_ID_M_REQ 0
1028#define DOT11_ACTION_ID_M_REP 1
1029#define DOT11_ACTION_ID_TPC_REQ 2
1030#define DOT11_ACTION_ID_TPC_REP 3
1031#define DOT11_ACTION_ID_CHANNEL_SWITCH 4
1032#define DOT11_ACTION_ID_EXT_CSA 5
1033
1034
1035#define DOT11_ACTION_ID_HT_CH_WIDTH 0
1036#define DOT11_ACTION_ID_HT_MIMO_PS 1
1037
1038
1039#define DOT11_PUB_ACTION_BSS_COEX_MNG 0
1040#define DOT11_PUB_ACTION_CHANNEL_SWITCH 4
1041
1042
1043#define DOT11_BA_ACTION_ADDBA_REQ 0
1044#define DOT11_BA_ACTION_ADDBA_RESP 1
1045#define DOT11_BA_ACTION_DELBA 2
1046
1047
1048#define DOT11_ADDBA_PARAM_AMSDU_SUP 0x0001
1049#define DOT11_ADDBA_PARAM_POLICY_MASK 0x0002
1050#define DOT11_ADDBA_PARAM_POLICY_SHIFT 1
1051#define DOT11_ADDBA_PARAM_TID_MASK 0x003c
1052#define DOT11_ADDBA_PARAM_TID_SHIFT 2
1053#define DOT11_ADDBA_PARAM_BSIZE_MASK 0xffc0
1054#define DOT11_ADDBA_PARAM_BSIZE_SHIFT 6
1055
1056#define DOT11_ADDBA_POLICY_DELAYED 0
1057#define DOT11_ADDBA_POLICY_IMMEDIATE 1
1058
1059BWL_PRE_PACKED_STRUCT struct dot11_addba_req {
1060 uint8 category;
1061 uint8 action;
1062 uint8 token;
1063 uint16 addba_param_set;
1064 uint16 timeout;
1065 uint16 start_seqnum;
1066} BWL_POST_PACKED_STRUCT;
1067typedef struct dot11_addba_req dot11_addba_req_t;
1068#define DOT11_ADDBA_REQ_LEN 9
1069
1070BWL_PRE_PACKED_STRUCT struct dot11_addba_resp {
1071 uint8 category;
1072 uint8 action;
1073 uint8 token;
1074 uint16 status;
1075 uint16 addba_param_set;
1076 uint16 timeout;
1077} BWL_POST_PACKED_STRUCT;
1078typedef struct dot11_addba_resp dot11_addba_resp_t;
1079#define DOT11_ADDBA_RESP_LEN 9
1080
1081
1082#define DOT11_DELBA_PARAM_INIT_MASK 0x0800
1083#define DOT11_DELBA_PARAM_INIT_SHIFT 11
1084#define DOT11_DELBA_PARAM_TID_MASK 0xf000
1085#define DOT11_DELBA_PARAM_TID_SHIFT 12
1086
1087BWL_PRE_PACKED_STRUCT struct dot11_delba {
1088 uint8 category;
1089 uint8 action;
1090 uint16 delba_param_set;
1091 uint16 reason;
1092} BWL_POST_PACKED_STRUCT;
1093typedef struct dot11_delba dot11_delba_t;
1094#define DOT11_DELBA_LEN 6
1095
1096
1097#define DOT11_BSSTYPE_INFRASTRUCTURE 0
1098#define DOT11_BSSTYPE_INDEPENDENT 1
1099#define DOT11_BSSTYPE_ANY 2
1100#define DOT11_SCANTYPE_ACTIVE 0
1101#define DOT11_SCANTYPE_PASSIVE 1
1102
1103
1104#define PREN_PREAMBLE 24
1105#define PREN_MM_EXT 8
1106#define PREN_PREAMBLE_EXT 4
1107
1108
1109#define NPHY_RIFS_TIME 2
1110
1111
1112#define APHY_SLOT_TIME 9
1113#define APHY_SIFS_TIME 16
1114#define APHY_DIFS_TIME (APHY_SIFS_TIME + (2 * APHY_SLOT_TIME))
1115#define APHY_PREAMBLE_TIME 16
1116#define APHY_SIGNAL_TIME 4
1117#define APHY_SYMBOL_TIME 4
1118#define APHY_SERVICE_NBITS 16
1119#define APHY_TAIL_NBITS 6
1120#define APHY_CWMIN 15
1121
1122
1123#define BPHY_SLOT_TIME 20
1124#define BPHY_SIFS_TIME 10
1125#define BPHY_DIFS_TIME 50
1126#define BPHY_PLCP_TIME 192
1127#define BPHY_PLCP_SHORT_TIME 96
1128#define BPHY_CWMIN 31
1129
1130
1131#define DOT11_OFDM_SIGNAL_EXTENSION 6
1132
1133#define PHY_CWMAX 1023
1134
1135#define DOT11_MAXNUMFRAGS 16
1136
1137
1138typedef struct d11cnt {
1139 uint32 txfrag;
1140 uint32 txmulti;
1141 uint32 txfail;
1142 uint32 txretry;
1143 uint32 txretrie;
1144 uint32 rxdup;
1145 uint32 txrts;
1146 uint32 txnocts;
1147 uint32 txnoack;
1148 uint32 rxfrag;
1149 uint32 rxmulti;
1150 uint32 rxcrc;
1151 uint32 txfrmsnt;
1152 uint32 rxundec;
1153} d11cnt_t;
1154
1155
1156#define BRCM_PROP_OUI "\x00\x90\x4C"
1157
1158
1159
1160
1161BWL_PRE_PACKED_STRUCT struct brcm_prop_ie_s {
1162 uint8 id;
1163 uint8 len;
1164 uint8 oui[3];
1165 uint8 type;
1166 uint16 cap;
1167} BWL_POST_PACKED_STRUCT;
1168typedef struct brcm_prop_ie_s brcm_prop_ie_t;
1169
1170#define BRCM_PROP_IE_LEN 6
1171
1172#define DPT_IE_TYPE 2
1173
1174
1175#define BRCM_OUI "\x00\x10\x18"
1176
1177
1178BWL_PRE_PACKED_STRUCT struct brcm_ie {
1179 uint8 id;
1180 uint8 len;
1181 uint8 oui[3];
1182 uint8 ver;
1183 uint8 assoc;
1184 uint8 flags;
1185 uint8 flags1;
1186 uint16 amsdu_mtu_pref;
1187} BWL_POST_PACKED_STRUCT;
1188typedef struct brcm_ie brcm_ie_t;
1189#define BRCM_IE_LEN 11
1190#define BRCM_IE_VER 2
1191#define BRCM_IE_LEGACY_AES_VER 1
1192
1193
1194#ifdef WLAFTERBURNER
1195#define BRF_ABCAP 0x1
1196#define BRF_ABRQRD 0x2
1197#define BRF_ABCOUNTER_MASK 0xf0
1198#define BRF_ABCOUNTER_SHIFT 4
1199#endif
1200#define BRF_LZWDS 0x4
1201#define BRF_BLOCKACK 0x8
1202
1203
1204#define BRF1_AMSDU 0x1
1205#define BRF1_WMEPS 0x4
1206#define BRF1_PSOFIX 0x8
1207
1208#ifdef WLAFTERBURNER
1209#define AB_WDS_TIMEOUT_MAX 15
1210#define AB_WDS_TIMEOUT_MIN 1
1211#endif
1212
1213#define AB_GUARDCOUNT 10
1214
1215#define MCSSET_LEN 16
1216#define MAX_MCS_NUM (128)
1217
1218BWL_PRE_PACKED_STRUCT struct ht_cap_ie {
1219 uint16 cap;
1220 uint8 params;
1221 uint8 supp_mcs[MCSSET_LEN];
1222 uint16 ext_htcap;
1223 uint32 txbf_cap;
1224 uint8 as_cap;
1225} BWL_POST_PACKED_STRUCT;
1226typedef struct ht_cap_ie ht_cap_ie_t;
1227
1228
1229
1230BWL_PRE_PACKED_STRUCT struct ht_prop_cap_ie {
1231 uint8 id;
1232 uint8 len;
1233 uint8 oui[3];
1234 uint8 type;
1235 ht_cap_ie_t cap_ie;
1236} BWL_POST_PACKED_STRUCT;
1237typedef struct ht_prop_cap_ie ht_prop_cap_ie_t;
1238#define HT_PROP_IE_OVERHEAD 4
1239#define HT_CAP_IE_LEN 26
1240#define HT_CAP_IE_TYPE 51
1241
1242#define HT_CAP_LDPC_CODING 0x0001
1243#define HT_CAP_40MHZ 0x0002
1244#define HT_CAP_MIMO_PS_MASK 0x000C
1245#define HT_CAP_MIMO_PS_SHIFT 0x0002
1246#define HT_CAP_MIMO_PS_OFF 0x0003
1247#define HT_CAP_MIMO_PS_RTS 0x0001
1248#define HT_CAP_MIMO_PS_ON 0x0000
1249#define HT_CAP_GF 0x0010
1250#define HT_CAP_SHORT_GI_20 0x0020
1251#define HT_CAP_SHORT_GI_40 0x0040
1252#define HT_CAP_TX_STBC 0x0080
1253#define HT_CAP_RX_STBC_MASK 0x0300
1254#define HT_CAP_RX_STBC_SHIFT 8
1255#define HT_CAP_DELAYED_BA 0x0400
1256#define HT_CAP_MAX_AMSDU 0x0800
1257#define HT_CAP_DSSS_CCK 0x1000
1258#define HT_CAP_PSMP 0x2000
1259#define HT_CAP_40MHZ_INTOLERANT 0x4000
1260#define HT_CAP_LSIG_TXOP 0x8000
1261
1262#define HT_CAP_RX_STBC_NO 0x0
1263#define HT_CAP_RX_STBC_ONE_STREAM 0x1
1264#define HT_CAP_RX_STBC_TWO_STREAM 0x2
1265#define HT_CAP_RX_STBC_THREE_STREAM 0x3
1266
1267#define HT_MAX_AMSDU 7935
1268#define HT_MIN_AMSDU 3835
1269
1270#define HT_PARAMS_RX_FACTOR_MASK 0x03
1271#define HT_PARAMS_DENSITY_MASK 0x1C
1272#define HT_PARAMS_DENSITY_SHIFT 2
1273
1274
1275#define AMPDU_MAX_MPDU_DENSITY 7
1276#define AMPDU_RX_FACTOR_64K 3
1277#define AMPDU_RX_FACTOR_BASE 8*1024
1278#define AMPDU_DELIMITER_LEN 4
1279
1280#define HT_CAP_EXT_PCO 0x0001
1281#define HT_CAP_EXT_PCO_TTIME_MASK 0x0006
1282#define HT_CAP_EXT_PCO_TTIME_SHIFT 1
1283#define HT_CAP_EXT_MCS_FEEDBACK_MASK 0x0300
1284#define HT_CAP_EXT_MCS_FEEDBACK_SHIFT 8
1285#define HT_CAP_EXT_HTC 0x0400
1286#define HT_CAP_EXT_RD_RESP 0x0800
1287
1288BWL_PRE_PACKED_STRUCT struct ht_add_ie {
1289 uint8 ctl_ch;
1290 uint8 byte1;
1291 uint16 opmode;
1292 uint16 misc_bits;
1293 uint8 basic_mcs[MCSSET_LEN];
1294} BWL_POST_PACKED_STRUCT;
1295typedef struct ht_add_ie ht_add_ie_t;
1296
1297
1298
1299BWL_PRE_PACKED_STRUCT struct ht_prop_add_ie {
1300 uint8 id;
1301 uint8 len;
1302 uint8 oui[3];
1303 uint8 type;
1304 ht_add_ie_t add_ie;
1305} BWL_POST_PACKED_STRUCT;
1306typedef struct ht_prop_add_ie ht_prop_add_ie_t;
1307
1308#define HT_ADD_IE_LEN 22
1309#define HT_ADD_IE_TYPE 52
1310
1311
1312#define HT_BW_ANY 0x04
1313#define HT_RIFS_PERMITTED 0x08
1314
1315
1316#define HT_OPMODE_MASK 0x0003
1317#define HT_OPMODE_SHIFT 0
1318#define HT_OPMODE_PURE 0x0000
1319#define HT_OPMODE_OPTIONAL 0x0001
1320#define HT_OPMODE_HT20IN40 0x0002
1321#define HT_OPMODE_MIXED 0x0003
1322#define HT_OPMODE_NONGF 0x0004
1323#define DOT11N_TXBURST 0x0008
1324#define DOT11N_OBSS_NONHT 0x0010
1325
1326
1327#define HT_BASIC_STBC_MCS 0x007f
1328#define HT_DUAL_STBC_PROT 0x0080
1329#define HT_SECOND_BCN 0x0100
1330#define HT_LSIG_TXOP 0x0200
1331#define HT_PCO_ACTIVE 0x0400
1332#define HT_PCO_PHASE 0x0800
1333#define HT_DUALCTS_PROTECTION 0x0080
1334
1335
1336#define DOT11N_2G_TXBURST_LIMIT 6160
1337#define DOT11N_5G_TXBURST_LIMIT 3080
1338
1339
1340#define GET_HT_OPMODE(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \
1341 >> HT_OPMODE_SHIFT)
1342#define HT_MIXEDMODE_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \
1343 == HT_OPMODE_MIXED)
1344#define HT_HT20_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \
1345 == HT_OPMODE_HT20IN40)
1346#define HT_OPTIONAL_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_MASK) \
1347 == HT_OPMODE_OPTIONAL)
1348#define HT_USE_PROTECTION(add_ie) (HT_HT20_PRESENT((add_ie)) || \
1349 HT_MIXEDMODE_PRESENT((add_ie)))
1350#define HT_NONGF_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & HT_OPMODE_NONGF) \
1351 == HT_OPMODE_NONGF)
1352#define DOT11N_TXBURST_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_TXBURST) \
1353 == DOT11N_TXBURST)
1354#define DOT11N_OBSS_NONHT_PRESENT(add_ie) ((ltoh16_ua(&add_ie->opmode) & DOT11N_OBSS_NONHT) \
1355 == DOT11N_OBSS_NONHT)
1356
1357BWL_PRE_PACKED_STRUCT struct obss_params {
1358 uint16 passive_dwell;
1359 uint16 active_dwell;
1360 uint16 bss_widthscan_interval;
1361 uint16 passive_total;
1362 uint16 active_total;
1363 uint16 chanwidth_transition_dly;
1364 uint16 activity_threshold;
1365} BWL_POST_PACKED_STRUCT;
1366typedef struct obss_params obss_params_t;
1367
1368BWL_PRE_PACKED_STRUCT struct dot11_obss_ie {
1369 uint8 id;
1370 uint8 len;
1371 obss_params_t obss_params;
1372} BWL_POST_PACKED_STRUCT;
1373typedef struct dot11_obss_ie dot11_obss_ie_t;
1374#define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t)
1375
1376
1377BWL_PRE_PACKED_STRUCT struct vndr_ie {
1378 uchar id;
1379 uchar len;
1380 uchar oui [3];
1381 uchar data [1];
1382} BWL_POST_PACKED_STRUCT;
1383typedef struct vndr_ie vndr_ie_t;
1384
1385#define VNDR_IE_HDR_LEN 2
1386#define VNDR_IE_MIN_LEN 3
1387#define VNDR_IE_MAX_LEN 256
1388
1389
1390#define WPA_VERSION 1
1391#define WPA_OUI "\x00\x50\xF2"
1392
1393#define WPA2_VERSION 1
1394#define WPA2_VERSION_LEN 2
1395#define WPA2_OUI "\x00\x0F\xAC"
1396
1397#define WPA_OUI_LEN 3
1398
1399
1400#define RSN_AKM_NONE 0
1401#define RSN_AKM_UNSPECIFIED 1
1402#define RSN_AKM_PSK 2
1403
1404
1405#define DOT11_MAX_DEFAULT_KEYS 4
1406#define DOT11_MAX_KEY_SIZE 32
1407#define DOT11_MAX_IV_SIZE 16
1408#define DOT11_EXT_IV_FLAG (1<<5)
1409#define DOT11_WPA_KEY_RSC_LEN 8
1410
1411#define WEP1_KEY_SIZE 5
1412#define WEP1_KEY_HEX_SIZE 10
1413#define WEP128_KEY_SIZE 13
1414#define WEP128_KEY_HEX_SIZE 26
1415#define TKIP_MIC_SIZE 8
1416#define TKIP_EOM_SIZE 7
1417#define TKIP_EOM_FLAG 0x5a
1418#define TKIP_KEY_SIZE 32
1419#define TKIP_MIC_AUTH_TX 16
1420#define TKIP_MIC_AUTH_RX 24
1421#define TKIP_MIC_SUP_RX TKIP_MIC_AUTH_TX
1422#define TKIP_MIC_SUP_TX TKIP_MIC_AUTH_RX
1423#define AES_KEY_SIZE 16
1424#define AES_MIC_SIZE 8
1425
1426#define SMS4_KEY_LEN 16
1427#define SMS4_WPI_CBC_MAC_LEN 16
1428
1429
1430#include <packed_section_end.h>
1431
1432
1433#endif
diff --git a/drivers/net/wireless/bcm4329/include/proto/802.11e.h b/drivers/net/wireless/bcm4329/include/proto/802.11e.h
new file mode 100644
index 00000000000..1dd6f45b1ed
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/proto/802.11e.h
@@ -0,0 +1,131 @@
1/*
2 * 802.11e protocol header file
3 *
4 * Copyright (C) 1999-2010, 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.5.56.1 2008/11/20 00:51:18 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/bcm4329/include/proto/802.1d.h b/drivers/net/wireless/bcm4329/include/proto/802.1d.h
new file mode 100644
index 00000000000..45c728bc297
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/proto/802.1d.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 1999-2010, 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/bcm4329/include/proto/bcmeth.h b/drivers/net/wireless/bcm4329/include/proto/bcmeth.h
new file mode 100644
index 00000000000..fdb5a2a5648
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/proto/bcmeth.h
@@ -0,0 +1,83 @@
1/*
2 * Broadcom Ethernettype protocol definitions
3 *
4 * Copyright (C) 1999-2010, 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.9.46.1 2008/11/20 00:51:20 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/bcm4329/include/proto/bcmevent.h b/drivers/net/wireless/bcm4329/include/proto/bcmevent.h
new file mode 100644
index 00000000000..1f8ecb14d97
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/proto/bcmevent.h
@@ -0,0 +1,212 @@
1/*
2 * Broadcom Event protocol definitions
3 *
4 * Copyright (C) 1999-2010, 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 *
25 * Dependencies: proto/bcmeth.h
26 *
27 * $Id: bcmevent.h,v 9.34.4.1.20.16.64.1 2010/11/08 21:57:03 Exp $
28 *
29 */
30
31
32
33
34#ifndef _BCMEVENT_H_
35#define _BCMEVENT_H_
36
37#ifndef _TYPEDEFS_H_
38#include <typedefs.h>
39#endif
40
41
42#include <packed_section_start.h>
43
44#define BCM_EVENT_MSG_VERSION 1
45#define BCM_MSG_IFNAME_MAX 16
46
47
48#define WLC_EVENT_MSG_LINK 0x01
49#define WLC_EVENT_MSG_FLUSHTXQ 0x02
50#define WLC_EVENT_MSG_GROUP 0x04
51
52
53typedef BWL_PRE_PACKED_STRUCT struct
54{
55 uint16 version;
56 uint16 flags;
57 uint32 event_type;
58 uint32 status;
59 uint32 reason;
60 uint32 auth_type;
61 uint32 datalen;
62 struct ether_addr addr;
63 char ifname[BCM_MSG_IFNAME_MAX];
64} BWL_POST_PACKED_STRUCT wl_event_msg_t;
65
66
67typedef BWL_PRE_PACKED_STRUCT struct bcm_event {
68 struct ether_header eth;
69 bcmeth_hdr_t bcm_hdr;
70 wl_event_msg_t event;
71
72} BWL_POST_PACKED_STRUCT bcm_event_t;
73
74#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - sizeof(struct ether_header))
75
76
77#define WLC_E_SET_SSID 0
78#define WLC_E_JOIN 1
79#define WLC_E_START 2
80#define WLC_E_AUTH 3
81#define WLC_E_AUTH_IND 4
82#define WLC_E_DEAUTH 5
83#define WLC_E_DEAUTH_IND 6
84#define WLC_E_ASSOC 7
85#define WLC_E_ASSOC_IND 8
86#define WLC_E_REASSOC 9
87#define WLC_E_REASSOC_IND 10
88#define WLC_E_DISASSOC 11
89#define WLC_E_DISASSOC_IND 12
90#define WLC_E_QUIET_START 13
91#define WLC_E_QUIET_END 14
92#define WLC_E_BEACON_RX 15
93#define WLC_E_LINK 16
94#define WLC_E_MIC_ERROR 17
95#define WLC_E_NDIS_LINK 18
96#define WLC_E_ROAM 19
97#define WLC_E_TXFAIL 20
98#define WLC_E_PMKID_CACHE 21
99#define WLC_E_RETROGRADE_TSF 22
100#define WLC_E_PRUNE 23
101#define WLC_E_AUTOAUTH 24
102#define WLC_E_EAPOL_MSG 25
103#define WLC_E_SCAN_COMPLETE 26
104#define WLC_E_ADDTS_IND 27
105#define WLC_E_DELTS_IND 28
106#define WLC_E_BCNSENT_IND 29
107#define WLC_E_BCNRX_MSG 30
108#define WLC_E_BCNLOST_MSG 31
109#define WLC_E_ROAM_PREP 32
110#define WLC_E_PFN_NET_FOUND 33
111#define WLC_E_PFN_NET_LOST 34
112#define WLC_E_RESET_COMPLETE 35
113#define WLC_E_JOIN_START 36
114#define WLC_E_ROAM_START 37
115#define WLC_E_ASSOC_START 38
116#define WLC_E_IBSS_ASSOC 39
117#define WLC_E_RADIO 40
118#define WLC_E_PSM_WATCHDOG 41
119#define WLC_E_PROBREQ_MSG 44
120#define WLC_E_SCAN_CONFIRM_IND 45
121#define WLC_E_PSK_SUP 46
122#define WLC_E_COUNTRY_CODE_CHANGED 47
123#define WLC_E_EXCEEDED_MEDIUM_TIME 48
124#define WLC_E_ICV_ERROR 49
125#define WLC_E_UNICAST_DECODE_ERROR 50
126#define WLC_E_MULTICAST_DECODE_ERROR 51
127#define WLC_E_TRACE 52
128#define WLC_E_IF 54
129#define WLC_E_RSSI 56
130#define WLC_E_PFN_SCAN_COMPLETE 57
131#define WLC_E_ACTION_FRAME 58
132#define WLC_E_ACTION_FRAME_COMPLETE 59
133
134#define WLC_E_ESCAN_RESULT 69
135#define WLC_E_WAKE_EVENT 70
136#define WLC_E_RELOAD 71
137#define WLC_E_LAST 72
138
139
140
141#define WLC_E_STATUS_SUCCESS 0
142#define WLC_E_STATUS_FAIL 1
143#define WLC_E_STATUS_TIMEOUT 2
144#define WLC_E_STATUS_NO_NETWORKS 3
145#define WLC_E_STATUS_ABORT 4
146#define WLC_E_STATUS_NO_ACK 5
147#define WLC_E_STATUS_UNSOLICITED 6
148#define WLC_E_STATUS_ATTEMPT 7
149#define WLC_E_STATUS_PARTIAL 8
150#define WLC_E_STATUS_NEWSCAN 9
151#define WLC_E_STATUS_NEWASSOC 10
152#define WLC_E_STATUS_11HQUIET 11
153#define WLC_E_STATUS_SUPPRESS 12
154#define WLC_E_STATUS_NOCHANS 13
155#define WLC_E_STATUS_CCXFASTRM 14
156#define WLC_E_STATUS_CS_ABORT 15
157
158
159#define WLC_E_REASON_INITIAL_ASSOC 0
160#define WLC_E_REASON_LOW_RSSI 1
161#define WLC_E_REASON_DEAUTH 2
162#define WLC_E_REASON_DISASSOC 3
163#define WLC_E_REASON_BCNS_LOST 4
164#define WLC_E_REASON_FAST_ROAM_FAILED 5
165#define WLC_E_REASON_DIRECTED_ROAM 6
166#define WLC_E_REASON_TSPEC_REJECTED 7
167#define WLC_E_REASON_BETTER_AP 8
168
169
170#define WLC_E_PRUNE_ENCR_MISMATCH 1
171#define WLC_E_PRUNE_BCAST_BSSID 2
172#define WLC_E_PRUNE_MAC_DENY 3
173#define WLC_E_PRUNE_MAC_NA 4
174#define WLC_E_PRUNE_REG_PASSV 5
175#define WLC_E_PRUNE_SPCT_MGMT 6
176#define WLC_E_PRUNE_RADAR 7
177#define WLC_E_RSN_MISMATCH 8
178#define WLC_E_PRUNE_NO_COMMON_RATES 9
179#define WLC_E_PRUNE_BASIC_RATES 10
180#define WLC_E_PRUNE_CIPHER_NA 12
181#define WLC_E_PRUNE_KNOWN_STA 13
182#define WLC_E_PRUNE_WDS_PEER 15
183#define WLC_E_PRUNE_QBSS_LOAD 16
184#define WLC_E_PRUNE_HOME_AP 17
185
186
187#define WLC_E_SUP_OTHER 0
188#define WLC_E_SUP_DECRYPT_KEY_DATA 1
189#define WLC_E_SUP_BAD_UCAST_WEP128 2
190#define WLC_E_SUP_BAD_UCAST_WEP40 3
191#define WLC_E_SUP_UNSUP_KEY_LEN 4
192#define WLC_E_SUP_PW_KEY_CIPHER 5
193#define WLC_E_SUP_MSG3_TOO_MANY_IE 6
194#define WLC_E_SUP_MSG3_IE_MISMATCH 7
195#define WLC_E_SUP_NO_INSTALL_FLAG 8
196#define WLC_E_SUP_MSG3_NO_GTK 9
197#define WLC_E_SUP_GRP_KEY_CIPHER 10
198#define WLC_E_SUP_GRP_MSG1_NO_GTK 11
199#define WLC_E_SUP_GTK_DECRYPT_FAIL 12
200#define WLC_E_SUP_SEND_FAIL 13
201#define WLC_E_SUP_DEAUTH 14
202#define WLC_E_SUP_WPA_PSK_TMO 15
203
204
205#define WLC_E_IF_ADD 1
206#define WLC_E_IF_DEL 2
207
208#define WLC_E_RELOAD_STATUS1 1
209
210#include <packed_section_end.h>
211
212#endif
diff --git a/drivers/net/wireless/bcm4329/include/proto/bcmip.h b/drivers/net/wireless/bcm4329/include/proto/bcmip.h
new file mode 100644
index 00000000000..9d2fd6fba48
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/proto/bcmip.h
@@ -0,0 +1,157 @@
1/*
2 * Copyright (C) 1999-2010, 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.16.186.4 2009/01/27 04:25:25 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#ifndef IP_TOS
148#define IP_TOS(ip_body) \
149 (IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \
150 IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0)
151#endif
152
153
154
155#include <packed_section_end.h>
156
157#endif
diff --git a/drivers/net/wireless/bcm4329/include/proto/eapol.h b/drivers/net/wireless/bcm4329/include/proto/eapol.h
new file mode 100644
index 00000000000..95e76ff18c6
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/proto/eapol.h
@@ -0,0 +1,172 @@
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.18.260.1.2.1.6.6 2009/04/08 05:00:08 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#define AKW_BLOCK_LEN 8 /* The only def we need here */
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_ID_LEN 8
85#define EAPOL_WPA_KEY_RSC_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_PAIRWISE 0x08
111#define WPA_KEY_INSTALL 0x40
112#define WPA_KEY_ACK 0x80
113#define WPA_KEY_MIC 0x100
114#define WPA_KEY_SECURE 0x200
115#define WPA_KEY_ERROR 0x400
116#define WPA_KEY_REQ 0x800
117
118/* WPA-only KEY KEY_INFO bits */
119#define WPA_KEY_INDEX_0 0x00
120#define WPA_KEY_INDEX_1 0x10
121#define WPA_KEY_INDEX_2 0x20
122#define WPA_KEY_INDEX_3 0x30
123#define WPA_KEY_INDEX_MASK 0x30
124#define WPA_KEY_INDEX_SHIFT 0x04
125
126/* 802.11i/WPA2-only KEY KEY_INFO bits */
127#define WPA_KEY_ENCRYPTED_DATA 0x1000
128
129/* Key Data encapsulation */
130typedef BWL_PRE_PACKED_STRUCT struct {
131 uint8 type;
132 uint8 length;
133 uint8 oui[3];
134 uint8 subtype;
135 uint8 data[1];
136} BWL_POST_PACKED_STRUCT eapol_wpa2_encap_data_t;
137
138#define EAPOL_WPA2_ENCAP_DATA_HDR_LEN 6
139
140#define WPA2_KEY_DATA_SUBTYPE_GTK 1
141#define WPA2_KEY_DATA_SUBTYPE_STAKEY 2
142#define WPA2_KEY_DATA_SUBTYPE_MAC 3
143#define WPA2_KEY_DATA_SUBTYPE_PMKID 4
144
145/* GTK encapsulation */
146typedef BWL_PRE_PACKED_STRUCT struct {
147 uint8 flags;
148 uint8 reserved;
149 uint8 gtk[EAPOL_WPA_MAX_KEY_SIZE];
150} BWL_POST_PACKED_STRUCT eapol_wpa2_key_gtk_encap_t;
151
152#define EAPOL_WPA2_KEY_GTK_ENCAP_HDR_LEN 2
153
154#define WPA2_GTK_INDEX_MASK 0x03
155#define WPA2_GTK_INDEX_SHIFT 0x00
156
157#define WPA2_GTK_TRANSMIT 0x04
158
159/* STAKey encapsulation */
160typedef BWL_PRE_PACKED_STRUCT struct {
161 uint8 reserved[2];
162 uint8 mac[ETHER_ADDR_LEN];
163 uint8 stakey[EAPOL_WPA_MAX_KEY_SIZE];
164} BWL_POST_PACKED_STRUCT eapol_wpa2_key_stakey_encap_t;
165
166#define WPA2_KEY_DATA_PAD 0xdd
167
168
169/* This marks the end of a packed structure section. */
170#include <packed_section_end.h>
171
172#endif /* _eapol_h_ */
diff --git a/drivers/net/wireless/bcm4329/include/proto/ethernet.h b/drivers/net/wireless/bcm4329/include/proto/ethernet.h
new file mode 100644
index 00000000000..9ad2ea0c70f
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/proto/ethernet.h
@@ -0,0 +1,148 @@
1/*
2 * From FreeBSD 2.2.7: Fundamental constants relating to ethernet.
3 *
4 * Copyright (C) 1999-2010, 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.45.56.5 2010/02/22 22:04:36 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_WAI 0x88b4
71#ifdef BCMWPA2
72#define ETHER_TYPE_802_1X_PREAUTH 0x88c7
73#endif
74
75
76#define ETHER_BRCM_SUBTYPE_LEN 4
77#define ETHER_BRCM_CRAM 1
78
79
80#define ETHER_DEST_OFFSET (0 * ETHER_ADDR_LEN)
81#define ETHER_SRC_OFFSET (1 * ETHER_ADDR_LEN)
82#define ETHER_TYPE_OFFSET (2 * ETHER_ADDR_LEN)
83
84
85#define ETHER_IS_VALID_LEN(foo) \
86 ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN)
87
88
89#ifndef __INCif_etherh
90
91BWL_PRE_PACKED_STRUCT struct ether_header {
92 uint8 ether_dhost[ETHER_ADDR_LEN];
93 uint8 ether_shost[ETHER_ADDR_LEN];
94 uint16 ether_type;
95} BWL_POST_PACKED_STRUCT;
96
97
98BWL_PRE_PACKED_STRUCT struct ether_addr {
99 uint8 octet[ETHER_ADDR_LEN];
100} BWL_POST_PACKED_STRUCT;
101#endif
102
103
104#define ETHER_SET_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] | 2))
105#define ETHER_IS_LOCALADDR(ea) (((uint8 *)(ea))[0] & 2)
106#define ETHER_CLR_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & 0xd))
107#define ETHER_TOGGLE_LOCALADDR(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] ^ 2))
108
109
110#define ETHER_SET_UNICAST(ea) (((uint8 *)(ea))[0] = (((uint8 *)(ea))[0] & ~1))
111
112
113#define ETHER_ISMULTI(ea) (((const uint8 *)(ea))[0] & 1)
114
115
116
117#define ether_cmp(a, b) (!(((short*)a)[0] == ((short*)b)[0]) | \
118 !(((short*)a)[1] == ((short*)b)[1]) | \
119 !(((short*)a)[2] == ((short*)b)[2]))
120
121
122#define ether_copy(s, d) { \
123 ((short*)d)[0] = ((short*)s)[0]; \
124 ((short*)d)[1] = ((short*)s)[1]; \
125 ((short*)d)[2] = ((short*)s)[2]; }
126
127
128static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}};
129static const struct ether_addr ether_null = {{0, 0, 0, 0, 0, 0}};
130
131#define ETHER_ISBCAST(ea) ((((uint8 *)(ea))[0] & \
132 ((uint8 *)(ea))[1] & \
133 ((uint8 *)(ea))[2] & \
134 ((uint8 *)(ea))[3] & \
135 ((uint8 *)(ea))[4] & \
136 ((uint8 *)(ea))[5]) == 0xff)
137#define ETHER_ISNULLADDR(ea) ((((uint8 *)(ea))[0] | \
138 ((uint8 *)(ea))[1] | \
139 ((uint8 *)(ea))[2] | \
140 ((uint8 *)(ea))[3] | \
141 ((uint8 *)(ea))[4] | \
142 ((uint8 *)(ea))[5]) == 0)
143
144
145
146#include <packed_section_end.h>
147
148#endif
diff --git a/drivers/net/wireless/bcm4329/include/proto/sdspi.h b/drivers/net/wireless/bcm4329/include/proto/sdspi.h
new file mode 100644
index 00000000000..7739e68a244
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/proto/sdspi.h
@@ -0,0 +1,71 @@
1/*
2 * SD-SPI Protocol Standard
3 *
4 * Copyright (C) 1999-2010, 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.1.20.1 2008/05/06 22:59:19 Exp $
25 */
26
27#define SPI_START_M BITFIELD_MASK(1) /* Bit [31] - Start Bit */
28#define SPI_START_S 31
29#define SPI_DIR_M BITFIELD_MASK(1) /* Bit [30] - Direction */
30#define SPI_DIR_S 30
31#define SPI_CMD_INDEX_M BITFIELD_MASK(6) /* Bits [29:24] - Command number */
32#define SPI_CMD_INDEX_S 24
33#define SPI_RW_M BITFIELD_MASK(1) /* Bit [23] - Read=0, Write=1 */
34#define SPI_RW_S 23
35#define SPI_FUNC_M BITFIELD_MASK(3) /* Bits [22:20] - Function Number */
36#define SPI_FUNC_S 20
37#define SPI_RAW_M BITFIELD_MASK(1) /* Bit [19] - Read After Wr */
38#define SPI_RAW_S 19
39#define SPI_STUFF_M BITFIELD_MASK(1) /* Bit [18] - Stuff bit */
40#define SPI_STUFF_S 18
41#define SPI_BLKMODE_M BITFIELD_MASK(1) /* Bit [19] - Blockmode 1=blk */
42#define SPI_BLKMODE_S 19
43#define SPI_OPCODE_M BITFIELD_MASK(1) /* Bit [18] - OP Code */
44#define SPI_OPCODE_S 18
45#define SPI_ADDR_M BITFIELD_MASK(17) /* Bits [17:1] - Address */
46#define SPI_ADDR_S 1
47#define SPI_STUFF0_M BITFIELD_MASK(1) /* Bit [0] - Stuff bit */
48#define SPI_STUFF0_S 0
49
50#define SPI_RSP_START_M BITFIELD_MASK(1) /* Bit [7] - Start Bit (always 0) */
51#define SPI_RSP_START_S 7
52#define SPI_RSP_PARAM_ERR_M BITFIELD_MASK(1) /* Bit [6] - Parameter Error */
53#define SPI_RSP_PARAM_ERR_S 6
54#define SPI_RSP_RFU5_M BITFIELD_MASK(1) /* Bit [5] - RFU (Always 0) */
55#define SPI_RSP_RFU5_S 5
56#define SPI_RSP_FUNC_ERR_M BITFIELD_MASK(1) /* Bit [4] - Function number error */
57#define SPI_RSP_FUNC_ERR_S 4
58#define SPI_RSP_CRC_ERR_M BITFIELD_MASK(1) /* Bit [3] - COM CRC Error */
59#define SPI_RSP_CRC_ERR_S 3
60#define SPI_RSP_ILL_CMD_M BITFIELD_MASK(1) /* Bit [2] - Illegal Command error */
61#define SPI_RSP_ILL_CMD_S 2
62#define SPI_RSP_RFU1_M BITFIELD_MASK(1) /* Bit [1] - RFU (Always 0) */
63#define SPI_RSP_RFU1_S 1
64#define SPI_RSP_IDLE_M BITFIELD_MASK(1) /* Bit [0] - In idle state */
65#define SPI_RSP_IDLE_S 0
66
67/* SD-SPI Protocol Definitions */
68#define SDSPI_COMMAND_LEN 6 /* Number of bytes in an SD command */
69#define SDSPI_START_BLOCK 0xFE /* SD Start Block Token */
70#define SDSPI_IDLE_PAD 0xFF /* SD-SPI idle value for MOSI */
71#define SDSPI_START_BIT_MASK 0x80
diff --git a/drivers/net/wireless/bcm4329/include/proto/vlan.h b/drivers/net/wireless/bcm4329/include/proto/vlan.h
new file mode 100644
index 00000000000..670bc44c6bd
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/proto/vlan.h
@@ -0,0 +1,63 @@
1/*
2 * 802.1Q VLAN protocol definitions
3 *
4 * Copyright (C) 1999-2010, 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.4.196.2 2008/12/07 21:19:20 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#endif
diff --git a/drivers/net/wireless/bcm4329/include/proto/wpa.h b/drivers/net/wireless/bcm4329/include/proto/wpa.h
new file mode 100644
index 00000000000..f5d0cd53977
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/proto/wpa.h
@@ -0,0 +1,159 @@
1/*
2 * Fundamental types and constants relating to WPA
3 *
4 * Copyright (C) 1999-2010, 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.16.166.1.20.1 2008/11/20 00:51:31 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#define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \
119 (cipher) == WPA_CIPHER_WEP_40 || \
120 (cipher) == WPA_CIPHER_WEP_104 || \
121 (cipher) == WPA_CIPHER_TKIP || \
122 (cipher) == WPA_CIPHER_AES_OCB || \
123 (cipher) == WPA_CIPHER_AES_CCM)
124
125
126#define WPA_TKIP_CM_DETECT 60
127#define WPA_TKIP_CM_BLOCK 60
128
129
130#define RSN_CAP_LEN 2
131
132
133#define RSN_CAP_PREAUTH 0x0001
134#define RSN_CAP_NOPAIRWISE 0x0002
135#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
136#define RSN_CAP_PTK_REPLAY_CNTR_SHIFT 2
137#define RSN_CAP_GTK_REPLAY_CNTR_MASK 0x0030
138#define RSN_CAP_GTK_REPLAY_CNTR_SHIFT 4
139#define RSN_CAP_1_REPLAY_CNTR 0
140#define RSN_CAP_2_REPLAY_CNTRS 1
141#define RSN_CAP_4_REPLAY_CNTRS 2
142#define RSN_CAP_16_REPLAY_CNTRS 3
143
144
145#define WPA_CAP_4_REPLAY_CNTRS RSN_CAP_4_REPLAY_CNTRS
146#define WPA_CAP_16_REPLAY_CNTRS RSN_CAP_16_REPLAY_CNTRS
147#define WPA_CAP_REPLAY_CNTR_SHIFT RSN_CAP_PTK_REPLAY_CNTR_SHIFT
148#define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK
149
150
151#define WPA_CAP_LEN RSN_CAP_LEN
152
153#define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH
154
155
156
157#include <packed_section_end.h>
158
159#endif
diff --git a/drivers/net/wireless/bcm4329/include/sbchipc.h b/drivers/net/wireless/bcm4329/include/sbchipc.h
new file mode 100644
index 00000000000..39e5c8d6aed
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/sbchipc.h
@@ -0,0 +1,1026 @@
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.103.2.5.4.5.2.9 2009/07/03 14:23:21 Exp $
9 *
10 * Copyright (C) 1999-2010, 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 PAD;
55
56
57 uint32 intstatus;
58 uint32 intmask;
59 uint32 chipcontrol;
60 uint32 chipstatus;
61
62
63 uint32 jtagcmd;
64 uint32 jtagir;
65 uint32 jtagdr;
66 uint32 jtagctrl;
67
68
69 uint32 flashcontrol;
70 uint32 flashaddress;
71 uint32 flashdata;
72 uint32 PAD[1];
73
74
75 uint32 broadcastaddress;
76 uint32 broadcastdata;
77
78
79 uint32 gpiopullup;
80 uint32 gpiopulldown;
81 uint32 gpioin;
82 uint32 gpioout;
83 uint32 gpioouten;
84 uint32 gpiocontrol;
85 uint32 gpiointpolarity;
86 uint32 gpiointmask;
87
88
89 uint32 gpioevent;
90 uint32 gpioeventintmask;
91
92
93 uint32 watchdog;
94
95
96 uint32 gpioeventintpolarity;
97
98
99 uint32 gpiotimerval;
100 uint32 gpiotimeroutmask;
101
102
103 uint32 clockcontrol_n;
104 uint32 clockcontrol_sb;
105 uint32 clockcontrol_pci;
106 uint32 clockcontrol_m2;
107 uint32 clockcontrol_m3;
108 uint32 clkdiv;
109 uint32 PAD[2];
110
111
112 uint32 pll_on_delay;
113 uint32 fref_sel_delay;
114 uint32 slow_clk_ctl;
115 uint32 PAD[1];
116
117
118 uint32 system_clk_ctl;
119 uint32 clkstatestretch;
120 uint32 PAD[13];
121
122
123 uint32 eromptr;
124
125
126 uint32 pcmcia_config;
127 uint32 pcmcia_memwait;
128 uint32 pcmcia_attrwait;
129 uint32 pcmcia_iowait;
130 uint32 ide_config;
131 uint32 ide_memwait;
132 uint32 ide_attrwait;
133 uint32 ide_iowait;
134 uint32 prog_config;
135 uint32 prog_waitcount;
136 uint32 flash_config;
137 uint32 flash_waitcount;
138 uint32 PAD[4];
139 uint32 PAD[40];
140
141
142
143 uint32 clk_ctl_st;
144 uint32 hw_war;
145 uint32 PAD[70];
146
147
148 uint8 uart0data;
149 uint8 uart0imr;
150 uint8 uart0fcr;
151 uint8 uart0lcr;
152 uint8 uart0mcr;
153 uint8 uart0lsr;
154 uint8 uart0msr;
155 uint8 uart0scratch;
156 uint8 PAD[248];
157
158 uint8 uart1data;
159 uint8 uart1imr;
160 uint8 uart1fcr;
161 uint8 uart1lcr;
162 uint8 uart1mcr;
163 uint8 uart1lsr;
164 uint8 uart1msr;
165 uint8 uart1scratch;
166 uint32 PAD[126];
167
168
169 uint32 pmucontrol;
170 uint32 pmucapabilities;
171 uint32 pmustatus;
172 uint32 res_state;
173 uint32 res_pending;
174 uint32 pmutimer;
175 uint32 min_res_mask;
176 uint32 max_res_mask;
177 uint32 res_table_sel;
178 uint32 res_dep_mask;
179 uint32 res_updn_timer;
180 uint32 res_timer;
181 uint32 clkstretch;
182 uint32 pmuwatchdog;
183 uint32 gpiosel;
184 uint32 gpioenable;
185 uint32 res_req_timer_sel;
186 uint32 res_req_timer;
187 uint32 res_req_mask;
188 uint32 PAD;
189 uint32 chipcontrol_addr;
190 uint32 chipcontrol_data;
191 uint32 regcontrol_addr;
192 uint32 regcontrol_data;
193 uint32 pllcontrol_addr;
194 uint32 pllcontrol_data;
195 uint32 PAD[102];
196 uint16 otp[768];
197} chipcregs_t;
198
199#endif
200
201#define CC_CHIPID 0
202#define CC_CAPABILITIES 4
203#define CC_OTPST 0x10
204#define CC_CHIPST 0x2c
205#define CC_JTAGCMD 0x30
206#define CC_JTAGIR 0x34
207#define CC_JTAGDR 0x38
208#define CC_JTAGCTRL 0x3c
209#define CC_WATCHDOG 0x80
210#define CC_CLKC_N 0x90
211#define CC_CLKC_M0 0x94
212#define CC_CLKC_M1 0x98
213#define CC_CLKC_M2 0x9c
214#define CC_CLKC_M3 0xa0
215#define CC_CLKDIV 0xa4
216#define CC_SYS_CLK_CTL 0xc0
217#define CC_CLK_CTL_ST SI_CLK_CTL_ST
218#define CC_EROMPTR 0xfc
219#define PMU_CTL 0x600
220#define PMU_CAP 0x604
221#define PMU_ST 0x608
222#define PMU_RES_STATE 0x60c
223#define PMU_TIMER 0x614
224#define PMU_MIN_RES_MASK 0x618
225#define PMU_MAX_RES_MASK 0x61c
226#define PMU_REG_CONTROL_ADDR 0x658
227#define PMU_REG_CONTROL_DATA 0x65C
228#define PMU_PLL_CONTROL_ADDR 0x660
229#define PMU_PLL_CONTROL_DATA 0x664
230#define CC_OTP 0x800
231
232
233#define CID_ID_MASK 0x0000ffff
234#define CID_REV_MASK 0x000f0000
235#define CID_REV_SHIFT 16
236#define CID_PKG_MASK 0x00f00000
237#define CID_PKG_SHIFT 20
238#define CID_CC_MASK 0x0f000000
239#define CID_CC_SHIFT 24
240#define CID_TYPE_MASK 0xf0000000
241#define CID_TYPE_SHIFT 28
242
243
244#define CC_CAP_UARTS_MASK 0x00000003
245#define CC_CAP_MIPSEB 0x00000004
246#define CC_CAP_UCLKSEL 0x00000018
247#define CC_CAP_UINTCLK 0x00000008
248#define CC_CAP_UARTGPIO 0x00000020
249#define CC_CAP_EXTBUS_MASK 0x000000c0
250#define CC_CAP_EXTBUS_NONE 0x00000000
251#define CC_CAP_EXTBUS_FULL 0x00000040
252#define CC_CAP_EXTBUS_PROG 0x00000080
253#define CC_CAP_FLASH_MASK 0x00000700
254#define CC_CAP_PLL_MASK 0x00038000
255#define CC_CAP_PWR_CTL 0x00040000
256#define CC_CAP_OTPSIZE 0x00380000
257#define CC_CAP_OTPSIZE_SHIFT 19
258#define CC_CAP_OTPSIZE_BASE 5
259#define CC_CAP_JTAGP 0x00400000
260#define CC_CAP_ROM 0x00800000
261#define CC_CAP_BKPLN64 0x08000000
262#define CC_CAP_PMU 0x10000000
263#define CC_CAP_ECI 0x20000000
264
265
266#define PLL_NONE 0x00000000
267#define PLL_TYPE1 0x00010000
268#define PLL_TYPE2 0x00020000
269#define PLL_TYPE3 0x00030000
270#define PLL_TYPE4 0x00008000
271#define PLL_TYPE5 0x00018000
272#define PLL_TYPE6 0x00028000
273#define PLL_TYPE7 0x00038000
274
275
276#define ILP_CLOCK 32000
277
278
279#define ALP_CLOCK 20000000
280
281
282#define HT_CLOCK 80000000
283
284
285#define CC_UARTCLKO 0x00000001
286#define CC_SE 0x00000002
287#define CC_UARTCLKEN 0x00000008
288
289
290#define CHIPCTRL_4321A0_DEFAULT 0x3a4
291#define CHIPCTRL_4321A1_DEFAULT 0x0a4
292#define CHIPCTRL_4321_PLL_DOWN 0x800000
293
294
295#define OTPS_OL_MASK 0x000000ff
296#define OTPS_OL_MFG 0x00000001
297#define OTPS_OL_OR1 0x00000002
298#define OTPS_OL_OR2 0x00000004
299#define OTPS_OL_GU 0x00000008
300#define OTPS_GUP_MASK 0x00000f00
301#define OTPS_GUP_SHIFT 8
302#define OTPS_GUP_HW 0x00000100
303#define OTPS_GUP_SW 0x00000200
304#define OTPS_GUP_CI 0x00000400
305#define OTPS_GUP_FUSE 0x00000800
306#define OTPS_READY 0x00001000
307#define OTPS_RV(x) (1 << (16 + (x)))
308#define OTPS_RV_MASK 0x0fff0000
309
310
311#define OTPC_PROGSEL 0x00000001
312#define OTPC_PCOUNT_MASK 0x0000000e
313#define OTPC_PCOUNT_SHIFT 1
314#define OTPC_VSEL_MASK 0x000000f0
315#define OTPC_VSEL_SHIFT 4
316#define OTPC_TMM_MASK 0x00000700
317#define OTPC_TMM_SHIFT 8
318#define OTPC_ODM 0x00000800
319#define OTPC_PROGEN 0x80000000
320
321
322#define OTPP_COL_MASK 0x000000ff
323#define OTPP_COL_SHIFT 0
324#define OTPP_ROW_MASK 0x0000ff00
325#define OTPP_ROW_SHIFT 8
326#define OTPP_OC_MASK 0x0f000000
327#define OTPP_OC_SHIFT 24
328#define OTPP_READERR 0x10000000
329#define OTPP_VALUE_MASK 0x20000000
330#define OTPP_VALUE_SHIFT 29
331#define OTPP_START_BUSY 0x80000000
332
333
334#define OTPPOC_READ 0
335#define OTPPOC_BIT_PROG 1
336#define OTPPOC_VERIFY 3
337#define OTPPOC_INIT 4
338#define OTPPOC_SET 5
339#define OTPPOC_RESET 6
340#define OTPPOC_OCST 7
341#define OTPPOC_ROW_LOCK 8
342#define OTPPOC_PRESCN_TEST 9
343
344
345#define JCMD_START 0x80000000
346#define JCMD_BUSY 0x80000000
347#define JCMD_STATE_MASK 0x60000000
348#define JCMD_STATE_TLR 0x00000000
349#define JCMD_STATE_PIR 0x20000000
350#define JCMD_STATE_PDR 0x40000000
351#define JCMD_STATE_RTI 0x60000000
352#define JCMD0_ACC_MASK 0x0000f000
353#define JCMD0_ACC_IRDR 0x00000000
354#define JCMD0_ACC_DR 0x00001000
355#define JCMD0_ACC_IR 0x00002000
356#define JCMD0_ACC_RESET 0x00003000
357#define JCMD0_ACC_IRPDR 0x00004000
358#define JCMD0_ACC_PDR 0x00005000
359#define JCMD0_IRW_MASK 0x00000f00
360#define JCMD_ACC_MASK 0x000f0000
361#define JCMD_ACC_IRDR 0x00000000
362#define JCMD_ACC_DR 0x00010000
363#define JCMD_ACC_IR 0x00020000
364#define JCMD_ACC_RESET 0x00030000
365#define JCMD_ACC_IRPDR 0x00040000
366#define JCMD_ACC_PDR 0x00050000
367#define JCMD_ACC_PIR 0x00060000
368#define JCMD_ACC_IRDR_I 0x00070000
369#define JCMD_ACC_DR_I 0x00080000
370#define JCMD_IRW_MASK 0x00001f00
371#define JCMD_IRW_SHIFT 8
372#define JCMD_DRW_MASK 0x0000003f
373
374
375#define JCTRL_FORCE_CLK 4
376#define JCTRL_EXT_EN 2
377#define JCTRL_EN 1
378
379
380#define CLKD_SFLASH 0x0f000000
381#define CLKD_SFLASH_SHIFT 24
382#define CLKD_OTP 0x000f0000
383#define CLKD_OTP_SHIFT 16
384#define CLKD_JTAG 0x00000f00
385#define CLKD_JTAG_SHIFT 8
386#define CLKD_UART 0x000000ff
387
388
389#define CI_GPIO 0x00000001
390#define CI_EI 0x00000002
391#define CI_TEMP 0x00000004
392#define CI_SIRQ 0x00000008
393#define CI_ECI 0x00000010
394#define CI_PMU 0x00000020
395#define CI_UART 0x00000040
396#define CI_WDRESET 0x80000000
397
398
399#define SCC_SS_MASK 0x00000007
400#define SCC_SS_LPO 0x00000000
401#define SCC_SS_XTAL 0x00000001
402#define SCC_SS_PCI 0x00000002
403#define SCC_LF 0x00000200
404#define SCC_LP 0x00000400
405#define SCC_FS 0x00000800
406#define SCC_IP 0x00001000
407#define SCC_XC 0x00002000
408#define SCC_XP 0x00004000
409#define SCC_CD_MASK 0xffff0000
410#define SCC_CD_SHIFT 16
411
412
413#define SYCC_IE 0x00000001
414#define SYCC_AE 0x00000002
415#define SYCC_FP 0x00000004
416#define SYCC_AR 0x00000008
417#define SYCC_HR 0x00000010
418#define SYCC_CD_MASK 0xffff0000
419#define SYCC_CD_SHIFT 16
420
421
422#define CF_EN 0x00000001
423#define CF_EM_MASK 0x0000000e
424#define CF_EM_SHIFT 1
425#define CF_EM_FLASH 0
426#define CF_EM_SYNC 2
427#define CF_EM_PCMCIA 4
428#define CF_DS 0x00000010
429#define CF_BS 0x00000020
430#define CF_CD_MASK 0x000000c0
431#define CF_CD_SHIFT 6
432#define CF_CD_DIV2 0x00000000
433#define CF_CD_DIV3 0x00000040
434#define CF_CD_DIV4 0x00000080
435#define CF_CE 0x00000100
436#define CF_SB 0x00000200
437
438
439#define PM_W0_MASK 0x0000003f
440#define PM_W1_MASK 0x00001f00
441#define PM_W1_SHIFT 8
442#define PM_W2_MASK 0x001f0000
443#define PM_W2_SHIFT 16
444#define PM_W3_MASK 0x1f000000
445#define PM_W3_SHIFT 24
446
447
448#define PA_W0_MASK 0x0000003f
449#define PA_W1_MASK 0x00001f00
450#define PA_W1_SHIFT 8
451#define PA_W2_MASK 0x001f0000
452#define PA_W2_SHIFT 16
453#define PA_W3_MASK 0x1f000000
454#define PA_W3_SHIFT 24
455
456
457#define PI_W0_MASK 0x0000003f
458#define PI_W1_MASK 0x00001f00
459#define PI_W1_SHIFT 8
460#define PI_W2_MASK 0x001f0000
461#define PI_W2_SHIFT 16
462#define PI_W3_MASK 0x1f000000
463#define PI_W3_SHIFT 24
464
465
466#define PW_W0_MASK 0x0000001f
467#define PW_W1_MASK 0x00001f00
468#define PW_W1_SHIFT 8
469#define PW_W2_MASK 0x001f0000
470#define PW_W2_SHIFT 16
471#define PW_W3_MASK 0x1f000000
472#define PW_W3_SHIFT 24
473
474#define PW_W0 0x0000000c
475#define PW_W1 0x00000a00
476#define PW_W2 0x00020000
477#define PW_W3 0x01000000
478
479
480#define FW_W0_MASK 0x0000003f
481#define FW_W1_MASK 0x00001f00
482#define FW_W1_SHIFT 8
483#define FW_W2_MASK 0x001f0000
484#define FW_W2_SHIFT 16
485#define FW_W3_MASK 0x1f000000
486#define FW_W3_SHIFT 24
487
488
489#define WATCHDOG_CLOCK 48000000
490#define WATCHDOG_CLOCK_5354 32000
491
492
493#define PCTL_ILP_DIV_MASK 0xffff0000
494#define PCTL_ILP_DIV_SHIFT 16
495#define PCTL_PLL_PLLCTL_UPD 0x00000400
496#define PCTL_NOILP_ON_WAIT 0x00000200
497#define PCTL_HT_REQ_EN 0x00000100
498#define PCTL_ALP_REQ_EN 0x00000080
499#define PCTL_XTALFREQ_MASK 0x0000007c
500#define PCTL_XTALFREQ_SHIFT 2
501#define PCTL_ILP_DIV_EN 0x00000002
502#define PCTL_LPO_SEL 0x00000001
503
504
505#define CSTRETCH_HT 0xffff0000
506#define CSTRETCH_ALP 0x0000ffff
507
508
509#define GPIO_ONTIME_SHIFT 16
510
511
512#define CN_N1_MASK 0x3f
513#define CN_N2_MASK 0x3f00
514#define CN_N2_SHIFT 8
515#define CN_PLLC_MASK 0xf0000
516#define CN_PLLC_SHIFT 16
517
518
519#define CC_M1_MASK 0x3f
520#define CC_M2_MASK 0x3f00
521#define CC_M2_SHIFT 8
522#define CC_M3_MASK 0x3f0000
523#define CC_M3_SHIFT 16
524#define CC_MC_MASK 0x1f000000
525#define CC_MC_SHIFT 24
526
527
528#define CC_F6_2 0x02
529#define CC_F6_3 0x03
530#define CC_F6_4 0x05
531#define CC_F6_5 0x09
532#define CC_F6_6 0x11
533#define CC_F6_7 0x21
534
535#define CC_F5_BIAS 5
536
537#define CC_MC_BYPASS 0x08
538#define CC_MC_M1 0x04
539#define CC_MC_M1M2 0x02
540#define CC_MC_M1M2M3 0x01
541#define CC_MC_M1M3 0x11
542
543
544#define CC_T2_BIAS 2
545#define CC_T2M2_BIAS 3
546
547#define CC_T2MC_M1BYP 1
548#define CC_T2MC_M2BYP 2
549#define CC_T2MC_M3BYP 4
550
551
552#define CC_T6_MMASK 1
553#define CC_T6_M0 120000000
554#define CC_T6_M1 100000000
555#define SB2MIPS_T6(sb) (2 * (sb))
556
557
558#define CC_CLOCK_BASE1 24000000
559#define CC_CLOCK_BASE2 12500000
560
561
562#define CLKC_5350_N 0x0311
563#define CLKC_5350_M 0x04020009
564
565
566#define FLASH_NONE 0x000
567#define SFLASH_ST 0x100
568#define SFLASH_AT 0x200
569#define PFLASH 0x700
570
571
572#define CC_CFG_EN 0x0001
573#define CC_CFG_EM_MASK 0x000e
574#define CC_CFG_EM_ASYNC 0x0000
575#define CC_CFG_EM_SYNC 0x0002
576#define CC_CFG_EM_PCMCIA 0x0004
577#define CC_CFG_EM_IDE 0x0006
578#define CC_CFG_DS 0x0010
579#define CC_CFG_CD_MASK 0x00e0
580#define CC_CFG_CE 0x0100
581#define CC_CFG_SB 0x0200
582#define CC_CFG_IS 0x0400
583
584
585#define CC_EB_BASE 0x1a000000
586#define CC_EB_PCMCIA_MEM 0x1a000000
587#define CC_EB_PCMCIA_IO 0x1a200000
588#define CC_EB_PCMCIA_CFG 0x1a400000
589#define CC_EB_IDE 0x1a800000
590#define CC_EB_PCMCIA1_MEM 0x1a800000
591#define CC_EB_PCMCIA1_IO 0x1aa00000
592#define CC_EB_PCMCIA1_CFG 0x1ac00000
593#define CC_EB_PROGIF 0x1b000000
594
595
596
597#define SFLASH_OPCODE 0x000000ff
598#define SFLASH_ACTION 0x00000700
599#define SFLASH_CS_ACTIVE 0x00001000
600#define SFLASH_START 0x80000000
601#define SFLASH_BUSY SFLASH_START
602
603
604#define SFLASH_ACT_OPONLY 0x0000
605#define SFLASH_ACT_OP1D 0x0100
606#define SFLASH_ACT_OP3A 0x0200
607#define SFLASH_ACT_OP3A1D 0x0300
608#define SFLASH_ACT_OP3A4D 0x0400
609#define SFLASH_ACT_OP3A4X4D 0x0500
610#define SFLASH_ACT_OP3A1X4D 0x0700
611
612
613#define SFLASH_ST_WREN 0x0006
614#define SFLASH_ST_WRDIS 0x0004
615#define SFLASH_ST_RDSR 0x0105
616#define SFLASH_ST_WRSR 0x0101
617#define SFLASH_ST_READ 0x0303
618#define SFLASH_ST_PP 0x0302
619#define SFLASH_ST_SE 0x02d8
620#define SFLASH_ST_BE 0x00c7
621#define SFLASH_ST_DP 0x00b9
622#define SFLASH_ST_RES 0x03ab
623#define SFLASH_ST_CSA 0x1000
624
625
626#define SFLASH_ST_WIP 0x01
627#define SFLASH_ST_WEL 0x02
628#define SFLASH_ST_BP_MASK 0x1c
629#define SFLASH_ST_BP_SHIFT 2
630#define SFLASH_ST_SRWD 0x80
631
632
633#define SFLASH_AT_READ 0x07e8
634#define SFLASH_AT_PAGE_READ 0x07d2
635#define SFLASH_AT_BUF1_READ
636#define SFLASH_AT_BUF2_READ
637#define SFLASH_AT_STATUS 0x01d7
638#define SFLASH_AT_BUF1_WRITE 0x0384
639#define SFLASH_AT_BUF2_WRITE 0x0387
640#define SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283
641#define SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286
642#define SFLASH_AT_BUF1_PROGRAM 0x0288
643#define SFLASH_AT_BUF2_PROGRAM 0x0289
644#define SFLASH_AT_PAGE_ERASE 0x0281
645#define SFLASH_AT_BLOCK_ERASE 0x0250
646#define SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382
647#define SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385
648#define SFLASH_AT_BUF1_LOAD 0x0253
649#define SFLASH_AT_BUF2_LOAD 0x0255
650#define SFLASH_AT_BUF1_COMPARE 0x0260
651#define SFLASH_AT_BUF2_COMPARE 0x0261
652#define SFLASH_AT_BUF1_REPROGRAM 0x0258
653#define SFLASH_AT_BUF2_REPROGRAM 0x0259
654
655
656#define SFLASH_AT_READY 0x80
657#define SFLASH_AT_MISMATCH 0x40
658#define SFLASH_AT_ID_MASK 0x38
659#define SFLASH_AT_ID_SHIFT 3
660
661
662
663#define UART_RX 0
664#define UART_TX 0
665#define UART_DLL 0
666#define UART_IER 1
667#define UART_DLM 1
668#define UART_IIR 2
669#define UART_FCR 2
670#define UART_LCR 3
671#define UART_MCR 4
672#define UART_LSR 5
673#define UART_MSR 6
674#define UART_SCR 7
675#define UART_LCR_DLAB 0x80
676#define UART_LCR_WLEN8 0x03
677#define UART_MCR_OUT2 0x08
678#define UART_MCR_LOOP 0x10
679#define UART_LSR_RX_FIFO 0x80
680#define UART_LSR_TDHR 0x40
681#define UART_LSR_THRE 0x20
682#define UART_LSR_BREAK 0x10
683#define UART_LSR_FRAMING 0x08
684#define UART_LSR_PARITY 0x04
685#define UART_LSR_OVERRUN 0x02
686#define UART_LSR_RXRDY 0x01
687#define UART_FCR_FIFO_ENABLE 1
688
689
690#define UART_IIR_FIFO_MASK 0xc0
691#define UART_IIR_INT_MASK 0xf
692#define UART_IIR_MDM_CHG 0x0
693#define UART_IIR_NOINT 0x1
694#define UART_IIR_THRE 0x2
695#define UART_IIR_RCVD_DATA 0x4
696#define UART_IIR_RCVR_STATUS 0x6
697#define UART_IIR_CHAR_TIME 0xc
698
699
700#define UART_IER_EDSSI 8
701#define UART_IER_ELSI 4
702#define UART_IER_ETBEI 2
703#define UART_IER_ERBFI 1
704
705
706#define PST_INTPEND 0x0040
707#define PST_SBCLKST 0x0030
708#define PST_SBCLKST_ILP 0x0010
709#define PST_SBCLKST_ALP 0x0020
710#define PST_SBCLKST_HT 0x0030
711#define PST_ALPAVAIL 0x0008
712#define PST_HTAVAIL 0x0004
713#define PST_RESINIT 0x0003
714
715
716#define PCAP_REV_MASK 0x000000ff
717#define PCAP_RC_MASK 0x00001f00
718#define PCAP_RC_SHIFT 8
719#define PCAP_TC_MASK 0x0001e000
720#define PCAP_TC_SHIFT 13
721#define PCAP_PC_MASK 0x001e0000
722#define PCAP_PC_SHIFT 17
723#define PCAP_VC_MASK 0x01e00000
724#define PCAP_VC_SHIFT 21
725#define PCAP_CC_MASK 0x1e000000
726#define PCAP_CC_SHIFT 25
727#define PCAP5_PC_MASK 0x003e0000
728#define PCAP5_PC_SHIFT 17
729#define PCAP5_VC_MASK 0x07c00000
730#define PCAP5_VC_SHIFT 22
731#define PCAP5_CC_MASK 0xf8000000
732#define PCAP5_CC_SHIFT 27
733
734
735
736#define PRRT_TIME_MASK 0x03ff
737#define PRRT_INTEN 0x0400
738#define PRRT_REQ_ACTIVE 0x0800
739#define PRRT_ALP_REQ 0x1000
740#define PRRT_HT_REQ 0x2000
741
742
743#define PMURES_BIT(bit) (1 << (bit))
744
745
746#define PMURES_MAX_RESNUM 30
747
748
749
750
751#define PMU0_PLL0_PLLCTL0 0
752#define PMU0_PLL0_PC0_PDIV_MASK 1
753#define PMU0_PLL0_PC0_PDIV_FREQ 25000
754#define PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038
755#define PMU0_PLL0_PC0_DIV_ARM_SHIFT 3
756#define PMU0_PLL0_PC0_DIV_ARM_BASE 8
757
758
759#define PMU0_PLL0_PC0_DIV_ARM_110MHZ 0
760#define PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1
761#define PMU0_PLL0_PC0_DIV_ARM_88MHZ 2
762#define PMU0_PLL0_PC0_DIV_ARM_80MHZ 3
763#define PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4
764#define PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5
765#define PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6
766#define PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7
767
768
769#define PMU0_PLL0_PLLCTL1 1
770#define PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000
771#define PMU0_PLL0_PC1_WILD_INT_SHIFT 28
772#define PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00
773#define PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8
774#define PMU0_PLL0_PC1_STOP_MOD 0x00000040
775
776
777#define PMU0_PLL0_PLLCTL2 2
778#define PMU0_PLL0_PC2_WILD_INT_MASK 0xf
779#define PMU0_PLL0_PC2_WILD_INT_SHIFT 4
780
781
782#define RES4328_EXT_SWITCHER_PWM 0
783#define RES4328_BB_SWITCHER_PWM 1
784#define RES4328_BB_SWITCHER_BURST 2
785#define RES4328_BB_EXT_SWITCHER_BURST 3
786#define RES4328_ILP_REQUEST 4
787#define RES4328_RADIO_SWITCHER_PWM 5
788#define RES4328_RADIO_SWITCHER_BURST 6
789#define RES4328_ROM_SWITCH 7
790#define RES4328_PA_REF_LDO 8
791#define RES4328_RADIO_LDO 9
792#define RES4328_AFE_LDO 10
793#define RES4328_PLL_LDO 11
794#define RES4328_BG_FILTBYP 12
795#define RES4328_TX_FILTBYP 13
796#define RES4328_RX_FILTBYP 14
797#define RES4328_XTAL_PU 15
798#define RES4328_XTAL_EN 16
799#define RES4328_BB_PLL_FILTBYP 17
800#define RES4328_RF_PLL_FILTBYP 18
801#define RES4328_BB_PLL_PU 19
802
803#define RES5354_EXT_SWITCHER_PWM 0
804#define RES5354_BB_SWITCHER_PWM 1
805#define RES5354_BB_SWITCHER_BURST 2
806#define RES5354_BB_EXT_SWITCHER_BURST 3
807#define RES5354_ILP_REQUEST 4
808#define RES5354_RADIO_SWITCHER_PWM 5
809#define RES5354_RADIO_SWITCHER_BURST 6
810#define RES5354_ROM_SWITCH 7
811#define RES5354_PA_REF_LDO 8
812#define RES5354_RADIO_LDO 9
813#define RES5354_AFE_LDO 10
814#define RES5354_PLL_LDO 11
815#define RES5354_BG_FILTBYP 12
816#define RES5354_TX_FILTBYP 13
817#define RES5354_RX_FILTBYP 14
818#define RES5354_XTAL_PU 15
819#define RES5354_XTAL_EN 16
820#define RES5354_BB_PLL_FILTBYP 17
821#define RES5354_RF_PLL_FILTBYP 18
822#define RES5354_BB_PLL_PU 19
823
824
825
826#define DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8
827#define DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT)
828#define DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT)
829
830
831#define PMU2_PHY_PLL_PLLCTL 4
832#define PMU2_SI_PLL_PLLCTL 10
833
834
835#define RES4325_BUCK_BOOST_BURST 0
836#define RES4325_CBUCK_BURST 1
837#define RES4325_CBUCK_PWM 2
838#define RES4325_CLDO_CBUCK_BURST 3
839#define RES4325_CLDO_CBUCK_PWM 4
840#define RES4325_BUCK_BOOST_PWM 5
841#define RES4325_ILP_REQUEST 6
842#define RES4325_ABUCK_BURST 7
843#define RES4325_ABUCK_PWM 8
844#define RES4325_LNLDO1_PU 9
845#define RES4325_OTP_PU 10
846#define RES4325_LNLDO3_PU 11
847#define RES4325_LNLDO4_PU 12
848#define RES4325_XTAL_PU 13
849#define RES4325_ALP_AVAIL 14
850#define RES4325_RX_PWRSW_PU 15
851#define RES4325_TX_PWRSW_PU 16
852#define RES4325_RFPLL_PWRSW_PU 17
853#define RES4325_LOGEN_PWRSW_PU 18
854#define RES4325_AFE_PWRSW_PU 19
855#define RES4325_BBPLL_PWRSW_PU 20
856#define RES4325_HT_AVAIL 21
857
858
859#define RES4325B0_CBUCK_LPOM 1
860#define RES4325B0_CBUCK_BURST 2
861#define RES4325B0_CBUCK_PWM 3
862#define RES4325B0_CLDO_PU 4
863
864
865#define RES4325C1_OTP_PWRSW_PU 10
866#define RES4325C1_LNLDO2_PU 12
867
868
869#define CST4325_SPROM_OTP_SEL_MASK 0x00000003
870#define CST4325_DEFCIS_SEL 0
871#define CST4325_SPROM_SEL 1
872#define CST4325_OTP_SEL 2
873#define CST4325_OTP_PWRDN 3
874#define CST4325_SDIO_USB_MODE_MASK 0x00000004
875#define CST4325_SDIO_USB_MODE_SHIFT 2
876#define CST4325_RCAL_VALID_MASK 0x00000008
877#define CST4325_RCAL_VALID_SHIFT 3
878#define CST4325_RCAL_VALUE_MASK 0x000001f0
879#define CST4325_RCAL_VALUE_SHIFT 4
880#define CST4325_PMUTOP_2B_MASK 0x00000200
881#define CST4325_PMUTOP_2B_SHIFT 9
882
883#define RES4329_RESERVED0 0
884#define RES4329_CBUCK_LPOM 1
885#define RES4329_CBUCK_BURST 2
886#define RES4329_CBUCK_PWM 3
887#define RES4329_CLDO_PU 4
888#define RES4329_PALDO_PU 5
889#define RES4329_ILP_REQUEST 6
890#define RES4329_RESERVED7 7
891#define RES4329_RESERVED8 8
892#define RES4329_LNLDO1_PU 9
893#define RES4329_OTP_PU 10
894#define RES4329_RESERVED11 11
895#define RES4329_LNLDO2_PU 12
896#define RES4329_XTAL_PU 13
897#define RES4329_ALP_AVAIL 14
898#define RES4329_RX_PWRSW_PU 15
899#define RES4329_TX_PWRSW_PU 16
900#define RES4329_RFPLL_PWRSW_PU 17
901#define RES4329_LOGEN_PWRSW_PU 18
902#define RES4329_AFE_PWRSW_PU 19
903#define RES4329_BBPLL_PWRSW_PU 20
904#define RES4329_HT_AVAIL 21
905
906#define CST4329_SPROM_OTP_SEL_MASK 0x00000003
907#define CST4329_DEFCIS_SEL 0
908#define CST4329_SPROM_SEL 1
909#define CST4329_OTP_SEL 2
910#define CST4329_OTP_PWRDN 3
911#define CST4329_SPI_SDIO_MODE_MASK 0x00000004
912#define CST4329_SPI_SDIO_MODE_SHIFT 2
913
914
915#define RES4312_SWITCHER_BURST 0
916#define RES4312_SWITCHER_PWM 1
917#define RES4312_PA_REF_LDO 2
918#define RES4312_CORE_LDO_BURST 3
919#define RES4312_CORE_LDO_PWM 4
920#define RES4312_RADIO_LDO 5
921#define RES4312_ILP_REQUEST 6
922#define RES4312_BG_FILTBYP 7
923#define RES4312_TX_FILTBYP 8
924#define RES4312_RX_FILTBYP 9
925#define RES4312_XTAL_PU 10
926#define RES4312_ALP_AVAIL 11
927#define RES4312_BB_PLL_FILTBYP 12
928#define RES4312_RF_PLL_FILTBYP 13
929#define RES4312_HT_AVAIL 14
930
931#define RES4322_RF_LDO 0
932#define RES4322_ILP_REQUEST 1
933#define RES4322_XTAL_PU 2
934#define RES4322_ALP_AVAIL 3
935#define RES4322_SI_PLL_ON 4
936#define RES4322_HT_SI_AVAIL 5
937#define RES4322_PHY_PLL_ON 6
938#define RES4322_HT_PHY_AVAIL 7
939#define RES4322_OTP_PU 8
940
941
942#define CST4322_XTAL_FREQ_20_40MHZ 0x00000020
943#define CST4322_SPROM_OTP_SEL_MASK 0x000000c0
944#define CST4322_SPROM_OTP_SEL_SHIFT 6
945#define CST4322_NO_SPROM_OTP 0
946#define CST4322_SPROM_PRESENT 1
947#define CST4322_OTP_PRESENT 2
948#define CST4322_PCI_OR_USB 0x00000100
949#define CST4322_BOOT_MASK 0x00000600
950#define CST4322_BOOT_SHIFT 9
951#define CST4322_BOOT_FROM_SRAM 0
952#define CST4322_BOOT_FROM_ROM 1
953#define CST4322_BOOT_FROM_FLASH 2
954#define CST4322_BOOT_FROM_INVALID 3
955#define CST4322_ILP_DIV_EN 0x00000800
956#define CST4322_FLASH_TYPE_MASK 0x00001000
957#define CST4322_FLASH_TYPE_SHIFT 12
958#define CST4322_FLASH_TYPE_SHIFT_ST 0
959#define CST4322_FLASH_TYPE_SHIFT_ATMEL 1
960#define CST4322_ARM_TAP_SEL 0x00002000
961#define CST4322_RES_INIT_MODE_MASK 0x0000c000
962#define CST4322_RES_INIT_MODE_SHIFT 14
963#define CST4322_RES_INIT_MODE_ILPAVAIL 0
964#define CST4322_RES_INIT_MODE_ILPREQ 1
965#define CST4322_RES_INIT_MODE_ALPAVAIL 2
966#define CST4322_RES_INIT_MODE_HTAVAIL 3
967#define CST4322_PCIPLLCLK_GATING 0x00010000
968#define CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000
969#define CST4322_PCI_CARDBUS_MODE 0x00040000
970
971#define RES4315_CBUCK_LPOM 1
972#define RES4315_CBUCK_BURST 2
973#define RES4315_CBUCK_PWM 3
974#define RES4315_CLDO_PU 4
975#define RES4315_PALDO_PU 5
976#define RES4315_ILP_REQUEST 6
977#define RES4315_LNLDO1_PU 9
978#define RES4315_OTP_PU 10
979#define RES4315_LNLDO2_PU 12
980#define RES4315_XTAL_PU 13
981#define RES4315_ALP_AVAIL 14
982#define RES4315_RX_PWRSW_PU 15
983#define RES4315_TX_PWRSW_PU 16
984#define RES4315_RFPLL_PWRSW_PU 17
985#define RES4315_LOGEN_PWRSW_PU 18
986#define RES4315_AFE_PWRSW_PU 19
987#define RES4315_BBPLL_PWRSW_PU 20
988#define RES4315_HT_AVAIL 21
989
990#define CST4315_SPROM_OTP_SEL_MASK 0x00000003
991#define CST4315_DEFCIS_SEL 0x00000000
992#define CST4315_SPROM_SEL 0x00000001
993#define CST4315_OTP_SEL 0x00000002
994#define CST4315_OTP_PWRDN 0x00000003
995#define CST4315_SDIO_MODE 0x00000004
996#define CST4315_RCAL_VALID 0x00000008
997#define CST4315_RCAL_VALUE_MASK 0x000001f0
998#define CST4315_RCAL_VALUE_SHIFT 4
999#define CST4315_PALDO_EXTPNP 0x00000200
1000#define CST4315_CBUCK_MODE_MASK 0x00000c00
1001#define CST4315_CBUCK_MODE_BURST 0x00000400
1002#define CST4315_CBUCK_MODE_LPBURST 0x00000c00
1003
1004#define PMU_MAX_TRANSITION_DLY 15000
1005
1006
1007#define PMURES_UP_TRANSITION 2
1008
1009
1010
1011
1012
1013#define ECI_BW_20 0x0
1014#define ECI_BW_25 0x1
1015#define ECI_BW_30 0x2
1016#define ECI_BW_35 0x3
1017#define ECI_BW_40 0x4
1018#define ECI_BW_45 0x5
1019#define ECI_BW_50 0x6
1020#define ECI_BW_ALL 0x7
1021
1022
1023#define WLAN_NUM_ANT1 TXANT_0
1024#define WLAN_NUM_ANT2 TXANT_1
1025
1026#endif
diff --git a/drivers/net/wireless/bcm4329/include/sbconfig.h b/drivers/net/wireless/bcm4329/include/sbconfig.h
new file mode 100644
index 00000000000..da18ccbe9ab
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/sbconfig.h
@@ -0,0 +1,276 @@
1/*
2 * Broadcom SiliconBackplane hardware register definitions.
3 *
4 * Copyright (C) 1999-2010, 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.67.30.1 2008/05/07 20:17:27 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/bcm4329/include/sbhnddma.h b/drivers/net/wireless/bcm4329/include/sbhnddma.h
new file mode 100644
index 00000000000..7681395f5b3
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/sbhnddma.h
@@ -0,0 +1,294 @@
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-2010, 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.11.250.5.16.1 2009/07/21 14:04:51 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#define D32MAXDD (D32MAXRINGSZ / sizeof (dma32dd_t))
68
69
70#define XC_XE ((uint32)1 << 0)
71#define XC_SE ((uint32)1 << 1)
72#define XC_LE ((uint32)1 << 2)
73#define XC_FL ((uint32)1 << 4)
74#define XC_PD ((uint32)1 << 11)
75#define XC_AE ((uint32)3 << 16)
76#define XC_AE_SHIFT 16
77
78
79#define XP_LD_MASK 0xfff
80
81
82#define XS_CD_MASK 0x0fff
83#define XS_XS_MASK 0xf000
84#define XS_XS_SHIFT 12
85#define XS_XS_DISABLED 0x0000
86#define XS_XS_ACTIVE 0x1000
87#define XS_XS_IDLE 0x2000
88#define XS_XS_STOPPED 0x3000
89#define XS_XS_SUSP 0x4000
90#define XS_XE_MASK 0xf0000
91#define XS_XE_SHIFT 16
92#define XS_XE_NOERR 0x00000
93#define XS_XE_DPE 0x10000
94#define XS_XE_DFU 0x20000
95#define XS_XE_BEBR 0x30000
96#define XS_XE_BEDA 0x40000
97#define XS_AD_MASK 0xfff00000
98#define XS_AD_SHIFT 20
99
100
101#define RC_RE ((uint32)1 << 0)
102#define RC_RO_MASK 0xfe
103#define RC_RO_SHIFT 1
104#define RC_FM ((uint32)1 << 8)
105#define RC_SH ((uint32)1 << 9)
106#define RC_OC ((uint32)1 << 10)
107#define RC_PD ((uint32)1 << 11)
108#define RC_AE ((uint32)3 << 16)
109#define RC_AE_SHIFT 16
110
111
112#define RP_LD_MASK 0xfff
113
114
115#define RS_CD_MASK 0x0fff
116#define RS_RS_MASK 0xf000
117#define RS_RS_SHIFT 12
118#define RS_RS_DISABLED 0x0000
119#define RS_RS_ACTIVE 0x1000
120#define RS_RS_IDLE 0x2000
121#define RS_RS_STOPPED 0x3000
122#define RS_RE_MASK 0xf0000
123#define RS_RE_SHIFT 16
124#define RS_RE_NOERR 0x00000
125#define RS_RE_DPE 0x10000
126#define RS_RE_DFO 0x20000
127#define RS_RE_BEBW 0x30000
128#define RS_RE_BEDA 0x40000
129#define RS_AD_MASK 0xfff00000
130#define RS_AD_SHIFT 20
131
132
133#define FA_OFF_MASK 0xffff
134#define FA_SEL_MASK 0xf0000
135#define FA_SEL_SHIFT 16
136#define FA_SEL_XDD 0x00000
137#define FA_SEL_XDP 0x10000
138#define FA_SEL_RDD 0x40000
139#define FA_SEL_RDP 0x50000
140#define FA_SEL_XFD 0x80000
141#define FA_SEL_XFP 0x90000
142#define FA_SEL_RFD 0xc0000
143#define FA_SEL_RFP 0xd0000
144#define FA_SEL_RSD 0xe0000
145#define FA_SEL_RSP 0xf0000
146
147
148#define CTRL_BC_MASK 0x1fff
149#define CTRL_AE ((uint32)3 << 16)
150#define CTRL_AE_SHIFT 16
151#define CTRL_EOT ((uint32)1 << 28)
152#define CTRL_IOC ((uint32)1 << 29)
153#define CTRL_EOF ((uint32)1 << 30)
154#define CTRL_SOF ((uint32)1 << 31)
155
156
157#define CTRL_CORE_MASK 0x0ff00000
158
159
160
161
162typedef volatile struct {
163 uint32 control;
164 uint32 ptr;
165 uint32 addrlow;
166 uint32 addrhigh;
167 uint32 status0;
168 uint32 status1;
169} dma64regs_t;
170
171typedef volatile struct {
172 dma64regs_t tx;
173 dma64regs_t rx;
174} dma64regp_t;
175
176typedef volatile struct {
177 uint32 fifoaddr;
178 uint32 fifodatalow;
179 uint32 fifodatahigh;
180 uint32 pad;
181} dma64diag_t;
182
183
184typedef volatile struct {
185 uint32 ctrl1;
186 uint32 ctrl2;
187 uint32 addrlow;
188 uint32 addrhigh;
189} dma64dd_t;
190
191
192#define D64RINGALIGN_BITS 13
193#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS)
194#define D64RINGALIGN (1 << D64RINGALIGN_BITS)
195#define D64MAXDD (D64MAXRINGSZ / sizeof (dma64dd_t))
196
197
198#define D64_XC_XE 0x00000001
199#define D64_XC_SE 0x00000002
200#define D64_XC_LE 0x00000004
201#define D64_XC_FL 0x00000010
202#define D64_XC_PD 0x00000800
203#define D64_XC_AE 0x00030000
204#define D64_XC_AE_SHIFT 16
205
206
207#define D64_XP_LD_MASK 0x00000fff
208
209
210#define D64_XS0_CD_MASK 0x00001fff
211#define D64_XS0_XS_MASK 0xf0000000
212#define D64_XS0_XS_SHIFT 28
213#define D64_XS0_XS_DISABLED 0x00000000
214#define D64_XS0_XS_ACTIVE 0x10000000
215#define D64_XS0_XS_IDLE 0x20000000
216#define D64_XS0_XS_STOPPED 0x30000000
217#define D64_XS0_XS_SUSP 0x40000000
218
219#define D64_XS1_AD_MASK 0x0001ffff
220#define D64_XS1_XE_MASK 0xf0000000
221#define D64_XS1_XE_SHIFT 28
222#define D64_XS1_XE_NOERR 0x00000000
223#define D64_XS1_XE_DPE 0x10000000
224#define D64_XS1_XE_DFU 0x20000000
225#define D64_XS1_XE_DTE 0x30000000
226#define D64_XS1_XE_DESRE 0x40000000
227#define D64_XS1_XE_COREE 0x50000000
228
229
230#define D64_RC_RE 0x00000001
231#define D64_RC_RO_MASK 0x000000fe
232#define D64_RC_RO_SHIFT 1
233#define D64_RC_FM 0x00000100
234#define D64_RC_SH 0x00000200
235#define D64_RC_OC 0x00000400
236#define D64_RC_PD 0x00000800
237#define D64_RC_AE 0x00030000
238#define D64_RC_AE_SHIFT 16
239
240
241#define D64_RP_LD_MASK 0x00000fff
242
243
244#define D64_RS0_CD_MASK 0x00001fff
245#define D64_RS0_RS_MASK 0xf0000000
246#define D64_RS0_RS_SHIFT 28
247#define D64_RS0_RS_DISABLED 0x00000000
248#define D64_RS0_RS_ACTIVE 0x10000000
249#define D64_RS0_RS_IDLE 0x20000000
250#define D64_RS0_RS_STOPPED 0x30000000
251#define D64_RS0_RS_SUSP 0x40000000
252
253#define D64_RS1_AD_MASK 0x0001ffff
254#define D64_RS1_RE_MASK 0xf0000000
255#define D64_RS1_RE_SHIFT 28
256#define D64_RS1_RE_NOERR 0x00000000
257#define D64_RS1_RE_DPO 0x10000000
258#define D64_RS1_RE_DFU 0x20000000
259#define D64_RS1_RE_DTE 0x30000000
260#define D64_RS1_RE_DESRE 0x40000000
261#define D64_RS1_RE_COREE 0x50000000
262
263
264#define D64_FA_OFF_MASK 0xffff
265#define D64_FA_SEL_MASK 0xf0000
266#define D64_FA_SEL_SHIFT 16
267#define D64_FA_SEL_XDD 0x00000
268#define D64_FA_SEL_XDP 0x10000
269#define D64_FA_SEL_RDD 0x40000
270#define D64_FA_SEL_RDP 0x50000
271#define D64_FA_SEL_XFD 0x80000
272#define D64_FA_SEL_XFP 0x90000
273#define D64_FA_SEL_RFD 0xc0000
274#define D64_FA_SEL_RFP 0xd0000
275#define D64_FA_SEL_RSD 0xe0000
276#define D64_FA_SEL_RSP 0xf0000
277
278
279#define D64_CTRL1_EOT ((uint32)1 << 28)
280#define D64_CTRL1_IOC ((uint32)1 << 29)
281#define D64_CTRL1_EOF ((uint32)1 << 30)
282#define D64_CTRL1_SOF ((uint32)1 << 31)
283
284
285#define D64_CTRL2_BC_MASK 0x00007fff
286#define D64_CTRL2_AE 0x00030000
287#define D64_CTRL2_AE_SHIFT 16
288#define D64_CTRL2_PARITY 0x00040000
289
290
291#define D64_CTRL_CORE_MASK 0x0ff00000
292
293
294#endif
diff --git a/drivers/net/wireless/bcm4329/include/sbpcmcia.h b/drivers/net/wireless/bcm4329/include/sbpcmcia.h
new file mode 100644
index 00000000000..d6d80334258
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/sbpcmcia.h
@@ -0,0 +1,109 @@
1/*
2 * BCM43XX Sonics SiliconBackplane PCMCIA core hardware definitions.
3 *
4 * Copyright (C) 1999-2010, 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.31.4.1.2.3.8.7 2009/06/22 05:14:24 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/bcm4329/include/sbsdio.h b/drivers/net/wireless/bcm4329/include/sbsdio.h
new file mode 100644
index 00000000000..75aaf4d88f7
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/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-2010, 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.29.4.1.22.3 2009/03/11 20:26:57 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/bcm4329/include/sbsdpcmdev.h b/drivers/net/wireless/bcm4329/include/sbsdpcmdev.h
new file mode 100644
index 00000000000..7c7c7e4de0f
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/sbsdpcmdev.h
@@ -0,0 +1,288 @@
1/*
2 * Broadcom SiliconBackplane SDIO/PCMCIA hardware-specific device core support
3 *
4 * Copyright (C) 1999-2010, 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: sbsdpcmdev.h,v 13.29.4.1.4.6.6.2 2008/12/31 21:16:51 Exp $
25 */
26
27#ifndef _sbsdpcmdev_h_
28#define _sbsdpcmdev_h_
29
30/* cpp contortions to concatenate w/arg prescan */
31#ifndef PAD
32#define _PADLINE(line) pad ## line
33#define _XSTR(line) _PADLINE(line)
34#define PAD _XSTR(__LINE__)
35#endif /* PAD */
36
37
38typedef volatile struct {
39 dma64regs_t xmt; /* dma tx */
40 uint32 PAD[2];
41 dma64regs_t rcv; /* dma rx */
42 uint32 PAD[2];
43} dma64p_t;
44
45/* dma64 sdiod corerev >= 1 */
46typedef volatile struct {
47 dma64p_t dma64regs[2];
48 dma64diag_t dmafifo; /* DMA Diagnostic Regs, 0x280-0x28c */
49 uint32 PAD[92];
50} sdiodma64_t;
51
52/* dma32 sdiod corerev == 0 */
53typedef volatile struct {
54 dma32regp_t dma32regs[2]; /* dma tx & rx, 0x200-0x23c */
55 dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x240-0x24c */
56 uint32 PAD[108];
57} sdiodma32_t;
58
59/* dma32 regs for pcmcia core */
60typedef volatile struct {
61 dma32regp_t dmaregs; /* DMA Regs, 0x200-0x21c, rev8 */
62 dma32diag_t dmafifo; /* DMA Diagnostic Regs, 0x220-0x22c */
63 uint32 PAD[116];
64} pcmdma32_t;
65
66/* core registers */
67typedef volatile struct {
68 uint32 corecontrol; /* CoreControl, 0x000, rev8 */
69 uint32 corestatus; /* CoreStatus, 0x004, rev8 */
70 uint32 PAD[1];
71 uint32 biststatus; /* BistStatus, 0x00c, rev8 */
72
73 /* PCMCIA access */
74 uint16 pcmciamesportaladdr; /* PcmciaMesPortalAddr, 0x010, rev8 */
75 uint16 PAD[1];
76 uint16 pcmciamesportalmask; /* PcmciaMesPortalMask, 0x014, rev8 */
77 uint16 PAD[1];
78 uint16 pcmciawrframebc; /* PcmciaWrFrameBC, 0x018, rev8 */
79 uint16 PAD[1];
80 uint16 pcmciaunderflowtimer; /* PcmciaUnderflowTimer, 0x01c, rev8 */
81 uint16 PAD[1];
82
83 /* interrupt */
84 uint32 intstatus; /* IntStatus, 0x020, rev8 */
85 uint32 hostintmask; /* IntHostMask, 0x024, rev8 */
86 uint32 intmask; /* IntSbMask, 0x028, rev8 */
87 uint32 sbintstatus; /* SBIntStatus, 0x02c, rev8 */
88 uint32 sbintmask; /* SBIntMask, 0x030, rev8 */
89 uint32 PAD[3];
90 uint32 tosbmailbox; /* ToSBMailbox, 0x040, rev8 */
91 uint32 tohostmailbox; /* ToHostMailbox, 0x044, rev8 */
92 uint32 tosbmailboxdata; /* ToSbMailboxData, 0x048, rev8 */
93 uint32 tohostmailboxdata; /* ToHostMailboxData, 0x04c, rev8 */
94
95 /* synchronized access to registers in SDIO clock domain */
96 uint32 sdioaccess; /* SdioAccess, 0x050, rev8 */
97 uint32 PAD[3];
98
99 /* PCMCIA frame control */
100 uint8 pcmciaframectrl; /* pcmciaFrameCtrl, 0x060, rev8 */
101 uint8 PAD[3];
102 uint8 pcmciawatermark; /* pcmciaWaterMark, 0x064, rev8 */
103 uint8 PAD[155];
104
105 /* interrupt batching control */
106 uint32 intrcvlazy; /* IntRcvLazy, 0x100, rev8 */
107 uint32 PAD[3];
108
109 /* counters */
110 uint32 cmd52rd; /* Cmd52RdCount, 0x110, rev8, SDIO: cmd52 reads */
111 uint32 cmd52wr; /* Cmd52WrCount, 0x114, rev8, SDIO: cmd52 writes */
112 uint32 cmd53rd; /* Cmd53RdCount, 0x118, rev8, SDIO: cmd53 reads */
113 uint32 cmd53wr; /* Cmd53WrCount, 0x11c, rev8, SDIO: cmd53 writes */
114 uint32 abort; /* AbortCount, 0x120, rev8, SDIO: aborts */
115 uint32 datacrcerror; /* DataCrcErrorCount, 0x124, rev8, SDIO: frames w/bad CRC */
116 uint32 rdoutofsync; /* RdOutOfSyncCount, 0x128, rev8, SDIO/PCMCIA: Rd Frm OOS */
117 uint32 wroutofsync; /* RdOutOfSyncCount, 0x12c, rev8, SDIO/PCMCIA: Wr Frm OOS */
118 uint32 writebusy; /* WriteBusyCount, 0x130, rev8, SDIO: dev asserted "busy" */
119 uint32 readwait; /* ReadWaitCount, 0x134, rev8, SDIO: read: no data avail */
120 uint32 readterm; /* ReadTermCount, 0x138, rev8, SDIO: rd frm terminates */
121 uint32 writeterm; /* WriteTermCount, 0x13c, rev8, SDIO: wr frm terminates */
122 uint32 PAD[40];
123 uint32 clockctlstatus; /* ClockCtlStatus, 0x1e0, rev8 */
124 uint32 PAD[7];
125
126 /* DMA engines */
127 volatile union {
128 pcmdma32_t pcm32;
129 sdiodma32_t sdiod32;
130 sdiodma64_t sdiod64;
131 } dma;
132
133 /* SDIO/PCMCIA CIS region */
134 char cis[512]; /* 512 byte CIS, 0x400-0x5ff, rev6 */
135
136 /* PCMCIA function control registers */
137 char pcmciafcr[256]; /* PCMCIA FCR, 0x600-6ff, rev6 */
138 uint16 PAD[55];
139
140 /* PCMCIA backplane access */
141 uint16 backplanecsr; /* BackplaneCSR, 0x76E, rev6 */
142 uint16 backplaneaddr0; /* BackplaneAddr0, 0x770, rev6 */
143 uint16 backplaneaddr1; /* BackplaneAddr1, 0x772, rev6 */
144 uint16 backplaneaddr2; /* BackplaneAddr2, 0x774, rev6 */
145 uint16 backplaneaddr3; /* BackplaneAddr3, 0x776, rev6 */
146 uint16 backplanedata0; /* BackplaneData0, 0x778, rev6 */
147 uint16 backplanedata1; /* BackplaneData1, 0x77a, rev6 */
148 uint16 backplanedata2; /* BackplaneData2, 0x77c, rev6 */
149 uint16 backplanedata3; /* BackplaneData3, 0x77e, rev6 */
150 uint16 PAD[31];
151
152 /* sprom "size" & "blank" info */
153 uint16 spromstatus; /* SPROMStatus, 0x7BE, rev2 */
154 uint32 PAD[464];
155
156 /* Sonics SiliconBackplane registers */
157 sbconfig_t sbconfig; /* SbConfig Regs, 0xf00-0xfff, rev8 */
158} sdpcmd_regs_t;
159
160/* corecontrol */
161#define CC_CISRDY (1 << 0) /* CIS Ready */
162#define CC_BPRESEN (1 << 1) /* CCCR RES signal causes backplane reset */
163#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */
164#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation bit (rev 11) */
165
166/* corestatus */
167#define CS_PCMCIAMODE (1 << 0) /* Device Mode; 0=SDIO, 1=PCMCIA */
168#define CS_SMARTDEV (1 << 1) /* 1=smartDev enabled */
169#define CS_F2ENABLED (1 << 2) /* 1=host has enabled the device */
170
171#define PCMCIA_MES_PA_MASK 0x7fff /* PCMCIA Message Portal Address Mask */
172#define PCMCIA_MES_PM_MASK 0x7fff /* PCMCIA Message Portal Mask Mask */
173#define PCMCIA_WFBC_MASK 0xffff /* PCMCIA Write Frame Byte Count Mask */
174#define PCMCIA_UT_MASK 0x07ff /* PCMCIA Underflow Timer Mask */
175
176/* intstatus */
177#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */
178#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */
179#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */
180#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */
181#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */
182#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */
183#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */
184#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */
185#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */
186#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */
187#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */
188#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */
189#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */
190#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */
191#define I_PC (1 << 10) /* descriptor error */
192#define I_PD (1 << 11) /* data error */
193#define I_DE (1 << 12) /* Descriptor protocol Error */
194#define I_RU (1 << 13) /* Receive descriptor Underflow */
195#define I_RO (1 << 14) /* Receive fifo Overflow */
196#define I_XU (1 << 15) /* Transmit fifo Underflow */
197#define I_RI (1 << 16) /* Receive Interrupt */
198#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */
199#define I_XI (1 << 24) /* Transmit Interrupt */
200#define I_RF_TERM (1 << 25) /* Read Frame Terminate */
201#define I_WF_TERM (1 << 26) /* Write Frame Terminate */
202#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */
203#define I_SBINT (1 << 28) /* sbintstatus Interrupt */
204#define I_CHIPACTIVE (1 << 29) /* chip transitioned from doze to active state */
205#define I_SRESET (1 << 30) /* CCCR RES interrupt */
206#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */
207#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU) /* DMA Errors */
208#define I_DMA (I_RI | I_XI | I_ERRORS)
209
210/* sbintstatus */
211#define I_SB_SERR (1 << 8) /* Backplane SError (write) */
212#define I_SB_RESPERR (1 << 9) /* Backplane Response Error (read) */
213#define I_SB_SPROMERR (1 << 10) /* Error accessing the sprom */
214
215/* sdioaccess */
216#define SDA_DATA_MASK 0x000000ff /* Read/Write Data Mask */
217#define SDA_ADDR_MASK 0x000fff00 /* Read/Write Address Mask */
218#define SDA_ADDR_SHIFT 8 /* Read/Write Address Shift */
219#define SDA_WRITE 0x01000000 /* Write bit */
220#define SDA_READ 0x00000000 /* Write bit cleared for Read */
221#define SDA_BUSY 0x80000000 /* Busy bit */
222
223/* sdioaccess-accessible register address spaces */
224#define SDA_CCCR_SPACE 0x000 /* sdioAccess CCCR register space */
225#define SDA_F1_FBR_SPACE 0x100 /* sdioAccess F1 FBR register space */
226#define SDA_F2_FBR_SPACE 0x200 /* sdioAccess F2 FBR register space */
227#define SDA_F1_REG_SPACE 0x300 /* sdioAccess F1 core-specific register space */
228
229/* SDA_F1_REG_SPACE sdioaccess-accessible F1 reg space register offsets */
230#define SDA_CHIPCONTROLDATA 0x006 /* ChipControlData */
231#define SDA_CHIPCONTROLENAB 0x007 /* ChipControlEnable */
232#define SDA_F2WATERMARK 0x008 /* Function 2 Watermark */
233#define SDA_DEVICECONTROL 0x009 /* DeviceControl */
234#define SDA_SBADDRLOW 0x00a /* SbAddrLow */
235#define SDA_SBADDRMID 0x00b /* SbAddrMid */
236#define SDA_SBADDRHIGH 0x00c /* SbAddrHigh */
237#define SDA_FRAMECTRL 0x00d /* FrameCtrl */
238#define SDA_CHIPCLOCKCSR 0x00e /* ChipClockCSR */
239#define SDA_SDIOPULLUP 0x00f /* SdioPullUp */
240#define SDA_SDIOWRFRAMEBCLOW 0x019 /* SdioWrFrameBCLow */
241#define SDA_SDIOWRFRAMEBCHIGH 0x01a /* SdioWrFrameBCHigh */
242#define SDA_SDIORDFRAMEBCLOW 0x01b /* SdioRdFrameBCLow */
243#define SDA_SDIORDFRAMEBCHIGH 0x01c /* SdioRdFrameBCHigh */
244
245/* SDA_F2WATERMARK */
246#define SDA_F2WATERMARK_MASK 0x7f /* F2Watermark Mask */
247
248/* SDA_SBADDRLOW */
249#define SDA_SBADDRLOW_MASK 0x80 /* SbAddrLow Mask */
250
251/* SDA_SBADDRMID */
252#define SDA_SBADDRMID_MASK 0xff /* SbAddrMid Mask */
253
254/* SDA_SBADDRHIGH */
255#define SDA_SBADDRHIGH_MASK 0xff /* SbAddrHigh Mask */
256
257/* SDA_FRAMECTRL */
258#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */
259#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */
260#define SFC_CRC4WOOS (1 << 2) /* HW reports CRC error for write out of sync */
261#define SFC_ABORTALL (1 << 3) /* Abort cancels all in-progress frames */
262
263/* pcmciaframectrl */
264#define PFC_RF_TERM (1 << 0) /* Read Frame Terminate */
265#define PFC_WF_TERM (1 << 1) /* Write Frame Terminate */
266
267/* intrcvlazy */
268#define IRL_TO_MASK 0x00ffffff /* timeout */
269#define IRL_FC_MASK 0xff000000 /* frame count */
270#define IRL_FC_SHIFT 24 /* frame count */
271
272/* rx header */
273typedef volatile struct {
274 uint16 len;
275 uint16 flags;
276} sdpcmd_rxh_t;
277
278/* rx header flags */
279#define RXF_CRC 0x0001 /* CRC error detected */
280#define RXF_WOOS 0x0002 /* write frame out of sync */
281#define RXF_WF_TERM 0x0004 /* write frame terminated */
282#define RXF_ABORT 0x0008 /* write frame aborted */
283#define RXF_DISCARD (RXF_CRC | RXF_WOOS | RXF_WF_TERM | RXF_ABORT) /* bad frame */
284
285/* HW frame tag */
286#define SDPCM_FRAMETAG_LEN 4 /* HW frametag: 2 bytes len, 2 bytes check val */
287
288#endif /* _sbsdpcmdev_h_ */
diff --git a/drivers/net/wireless/bcm4329/include/sbsocram.h b/drivers/net/wireless/bcm4329/include/sbsocram.h
new file mode 100644
index 00000000000..5ede0b66d97
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/sbsocram.h
@@ -0,0 +1,150 @@
1/*
2 * BCM47XX Sonics SiliconBackplane embedded ram core
3 *
4 * Copyright (C) 1999-2010, 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.9.162.2 2008/12/12 14:13:27 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[17];
60 uint32 extmemconfig;
61 uint32 extmemparitycsr;
62 uint32 extmemparityerrdata;
63 uint32 extmemparityerrcnt;
64 uint32 extmemwrctrlandsize;
65 uint32 PAD[84];
66 uint32 workaround;
67 uint32 pwrctl;
68} sbsocramregs_t;
69
70#endif
71
72
73#define SR_COREINFO 0x00
74#define SR_BWALLOC 0x04
75#define SR_BISTSTAT 0x0c
76#define SR_BANKINDEX 0x10
77#define SR_BANKSTBYCTL 0x14
78#define SR_PWRCTL 0x1e8
79
80
81#define SRCI_PT_MASK 0x00070000
82#define SRCI_PT_SHIFT 16
83
84#define SRCI_PT_OCP_OCP 0
85#define SRCI_PT_AXI_OCP 1
86#define SRCI_PT_ARM7AHB_OCP 2
87#define SRCI_PT_CM3AHB_OCP 3
88#define SRCI_PT_AXI_AXI 4
89#define SRCI_PT_AHB_AXI 5
90
91#define SRCI_LSS_MASK 0x00f00000
92#define SRCI_LSS_SHIFT 20
93#define SRCI_LRS_MASK 0x0f000000
94#define SRCI_LRS_SHIFT 24
95
96
97#define SRCI_MS0_MASK 0xf
98#define SR_MS0_BASE 16
99
100
101#define SRCI_ROMNB_MASK 0xf000
102#define SRCI_ROMNB_SHIFT 12
103#define SRCI_ROMBSZ_MASK 0xf00
104#define SRCI_ROMBSZ_SHIFT 8
105#define SRCI_SRNB_MASK 0xf0
106#define SRCI_SRNB_SHIFT 4
107#define SRCI_SRBSZ_MASK 0xf
108#define SRCI_SRBSZ_SHIFT 0
109
110#define SR_BSZ_BASE 14
111
112
113#define SRSC_SBYOVR_MASK 0x80000000
114#define SRSC_SBYOVR_SHIFT 31
115#define SRSC_SBYOVRVAL_MASK 0x60000000
116#define SRSC_SBYOVRVAL_SHIFT 29
117#define SRSC_SBYEN_MASK 0x01000000
118#define SRSC_SBYEN_SHIFT 24
119
120
121#define SRPC_PMU_STBYDIS_MASK 0x00000010
122#define SRPC_PMU_STBYDIS_SHIFT 4
123#define SRPC_STBYOVRVAL_MASK 0x00000008
124#define SRPC_STBYOVRVAL_SHIFT 3
125#define SRPC_STBYOVR_MASK 0x00000007
126#define SRPC_STBYOVR_SHIFT 0
127
128
129#define SRECC_NUM_BANKS_MASK 0x000000F0
130#define SRECC_NUM_BANKS_SHIFT 4
131#define SRECC_BANKSIZE_MASK 0x0000000F
132#define SRECC_BANKSIZE_SHIFT 0
133
134#define SRECC_BANKSIZE(value) (1 << (value))
135
136
137#define SRCBPC_PATCHENABLE 0x80000000
138
139#define SRP_ADDRESS 0x0001FFFC
140#define SRP_VALID 0x8000
141
142
143#define SRCMD_WRITE 0x00020000
144#define SRCMD_READ 0x00010000
145#define SRCMD_DONE 0x80000000
146
147#define SRCMD_DONE_DLY 1000
148
149
150#endif
diff --git a/drivers/net/wireless/bcm4329/include/sdio.h b/drivers/net/wireless/bcm4329/include/sdio.h
new file mode 100644
index 00000000000..280cb845fb0
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/sdio.h
@@ -0,0 +1,566 @@
1/*
2 * SDIO spec header file
3 * Protocol and standard (common) device definitions
4 *
5 * Copyright (C) 1999-2010, 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.24.4.1.4.1.16.1 2009/08/12 01:08:02 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
83/* Broadcom extensions (corerev >= 1) */
84#define SDIOD_CCCR_BRCM_SEPINT 0xf2
85
86/* cccr_sdio_rev */
87#define SDIO_REV_SDIOID_MASK 0xf0 /* SDIO spec revision number */
88#define SDIO_REV_CCCRID_MASK 0x0f /* CCCR format version number */
89
90/* sd_rev */
91#define SD_REV_PHY_MASK 0x0f /* SD format version number */
92
93/* io_en */
94#define SDIO_FUNC_ENABLE_1 0x02 /* function 1 I/O enable */
95#define SDIO_FUNC_ENABLE_2 0x04 /* function 2 I/O enable */
96
97/* io_rdys */
98#define SDIO_FUNC_READY_1 0x02 /* function 1 I/O ready */
99#define SDIO_FUNC_READY_2 0x04 /* function 2 I/O ready */
100
101/* intr_ctl */
102#define INTR_CTL_MASTER_EN 0x1 /* interrupt enable master */
103#define INTR_CTL_FUNC1_EN 0x2 /* interrupt enable for function 1 */
104#define INTR_CTL_FUNC2_EN 0x4 /* interrupt enable for function 2 */
105
106/* intr_status */
107#define INTR_STATUS_FUNC1 0x2 /* interrupt pending for function 1 */
108#define INTR_STATUS_FUNC2 0x4 /* interrupt pending for function 2 */
109
110/* io_abort */
111#define IO_ABORT_RESET_ALL 0x08 /* I/O card reset */
112#define IO_ABORT_FUNC_MASK 0x07 /* abort selction: function x */
113
114/* bus_inter */
115#define BUS_CARD_DETECT_DIS 0x80 /* Card Detect disable */
116#define BUS_SPI_CONT_INTR_CAP 0x40 /* support continuous SPI interrupt */
117#define BUS_SPI_CONT_INTR_EN 0x20 /* continuous SPI interrupt enable */
118#define BUS_SD_DATA_WIDTH_MASK 0x03 /* bus width mask */
119#define BUS_SD_DATA_WIDTH_4BIT 0x02 /* bus width 4-bit mode */
120#define BUS_SD_DATA_WIDTH_1BIT 0x00 /* bus width 1-bit mode */
121
122/* capability */
123#define SDIO_CAP_4BLS 0x80 /* 4-bit support for low speed card */
124#define SDIO_CAP_LSC 0x40 /* low speed card */
125#define SDIO_CAP_E4MI 0x20 /* enable interrupt between block of data in 4-bit mode */
126#define SDIO_CAP_S4MI 0x10 /* support interrupt between block of data in 4-bit mode */
127#define SDIO_CAP_SBS 0x08 /* support suspend/resume */
128#define SDIO_CAP_SRW 0x04 /* support read wait */
129#define SDIO_CAP_SMB 0x02 /* support multi-block transfer */
130#define SDIO_CAP_SDC 0x01 /* Support Direct commands during multi-byte transfer */
131
132/* power_control */
133#define SDIO_POWER_SMPC 0x01 /* supports master power control (RO) */
134#define SDIO_POWER_EMPC 0x02 /* enable master power control (allow > 200mA) (RW) */
135
136/* speed_control (control device entry into high-speed clocking mode) */
137#define SDIO_SPEED_SHS 0x01 /* supports high-speed [clocking] mode (RO) */
138#define SDIO_SPEED_EHS 0x02 /* enable high-speed [clocking] mode (RW) */
139
140/* brcm sepint */
141#define SDIO_SEPINT_MASK 0x01 /* route sdpcmdev intr onto separate pad (chip-specific) */
142#define SDIO_SEPINT_OE 0x02 /* 1 asserts output enable for above pad */
143#define SDIO_SEPINT_ACT_HI 0x04 /* use active high interrupt level instead of active low */
144
145/* FBR structure for function 1-7, FBR addresses and register offsets */
146typedef volatile struct {
147 uint8 devctr; /* device interface, CSA control */
148 uint8 ext_dev; /* extended standard I/O device type code */
149 uint8 pwr_sel; /* power selection support */
150 uint8 PAD[6]; /* reserved */
151
152 uint8 cis_low; /* CIS LSB */
153 uint8 cis_mid;
154 uint8 cis_high; /* CIS MSB */
155 uint8 csa_low; /* code storage area, LSB */
156 uint8 csa_mid;
157 uint8 csa_high; /* code storage area, MSB */
158 uint8 csa_dat_win; /* data access window to function */
159
160 uint8 fnx_blk_size[2]; /* block size, little endian */
161} sdio_fbr_t;
162
163/* Maximum number of I/O funcs */
164#define SDIOD_MAX_IOFUNCS 7
165
166/* SDIO Device FBR Start Address */
167#define SDIOD_FBR_STARTADDR 0x100
168
169/* SDIO Device FBR Size */
170#define SDIOD_FBR_SIZE 0x100
171
172/* Macro to calculate FBR register base */
173#define SDIOD_FBR_BASE(n) ((n) * 0x100)
174
175/* Function register offsets */
176#define SDIOD_FBR_DEVCTR 0x00 /* basic info for function */
177#define SDIOD_FBR_EXT_DEV 0x01 /* extended I/O device code */
178#define SDIOD_FBR_PWR_SEL 0x02 /* power selection bits */
179
180/* SDIO Function CIS ptr offset */
181#define SDIOD_FBR_CISPTR_0 0x09
182#define SDIOD_FBR_CISPTR_1 0x0A
183#define SDIOD_FBR_CISPTR_2 0x0B
184
185/* Code Storage Area pointer */
186#define SDIOD_FBR_CSA_ADDR_0 0x0C
187#define SDIOD_FBR_CSA_ADDR_1 0x0D
188#define SDIOD_FBR_CSA_ADDR_2 0x0E
189#define SDIOD_FBR_CSA_DATA 0x0F
190
191/* SDIO Function I/O Block Size */
192#define SDIOD_FBR_BLKSIZE_0 0x10
193#define SDIOD_FBR_BLKSIZE_1 0x11
194
195/* devctr */
196#define SDIOD_FBR_DEVCTR_DIC 0x0f /* device interface code */
197#define SDIOD_FBR_DECVTR_CSA 0x40 /* CSA support flag */
198#define SDIOD_FBR_DEVCTR_CSA_EN 0x80 /* CSA enabled */
199/* interface codes */
200#define SDIOD_DIC_NONE 0 /* SDIO standard interface is not supported */
201#define SDIOD_DIC_UART 1
202#define SDIOD_DIC_BLUETOOTH_A 2
203#define SDIOD_DIC_BLUETOOTH_B 3
204#define SDIOD_DIC_GPS 4
205#define SDIOD_DIC_CAMERA 5
206#define SDIOD_DIC_PHS 6
207#define SDIOD_DIC_WLAN 7
208#define SDIOD_DIC_EXT 0xf /* extended device interface, read ext_dev register */
209
210/* pwr_sel */
211#define SDIOD_PWR_SEL_SPS 0x01 /* supports power selection */
212#define SDIOD_PWR_SEL_EPS 0x02 /* enable power selection (low-current mode) */
213
214/* misc defines */
215#define SDIO_FUNC_0 0
216#define SDIO_FUNC_1 1
217#define SDIO_FUNC_2 2
218#define SDIO_FUNC_3 3
219#define SDIO_FUNC_4 4
220#define SDIO_FUNC_5 5
221#define SDIO_FUNC_6 6
222#define SDIO_FUNC_7 7
223
224#define SD_CARD_TYPE_UNKNOWN 0 /* bad type or unrecognized */
225#define SD_CARD_TYPE_IO 1 /* IO only card */
226#define SD_CARD_TYPE_MEMORY 2 /* memory only card */
227#define SD_CARD_TYPE_COMBO 3 /* IO and memory combo card */
228
229#define SDIO_MAX_BLOCK_SIZE 2048 /* maximum block size for block mode operation */
230#define SDIO_MIN_BLOCK_SIZE 1 /* minimum block size for block mode operation */
231
232/* Card registers: status bit position */
233#define CARDREG_STATUS_BIT_OUTOFRANGE 31
234#define CARDREG_STATUS_BIT_COMCRCERROR 23
235#define CARDREG_STATUS_BIT_ILLEGALCOMMAND 22
236#define CARDREG_STATUS_BIT_ERROR 19
237#define CARDREG_STATUS_BIT_IOCURRENTSTATE3 12
238#define CARDREG_STATUS_BIT_IOCURRENTSTATE2 11
239#define CARDREG_STATUS_BIT_IOCURRENTSTATE1 10
240#define CARDREG_STATUS_BIT_IOCURRENTSTATE0 9
241#define CARDREG_STATUS_BIT_FUN_NUM_ERROR 4
242
243
244
245#define SD_CMD_GO_IDLE_STATE 0 /* mandatory for SDIO */
246#define SD_CMD_SEND_OPCOND 1
247#define SD_CMD_MMC_SET_RCA 3
248#define SD_CMD_IO_SEND_OP_COND 5 /* mandatory for SDIO */
249#define SD_CMD_SELECT_DESELECT_CARD 7
250#define SD_CMD_SEND_CSD 9
251#define SD_CMD_SEND_CID 10
252#define SD_CMD_STOP_TRANSMISSION 12
253#define SD_CMD_SEND_STATUS 13
254#define SD_CMD_GO_INACTIVE_STATE 15
255#define SD_CMD_SET_BLOCKLEN 16
256#define SD_CMD_READ_SINGLE_BLOCK 17
257#define SD_CMD_READ_MULTIPLE_BLOCK 18
258#define SD_CMD_WRITE_BLOCK 24
259#define SD_CMD_WRITE_MULTIPLE_BLOCK 25
260#define SD_CMD_PROGRAM_CSD 27
261#define SD_CMD_SET_WRITE_PROT 28
262#define SD_CMD_CLR_WRITE_PROT 29
263#define SD_CMD_SEND_WRITE_PROT 30
264#define SD_CMD_ERASE_WR_BLK_START 32
265#define SD_CMD_ERASE_WR_BLK_END 33
266#define SD_CMD_ERASE 38
267#define SD_CMD_LOCK_UNLOCK 42
268#define SD_CMD_IO_RW_DIRECT 52 /* mandatory for SDIO */
269#define SD_CMD_IO_RW_EXTENDED 53 /* mandatory for SDIO */
270#define SD_CMD_APP_CMD 55
271#define SD_CMD_GEN_CMD 56
272#define SD_CMD_READ_OCR 58
273#define SD_CMD_CRC_ON_OFF 59 /* mandatory for SDIO */
274#define SD_ACMD_SD_STATUS 13
275#define SD_ACMD_SEND_NUM_WR_BLOCKS 22
276#define SD_ACMD_SET_WR_BLOCK_ERASE_CNT 23
277#define SD_ACMD_SD_SEND_OP_COND 41
278#define SD_ACMD_SET_CLR_CARD_DETECT 42
279#define SD_ACMD_SEND_SCR 51
280
281/* argument for SD_CMD_IO_RW_DIRECT and SD_CMD_IO_RW_EXTENDED */
282#define SD_IO_OP_READ 0 /* Read_Write: Read */
283#define SD_IO_OP_WRITE 1 /* Read_Write: Write */
284#define SD_IO_RW_NORMAL 0 /* no RAW */
285#define SD_IO_RW_RAW 1 /* RAW */
286#define SD_IO_BYTE_MODE 0 /* Byte Mode */
287#define SD_IO_BLOCK_MODE 1 /* BlockMode */
288#define SD_IO_FIXED_ADDRESS 0 /* fix Address */
289#define SD_IO_INCREMENT_ADDRESS 1 /* IncrementAddress */
290
291/* build SD_CMD_IO_RW_DIRECT Argument */
292#define SDIO_IO_RW_DIRECT_ARG(rw, raw, func, addr, data) \
293 ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((raw) & 1) << 27) | \
294 (((addr) & 0x1FFFF) << 9) | ((data) & 0xFF))
295
296/* build SD_CMD_IO_RW_EXTENDED Argument */
297#define SDIO_IO_RW_EXTENDED_ARG(rw, blk, func, addr, inc_addr, count) \
298 ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | (((blk) & 1) << 27) | \
299 (((inc_addr) & 1) << 26) | (((addr) & 0x1FFFF) << 9) | ((count) & 0x1FF))
300
301/* SDIO response parameters */
302#define SD_RSP_NO_NONE 0
303#define SD_RSP_NO_1 1
304#define SD_RSP_NO_2 2
305#define SD_RSP_NO_3 3
306#define SD_RSP_NO_4 4
307#define SD_RSP_NO_5 5
308#define SD_RSP_NO_6 6
309
310 /* Modified R6 response (to CMD3) */
311#define SD_RSP_MR6_COM_CRC_ERROR 0x8000
312#define SD_RSP_MR6_ILLEGAL_COMMAND 0x4000
313#define SD_RSP_MR6_ERROR 0x2000
314
315 /* Modified R1 in R4 Response (to CMD5) */
316#define SD_RSP_MR1_SBIT 0x80
317#define SD_RSP_MR1_PARAMETER_ERROR 0x40
318#define SD_RSP_MR1_RFU5 0x20
319#define SD_RSP_MR1_FUNC_NUM_ERROR 0x10
320#define SD_RSP_MR1_COM_CRC_ERROR 0x08
321#define SD_RSP_MR1_ILLEGAL_COMMAND 0x04
322#define SD_RSP_MR1_RFU1 0x02
323#define SD_RSP_MR1_IDLE_STATE 0x01
324
325 /* R5 response (to CMD52 and CMD53) */
326#define SD_RSP_R5_COM_CRC_ERROR 0x80
327#define SD_RSP_R5_ILLEGAL_COMMAND 0x40
328#define SD_RSP_R5_IO_CURRENTSTATE1 0x20
329#define SD_RSP_R5_IO_CURRENTSTATE0 0x10
330#define SD_RSP_R5_ERROR 0x08
331#define SD_RSP_R5_RFU 0x04
332#define SD_RSP_R5_FUNC_NUM_ERROR 0x02
333#define SD_RSP_R5_OUT_OF_RANGE 0x01
334
335#define SD_RSP_R5_ERRBITS 0xCB
336
337
338/* ------------------------------------------------
339 * SDIO Commands and responses
340 *
341 * I/O only commands are:
342 * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53
343 * ------------------------------------------------
344 */
345
346/* SDIO Commands */
347#define SDIOH_CMD_0 0
348#define SDIOH_CMD_3 3
349#define SDIOH_CMD_5 5
350#define SDIOH_CMD_7 7
351#define SDIOH_CMD_15 15
352#define SDIOH_CMD_52 52
353#define SDIOH_CMD_53 53
354#define SDIOH_CMD_59 59
355
356/* SDIO Command Responses */
357#define SDIOH_RSP_NONE 0
358#define SDIOH_RSP_R1 1
359#define SDIOH_RSP_R2 2
360#define SDIOH_RSP_R3 3
361#define SDIOH_RSP_R4 4
362#define SDIOH_RSP_R5 5
363#define SDIOH_RSP_R6 6
364
365/*
366 * SDIO Response Error flags
367 */
368#define SDIOH_RSP5_ERROR_FLAGS 0xCB
369
370/* ------------------------------------------------
371 * SDIO Command structures. I/O only commands are:
372 *
373 * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53
374 * ------------------------------------------------
375 */
376
377#define CMD5_OCR_M BITFIELD_MASK(24)
378#define CMD5_OCR_S 0
379
380#define CMD7_RCA_M BITFIELD_MASK(16)
381#define CMD7_RCA_S 16
382
383#define CMD_15_RCA_M BITFIELD_MASK(16)
384#define CMD_15_RCA_S 16
385
386#define CMD52_DATA_M BITFIELD_MASK(8) /* Bits [7:0] - Write Data/Stuff bits of CMD52
387 */
388#define CMD52_DATA_S 0
389#define CMD52_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */
390#define CMD52_REG_ADDR_S 9
391#define CMD52_RAW_M BITFIELD_MASK(1) /* Bit 27 - Read after Write flag */
392#define CMD52_RAW_S 27
393#define CMD52_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */
394#define CMD52_FUNCTION_S 28
395#define CMD52_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */
396#define CMD52_RW_FLAG_S 31
397
398
399#define CMD53_BYTE_BLK_CNT_M BITFIELD_MASK(9) /* Bits [8:0] - Byte/Block Count of CMD53 */
400#define CMD53_BYTE_BLK_CNT_S 0
401#define CMD53_REG_ADDR_M BITFIELD_MASK(17) /* Bits [25:9] - register address */
402#define CMD53_REG_ADDR_S 9
403#define CMD53_OP_CODE_M BITFIELD_MASK(1) /* Bit 26 - R/W Operation Code */
404#define CMD53_OP_CODE_S 26
405#define CMD53_BLK_MODE_M BITFIELD_MASK(1) /* Bit 27 - Block Mode */
406#define CMD53_BLK_MODE_S 27
407#define CMD53_FUNCTION_M BITFIELD_MASK(3) /* Bits [30:28] - Function number */
408#define CMD53_FUNCTION_S 28
409#define CMD53_RW_FLAG_M BITFIELD_MASK(1) /* Bit 31 - R/W flag */
410#define CMD53_RW_FLAG_S 31
411
412/* ------------------------------------------------------
413 * SDIO Command Response structures for SD1 and SD4 modes
414 * -----------------------------------------------------
415 */
416#define RSP4_IO_OCR_M BITFIELD_MASK(24) /* Bits [23:0] - Card's OCR Bits [23:0] */
417#define RSP4_IO_OCR_S 0
418#define RSP4_STUFF_M BITFIELD_MASK(3) /* Bits [26:24] - Stuff bits */
419#define RSP4_STUFF_S 24
420#define RSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 27 - Memory present */
421#define RSP4_MEM_PRESENT_S 27
422#define RSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [30:28] - Number of I/O funcs */
423#define RSP4_NUM_FUNCS_S 28
424#define RSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 31 - SDIO card ready */
425#define RSP4_CARD_READY_S 31
426
427#define RSP6_STATUS_M BITFIELD_MASK(16) /* Bits [15:0] - Card status bits [19,22,23,12:0]
428 */
429#define RSP6_STATUS_S 0
430#define RSP6_IO_RCA_M BITFIELD_MASK(16) /* Bits [31:16] - RCA bits[31-16] */
431#define RSP6_IO_RCA_S 16
432
433#define RSP1_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error */
434#define RSP1_AKE_SEQ_ERROR_S 3
435#define RSP1_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */
436#define RSP1_APP_CMD_S 5
437#define RSP1_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data (buff empty) */
438#define RSP1_READY_FOR_DATA_S 8
439#define RSP1_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - State of card
440 * when Cmd was received
441 */
442#define RSP1_CURR_STATE_S 9
443#define RSP1_EARSE_RESET_M BITFIELD_MASK(1) /* Bit 13 - Erase seq cleared */
444#define RSP1_EARSE_RESET_S 13
445#define RSP1_CARD_ECC_DISABLE_M BITFIELD_MASK(1) /* Bit 14 - Card ECC disabled */
446#define RSP1_CARD_ECC_DISABLE_S 14
447#define RSP1_WP_ERASE_SKIP_M BITFIELD_MASK(1) /* Bit 15 - Partial blocks erased due to W/P */
448#define RSP1_WP_ERASE_SKIP_S 15
449#define RSP1_CID_CSD_OVERW_M BITFIELD_MASK(1) /* Bit 16 - Illegal write to CID or R/O bits
450 * of CSD
451 */
452#define RSP1_CID_CSD_OVERW_S 16
453#define RSP1_ERROR_M BITFIELD_MASK(1) /* Bit 19 - General/Unknown error */
454#define RSP1_ERROR_S 19
455#define RSP1_CC_ERROR_M BITFIELD_MASK(1) /* Bit 20 - Internal Card Control error */
456#define RSP1_CC_ERROR_S 20
457#define RSP1_CARD_ECC_FAILED_M BITFIELD_MASK(1) /* Bit 21 - Card internal ECC failed
458 * to correct data
459 */
460#define RSP1_CARD_ECC_FAILED_S 21
461#define RSP1_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 22 - Cmd not legal for the card state */
462#define RSP1_ILLEGAL_CMD_S 22
463#define RSP1_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 23 - CRC check of previous command failed
464 */
465#define RSP1_COM_CRC_ERROR_S 23
466#define RSP1_LOCK_UNLOCK_FAIL_M BITFIELD_MASK(1) /* Bit 24 - Card lock-unlock Cmd Seq error */
467#define RSP1_LOCK_UNLOCK_FAIL_S 24
468#define RSP1_CARD_LOCKED_M BITFIELD_MASK(1) /* Bit 25 - Card locked by the host */
469#define RSP1_CARD_LOCKED_S 25
470#define RSP1_WP_VIOLATION_M BITFIELD_MASK(1) /* Bit 26 - Attempt to program
471 * write-protected blocks
472 */
473#define RSP1_WP_VIOLATION_S 26
474#define RSP1_ERASE_PARAM_M BITFIELD_MASK(1) /* Bit 27 - Invalid erase blocks */
475#define RSP1_ERASE_PARAM_S 27
476#define RSP1_ERASE_SEQ_ERR_M BITFIELD_MASK(1) /* Bit 28 - Erase Cmd seq error */
477#define RSP1_ERASE_SEQ_ERR_S 28
478#define RSP1_BLK_LEN_ERR_M BITFIELD_MASK(1) /* Bit 29 - Block length error */
479#define RSP1_BLK_LEN_ERR_S 29
480#define RSP1_ADDR_ERR_M BITFIELD_MASK(1) /* Bit 30 - Misaligned address */
481#define RSP1_ADDR_ERR_S 30
482#define RSP1_OUT_OF_RANGE_M BITFIELD_MASK(1) /* Bit 31 - Cmd arg was out of range */
483#define RSP1_OUT_OF_RANGE_S 31
484
485
486#define RSP5_DATA_M BITFIELD_MASK(8) /* Bits [0:7] - data */
487#define RSP5_DATA_S 0
488#define RSP5_FLAGS_M BITFIELD_MASK(8) /* Bit [15:8] - Rsp flags */
489#define RSP5_FLAGS_S 8
490#define RSP5_STUFF_M BITFIELD_MASK(16) /* Bits [31:16] - Stuff bits */
491#define RSP5_STUFF_S 16
492
493/* ----------------------------------------------
494 * SDIO Command Response structures for SPI mode
495 * ----------------------------------------------
496 */
497#define SPIRSP4_IO_OCR_M BITFIELD_MASK(16) /* Bits [15:0] - Card's OCR Bits [23:8] */
498#define SPIRSP4_IO_OCR_S 0
499#define SPIRSP4_STUFF_M BITFIELD_MASK(3) /* Bits [18:16] - Stuff bits */
500#define SPIRSP4_STUFF_S 16
501#define SPIRSP4_MEM_PRESENT_M BITFIELD_MASK(1) /* Bit 19 - Memory present */
502#define SPIRSP4_MEM_PRESENT_S 19
503#define SPIRSP4_NUM_FUNCS_M BITFIELD_MASK(3) /* Bits [22:20] - Number of I/O funcs */
504#define SPIRSP4_NUM_FUNCS_S 20
505#define SPIRSP4_CARD_READY_M BITFIELD_MASK(1) /* Bit 23 - SDIO card ready */
506#define SPIRSP4_CARD_READY_S 23
507#define SPIRSP4_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - idle state */
508#define SPIRSP4_IDLE_STATE_S 24
509#define SPIRSP4_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */
510#define SPIRSP4_ILLEGAL_CMD_S 26
511#define SPIRSP4_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */
512#define SPIRSP4_COM_CRC_ERROR_S 27
513#define SPIRSP4_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error
514 */
515#define SPIRSP4_FUNC_NUM_ERROR_S 28
516#define SPIRSP4_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */
517#define SPIRSP4_PARAM_ERROR_S 30
518#define SPIRSP4_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */
519#define SPIRSP4_START_BIT_S 31
520
521#define SPIRSP5_DATA_M BITFIELD_MASK(8) /* Bits [23:16] - R/W Data */
522#define SPIRSP5_DATA_S 16
523#define SPIRSP5_IDLE_STATE_M BITFIELD_MASK(1) /* Bit 24 - Idle state */
524#define SPIRSP5_IDLE_STATE_S 24
525#define SPIRSP5_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 26 - Illegal Cmd error */
526#define SPIRSP5_ILLEGAL_CMD_S 26
527#define SPIRSP5_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 27 - COM CRC error */
528#define SPIRSP5_COM_CRC_ERROR_S 27
529#define SPIRSP5_FUNC_NUM_ERROR_M BITFIELD_MASK(1) /* Bit 28 - Function number error
530 */
531#define SPIRSP5_FUNC_NUM_ERROR_S 28
532#define SPIRSP5_PARAM_ERROR_M BITFIELD_MASK(1) /* Bit 30 - Parameter Error Bit */
533#define SPIRSP5_PARAM_ERROR_S 30
534#define SPIRSP5_START_BIT_M BITFIELD_MASK(1) /* Bit 31 - Start Bit */
535#define SPIRSP5_START_BIT_S 31
536
537/* RSP6 card status format; Pg 68 Physical Layer spec v 1.10 */
538#define RSP6STAT_AKE_SEQ_ERROR_M BITFIELD_MASK(1) /* Bit 3 - Authentication seq error
539 */
540#define RSP6STAT_AKE_SEQ_ERROR_S 3
541#define RSP6STAT_APP_CMD_M BITFIELD_MASK(1) /* Bit 5 - Card expects ACMD */
542#define RSP6STAT_APP_CMD_S 5
543#define RSP6STAT_READY_FOR_DATA_M BITFIELD_MASK(1) /* Bit 8 - Ready for data
544 * (buff empty)
545 */
546#define RSP6STAT_READY_FOR_DATA_S 8
547#define RSP6STAT_CURR_STATE_M BITFIELD_MASK(4) /* Bits [12:9] - Card state at
548 * Cmd reception
549 */
550#define RSP6STAT_CURR_STATE_S 9
551#define RSP6STAT_ERROR_M BITFIELD_MASK(1) /* Bit 13 - General/Unknown error Bit 19
552 */
553#define RSP6STAT_ERROR_S 13
554#define RSP6STAT_ILLEGAL_CMD_M BITFIELD_MASK(1) /* Bit 14 - Illegal cmd for
555 * card state Bit 22
556 */
557#define RSP6STAT_ILLEGAL_CMD_S 14
558#define RSP6STAT_COM_CRC_ERROR_M BITFIELD_MASK(1) /* Bit 15 - CRC previous command
559 * failed Bit 23
560 */
561#define RSP6STAT_COM_CRC_ERROR_S 15
562
563#define SDIOH_XFER_TYPE_READ SD_IO_OP_READ
564#define SDIOH_XFER_TYPE_WRITE SD_IO_OP_WRITE
565
566#endif /* _SDIO_H */
diff --git a/drivers/net/wireless/bcm4329/include/sdioh.h b/drivers/net/wireless/bcm4329/include/sdioh.h
new file mode 100644
index 00000000000..8123452eac2
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/sdioh.h
@@ -0,0 +1,299 @@
1/*
2 * SDIO Host Controller Spec header file
3 * Register map and definitions for the Standard Host Controller
4 *
5 * Copyright (C) 1999-2010, 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.13.18.1.16.3 2009/12/08 22:34: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_Capabilities_Reserved 0x044
65#define SD_MaxCurCap 0x048
66#define SD_MaxCurCap_Reserved 0x04C
67#define SD_ADMA_SysAddr 0x58
68#define SD_SlotInterruptStatus 0x0FC
69#define SD_HostControllerVersion 0x0FE
70
71/* SD specific registers in PCI config space */
72#define SD_SlotInfo 0x40
73
74/* SD_Capabilities reg (0x040) */
75#define CAP_TO_CLKFREQ_M BITFIELD_MASK(6)
76#define CAP_TO_CLKFREQ_S 0
77#define CAP_TO_CLKUNIT_M BITFIELD_MASK(1)
78#define CAP_TO_CLKUNIT_S 7
79#define CAP_BASECLK_M BITFIELD_MASK(6)
80#define CAP_BASECLK_S 8
81#define CAP_MAXBLOCK_M BITFIELD_MASK(2)
82#define CAP_MAXBLOCK_S 16
83#define CAP_ADMA2_M BITFIELD_MASK(1)
84#define CAP_ADMA2_S 19
85#define CAP_ADMA1_M BITFIELD_MASK(1)
86#define CAP_ADMA1_S 20
87#define CAP_HIGHSPEED_M BITFIELD_MASK(1)
88#define CAP_HIGHSPEED_S 21
89#define CAP_DMA_M BITFIELD_MASK(1)
90#define CAP_DMA_S 22
91#define CAP_SUSPEND_M BITFIELD_MASK(1)
92#define CAP_SUSPEND_S 23
93#define CAP_VOLT_3_3_M BITFIELD_MASK(1)
94#define CAP_VOLT_3_3_S 24
95#define CAP_VOLT_3_0_M BITFIELD_MASK(1)
96#define CAP_VOLT_3_0_S 25
97#define CAP_VOLT_1_8_M BITFIELD_MASK(1)
98#define CAP_VOLT_1_8_S 26
99#define CAP_64BIT_HOST_M BITFIELD_MASK(1)
100#define CAP_64BIT_HOST_S 28
101
102/* SD_MaxCurCap reg (0x048) */
103#define CAP_CURR_3_3_M BITFIELD_MASK(8)
104#define CAP_CURR_3_3_S 0
105#define CAP_CURR_3_0_M BITFIELD_MASK(8)
106#define CAP_CURR_3_0_S 8
107#define CAP_CURR_1_8_M BITFIELD_MASK(8)
108#define CAP_CURR_1_8_S 16
109
110/* SD_SysAddr: Offset 0x0000, Size 4 bytes */
111
112/* SD_BlockSize: Offset 0x004, Size 2 bytes */
113#define BLKSZ_BLKSZ_M BITFIELD_MASK(12)
114#define BLKSZ_BLKSZ_S 0
115#define BLKSZ_BNDRY_M BITFIELD_MASK(3)
116#define BLKSZ_BNDRY_S 12
117
118/* SD_BlockCount: Offset 0x006, size 2 bytes */
119
120/* SD_Arg0: Offset 0x008, size = 4 bytes */
121/* SD_TransferMode Offset 0x00C, size = 2 bytes */
122#define XFER_DMA_ENABLE_M BITFIELD_MASK(1)
123#define XFER_DMA_ENABLE_S 0
124#define XFER_BLK_COUNT_EN_M BITFIELD_MASK(1)
125#define XFER_BLK_COUNT_EN_S 1
126#define XFER_CMD_12_EN_M BITFIELD_MASK(1)
127#define XFER_CMD_12_EN_S 2
128#define XFER_DATA_DIRECTION_M BITFIELD_MASK(1)
129#define XFER_DATA_DIRECTION_S 4
130#define XFER_MULTI_BLOCK_M BITFIELD_MASK(1)
131#define XFER_MULTI_BLOCK_S 5
132
133/* SD_Command: Offset 0x00E, size = 2 bytes */
134/* resp_type field */
135#define RESP_TYPE_NONE 0
136#define RESP_TYPE_136 1
137#define RESP_TYPE_48 2
138#define RESP_TYPE_48_BUSY 3
139/* type field */
140#define CMD_TYPE_NORMAL 0
141#define CMD_TYPE_SUSPEND 1
142#define CMD_TYPE_RESUME 2
143#define CMD_TYPE_ABORT 3
144
145#define CMD_RESP_TYPE_M BITFIELD_MASK(2) /* Bits [0-1] - Response type */
146#define CMD_RESP_TYPE_S 0
147#define CMD_CRC_EN_M BITFIELD_MASK(1) /* Bit 3 - CRC enable */
148#define CMD_CRC_EN_S 3
149#define CMD_INDEX_EN_M BITFIELD_MASK(1) /* Bit 4 - Enable index checking */
150#define CMD_INDEX_EN_S 4
151#define CMD_DATA_EN_M BITFIELD_MASK(1) /* Bit 5 - Using DAT line */
152#define CMD_DATA_EN_S 5
153#define CMD_TYPE_M BITFIELD_MASK(2) /* Bit [6-7] - Normal, abort, resume, etc
154 */
155#define CMD_TYPE_S 6
156#define CMD_INDEX_M BITFIELD_MASK(6) /* Bits [8-13] - Command number */
157#define CMD_INDEX_S 8
158
159/* SD_BufferDataPort0 : Offset 0x020, size = 2 or 4 bytes */
160/* SD_BufferDataPort1 : Offset 0x022, size = 2 bytes */
161/* SD_PresentState : Offset 0x024, size = 4 bytes */
162#define PRES_CMD_INHIBIT_M BITFIELD_MASK(1) /* Bit 0 May use CMD */
163#define PRES_CMD_INHIBIT_S 0
164#define PRES_DAT_INHIBIT_M BITFIELD_MASK(1) /* Bit 1 May use DAT */
165#define PRES_DAT_INHIBIT_S 1
166#define PRES_DAT_BUSY_M BITFIELD_MASK(1) /* Bit 2 DAT is busy */
167#define PRES_DAT_BUSY_S 2
168#define PRES_PRESENT_RSVD_M BITFIELD_MASK(5) /* Bit [3-7] rsvd */
169#define PRES_PRESENT_RSVD_S 3
170#define PRES_WRITE_ACTIVE_M BITFIELD_MASK(1) /* Bit 8 Write is active */
171#define PRES_WRITE_ACTIVE_S 8
172#define PRES_READ_ACTIVE_M BITFIELD_MASK(1) /* Bit 9 Read is active */
173#define PRES_READ_ACTIVE_S 9
174#define PRES_WRITE_DATA_RDY_M BITFIELD_MASK(1) /* Bit 10 Write buf is avail */
175#define PRES_WRITE_DATA_RDY_S 10
176#define PRES_READ_DATA_RDY_M BITFIELD_MASK(1) /* Bit 11 Read buf data avail */
177#define PRES_READ_DATA_RDY_S 11
178#define PRES_CARD_PRESENT_M BITFIELD_MASK(1) /* Bit 16 Card present - debounced */
179#define PRES_CARD_PRESENT_S 16
180#define PRES_CARD_STABLE_M BITFIELD_MASK(1) /* Bit 17 Debugging */
181#define PRES_CARD_STABLE_S 17
182#define PRES_CARD_PRESENT_RAW_M BITFIELD_MASK(1) /* Bit 18 Not debounced */
183#define PRES_CARD_PRESENT_RAW_S 18
184#define PRES_WRITE_ENABLED_M BITFIELD_MASK(1) /* Bit 19 Write protected? */
185#define PRES_WRITE_ENABLED_S 19
186#define PRES_DAT_SIGNAL_M BITFIELD_MASK(4) /* Bit [20-23] Debugging */
187#define PRES_DAT_SIGNAL_S 20
188#define PRES_CMD_SIGNAL_M BITFIELD_MASK(1) /* Bit 24 Debugging */
189#define PRES_CMD_SIGNAL_S 24
190
191/* SD_HostCntrl: Offset 0x028, size = 1 bytes */
192#define HOST_LED_M BITFIELD_MASK(1) /* Bit 0 LED On/Off */
193#define HOST_LED_S 0
194#define HOST_DATA_WIDTH_M BITFIELD_MASK(1) /* Bit 1 4 bit enable */
195#define HOST_DATA_WIDTH_S 1
196#define HOST_HI_SPEED_EN_M BITFIELD_MASK(1) /* Bit 2 High speed vs low speed */
197#define HOST_DMA_SEL_S 3
198#define HOST_DMA_SEL_M BITFIELD_MASK(2) /* Bit 4:3 DMA Select */
199#define HOST_HI_SPEED_EN_S 2
200
201/* misc defines */
202#define SD1_MODE 0x1 /* SD Host Cntrlr Spec */
203#define SD4_MODE 0x2 /* SD Host Cntrlr Spec */
204
205/* SD_PwrCntrl: Offset 0x029, size = 1 bytes */
206#define PWR_BUS_EN_M BITFIELD_MASK(1) /* Bit 0 Power the bus */
207#define PWR_BUS_EN_S 0
208#define PWR_VOLTS_M BITFIELD_MASK(3) /* Bit [1-3] Voltage Select */
209#define PWR_VOLTS_S 1
210
211/* SD_SoftwareReset: Offset 0x02F, size = 1 byte */
212#define SW_RESET_ALL_M BITFIELD_MASK(1) /* Bit 0 Reset All */
213#define SW_RESET_ALL_S 0
214#define SW_RESET_CMD_M BITFIELD_MASK(1) /* Bit 1 CMD Line Reset */
215#define SW_RESET_CMD_S 1
216#define SW_RESET_DAT_M BITFIELD_MASK(1) /* Bit 2 DAT Line Reset */
217#define SW_RESET_DAT_S 2
218
219/* SD_IntrStatus: Offset 0x030, size = 2 bytes */
220/* Defs also serve SD_IntrStatusEnable and SD_IntrSignalEnable */
221#define INTSTAT_CMD_COMPLETE_M BITFIELD_MASK(1) /* Bit 0 */
222#define INTSTAT_CMD_COMPLETE_S 0
223#define INTSTAT_XFER_COMPLETE_M BITFIELD_MASK(1)
224#define INTSTAT_XFER_COMPLETE_S 1
225#define INTSTAT_BLOCK_GAP_EVENT_M BITFIELD_MASK(1)
226#define INTSTAT_BLOCK_GAP_EVENT_S 2
227#define INTSTAT_DMA_INT_M BITFIELD_MASK(1)
228#define INTSTAT_DMA_INT_S 3
229#define INTSTAT_BUF_WRITE_READY_M BITFIELD_MASK(1)
230#define INTSTAT_BUF_WRITE_READY_S 4
231#define INTSTAT_BUF_READ_READY_M BITFIELD_MASK(1)
232#define INTSTAT_BUF_READ_READY_S 5
233#define INTSTAT_CARD_INSERTION_M BITFIELD_MASK(1)
234#define INTSTAT_CARD_INSERTION_S 6
235#define INTSTAT_CARD_REMOVAL_M BITFIELD_MASK(1)
236#define INTSTAT_CARD_REMOVAL_S 7
237#define INTSTAT_CARD_INT_M BITFIELD_MASK(1)
238#define INTSTAT_CARD_INT_S 8
239#define INTSTAT_ERROR_INT_M BITFIELD_MASK(1) /* Bit 15 */
240#define INTSTAT_ERROR_INT_S 15
241
242/* SD_ErrorIntrStatus: Offset 0x032, size = 2 bytes */
243/* Defs also serve SD_ErrorIntrStatusEnable and SD_ErrorIntrSignalEnable */
244#define ERRINT_CMD_TIMEOUT_M BITFIELD_MASK(1)
245#define ERRINT_CMD_TIMEOUT_S 0
246#define ERRINT_CMD_CRC_M BITFIELD_MASK(1)
247#define ERRINT_CMD_CRC_S 1
248#define ERRINT_CMD_ENDBIT_M BITFIELD_MASK(1)
249#define ERRINT_CMD_ENDBIT_S 2
250#define ERRINT_CMD_INDEX_M BITFIELD_MASK(1)
251#define ERRINT_CMD_INDEX_S 3
252#define ERRINT_DATA_TIMEOUT_M BITFIELD_MASK(1)
253#define ERRINT_DATA_TIMEOUT_S 4
254#define ERRINT_DATA_CRC_M BITFIELD_MASK(1)
255#define ERRINT_DATA_CRC_S 5
256#define ERRINT_DATA_ENDBIT_M BITFIELD_MASK(1)
257#define ERRINT_DATA_ENDBIT_S 6
258#define ERRINT_CURRENT_LIMIT_M BITFIELD_MASK(1)
259#define ERRINT_CURRENT_LIMIT_S 7
260#define ERRINT_AUTO_CMD12_M BITFIELD_MASK(1)
261#define ERRINT_AUTO_CMD12_S 8
262#define ERRINT_VENDOR_M BITFIELD_MASK(4)
263#define ERRINT_VENDOR_S 12
264
265/* Also provide definitions in "normal" form to allow combined masks */
266#define ERRINT_CMD_TIMEOUT_BIT 0x0001
267#define ERRINT_CMD_CRC_BIT 0x0002
268#define ERRINT_CMD_ENDBIT_BIT 0x0004
269#define ERRINT_CMD_INDEX_BIT 0x0008
270#define ERRINT_DATA_TIMEOUT_BIT 0x0010
271#define ERRINT_DATA_CRC_BIT 0x0020
272#define ERRINT_DATA_ENDBIT_BIT 0x0040
273#define ERRINT_CURRENT_LIMIT_BIT 0x0080
274#define ERRINT_AUTO_CMD12_BIT 0x0100
275
276/* Masks to select CMD vs. DATA errors */
277#define ERRINT_CMD_ERRS (ERRINT_CMD_TIMEOUT_BIT | ERRINT_CMD_CRC_BIT |\
278 ERRINT_CMD_ENDBIT_BIT | ERRINT_CMD_INDEX_BIT)
279#define ERRINT_DATA_ERRS (ERRINT_DATA_TIMEOUT_BIT | ERRINT_DATA_CRC_BIT |\
280 ERRINT_DATA_ENDBIT_BIT)
281#define ERRINT_TRANSFER_ERRS (ERRINT_CMD_ERRS | ERRINT_DATA_ERRS)
282
283/* SD_WakeupCntr_BlockGapCntrl : Offset 0x02A , size = bytes */
284/* SD_ClockCntrl : Offset 0x02C , size = bytes */
285/* SD_SoftwareReset_TimeoutCntrl : Offset 0x02E , size = bytes */
286/* SD_IntrStatus : Offset 0x030 , size = bytes */
287/* SD_ErrorIntrStatus : Offset 0x032 , size = bytes */
288/* SD_IntrStatusEnable : Offset 0x034 , size = bytes */
289/* SD_ErrorIntrStatusEnable : Offset 0x036 , size = bytes */
290/* SD_IntrSignalEnable : Offset 0x038 , size = bytes */
291/* SD_ErrorIntrSignalEnable : Offset 0x03A , size = bytes */
292/* SD_CMD12ErrorStatus : Offset 0x03C , size = bytes */
293/* SD_Capabilities : Offset 0x040 , size = bytes */
294/* SD_MaxCurCap : Offset 0x048 , size = bytes */
295/* SD_MaxCurCap_Reserved: Offset 0x04C , size = bytes */
296/* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */
297/* SD_HostControllerVersion : Offset 0x0FE , size = bytes */
298
299#endif /* _SDIOH_H */
diff --git a/drivers/net/wireless/bcm4329/include/sdiovar.h b/drivers/net/wireless/bcm4329/include/sdiovar.h
new file mode 100644
index 00000000000..0179d4cb96d
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/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-2010, 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.5.14.2.16.2 2009/12/08 22:34:21 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/bcm4329/include/siutils.h b/drivers/net/wireless/bcm4329/include/siutils.h
new file mode 100644
index 00000000000..cb9f1407b73
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/siutils.h
@@ -0,0 +1,235 @@
1/*
2 * Misc utility routines for accessing the SOC Interconnects
3 * of Broadcom HNBU chips.
4 *
5 * Copyright (C) 1999-2010, 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.197.4.2.4.3.8.16 2010/06/23 21:36:05 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 int pmurev;
43 uint32 pmucaps;
44 uint boardtype;
45 uint boardvendor;
46 uint boardflags;
47 uint chip;
48 uint chiprev;
49 uint chippkg;
50 uint32 chipst;
51 bool issim;
52 uint socirev;
53 bool pci_pr32414;
54};
55
56#if defined(WLC_HIGH) && !defined(WLC_LOW)
57typedef struct si_pub si_t;
58#else
59typedef const struct si_pub si_t;
60#endif
61
62
63#define SI_OSH NULL
64
65
66#define XTAL 0x1
67#define PLL 0x2
68
69
70#define CLK_FAST 0
71#define CLK_DYNAMIC 2
72
73
74#define GPIO_DRV_PRIORITY 0
75#define GPIO_APP_PRIORITY 1
76#define GPIO_HI_PRIORITY 2
77
78
79#define GPIO_PULLUP 0
80#define GPIO_PULLDN 1
81
82
83#define GPIO_REGEVT 0
84#define GPIO_REGEVT_INTMSK 1
85#define GPIO_REGEVT_INTPOL 2
86
87
88#define SI_DEVPATH_BUFSZ 16
89
90
91#define SI_DOATTACH 1
92#define SI_PCIDOWN 2
93#define SI_PCIUP 3
94
95#define ISSIM_ENAB(sih) 0
96
97
98#if defined(BCMPMUCTL)
99#define PMUCTL_ENAB(sih) (BCMPMUCTL)
100#else
101#define PMUCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PMU)
102#endif
103
104
105#if defined(BCMPMUCTL) && BCMPMUCTL
106#define CCCTL_ENAB(sih) (0)
107#define CCPLL_ENAB(sih) (0)
108#else
109#define CCCTL_ENAB(sih) ((sih)->cccaps & CC_CAP_PWR_CTL)
110#define CCPLL_ENAB(sih) ((sih)->cccaps & CC_CAP_PLL_MASK)
111#endif
112
113typedef void (*gpio_handler_t)(uint32 stat, void *arg);
114
115
116
117extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype,
118 void *sdh, char **vars, uint *varsz);
119extern si_t *si_kattach(osl_t *osh);
120extern void si_detach(si_t *sih);
121extern bool si_pci_war16165(si_t *sih);
122
123extern uint si_corelist(si_t *sih, uint coreid[]);
124extern uint si_coreid(si_t *sih);
125extern uint si_flag(si_t *sih);
126extern uint si_intflag(si_t *sih);
127extern uint si_coreidx(si_t *sih);
128extern uint si_coreunit(si_t *sih);
129extern uint si_corevendor(si_t *sih);
130extern uint si_corerev(si_t *sih);
131extern void *si_osh(si_t *sih);
132extern void si_setosh(si_t *sih, osl_t *osh);
133extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val);
134extern void *si_coreregs(si_t *sih);
135extern void si_write_wrapperreg(si_t *sih, uint32 offset, uint32 val);
136extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val);
137extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val);
138extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val);
139extern bool si_iscoreup(si_t *sih);
140extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit);
141extern void *si_setcoreidx(si_t *sih, uint coreidx);
142extern void *si_setcore(si_t *sih, uint coreid, uint coreunit);
143extern void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val);
144extern void si_restore_core(si_t *sih, uint coreid, uint intr_val);
145extern int si_numaddrspaces(si_t *sih);
146extern uint32 si_addrspace(si_t *sih, uint asidx);
147extern uint32 si_addrspacesize(si_t *sih, uint asidx);
148extern int si_corebist(si_t *sih);
149extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits);
150extern void si_core_tofixup(si_t *sih);
151extern void si_core_disable(si_t *sih, uint32 bits);
152extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m);
153extern uint32 si_clock(si_t *sih);
154extern void si_clock_pmu_spuravoid(si_t *sih, bool spuravoid);
155extern uint32 si_alp_clock(si_t *sih);
156extern uint32 si_ilp_clock(si_t *sih);
157extern void si_pci_setup(si_t *sih, uint coremask);
158extern void si_pcmcia_init(si_t *sih);
159extern void si_setint(si_t *sih, int siflag);
160extern bool si_backplane64(si_t *sih);
161extern void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn,
162 void *intrsenabled_fn, void *intr_arg);
163extern void si_deregister_intr_callback(si_t *sih);
164extern void si_clkctl_init(si_t *sih);
165extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih);
166extern bool si_clkctl_cc(si_t *sih, uint mode);
167extern int si_clkctl_xtal(si_t *sih, uint what, bool on);
168extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val);
169extern bool si_backplane64(si_t *sih);
170extern void si_btcgpiowar(si_t *sih);
171extern bool si_deviceremoved(si_t *sih);
172extern uint32 si_socram_size(si_t *sih);
173
174extern void si_watchdog(si_t *sih, uint ticks);
175extern void si_watchdog_ms(si_t *sih, uint32 ms);
176extern void *si_gpiosetcore(si_t *sih);
177extern uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority);
178extern uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority);
179extern uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority);
180extern uint32 si_gpioin(si_t *sih);
181extern uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority);
182extern uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority);
183extern uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val);
184extern uint32 si_gpioreserve(si_t *sih, uint32 gpio_num, uint8 priority);
185extern uint32 si_gpiorelease(si_t *sih, uint32 gpio_num, uint8 priority);
186extern uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val);
187extern uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val);
188extern uint32 si_gpio_int_enable(si_t *sih, bool enable);
189
190
191extern void *si_gpio_handler_register(si_t *sih, uint32 e, bool lev, gpio_handler_t cb, void *arg);
192extern void si_gpio_handler_unregister(si_t *sih, void* gpioh);
193extern void si_gpio_handler_process(si_t *sih);
194
195
196extern bool si_pci_pmecap(si_t *sih);
197struct osl_info;
198extern bool si_pci_fastpmecap(struct osl_info *osh);
199extern bool si_pci_pmeclr(si_t *sih);
200extern void si_pci_pmeen(si_t *sih);
201extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset);
202
203extern void si_sdio_init(si_t *sih);
204
205extern uint16 si_d11_devid(si_t *sih);
206extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevice,
207 uint8 *pciclass, uint8 *pcisubclass, uint8 *pciprogif, uint8 *pciheader);
208
209#define si_eci_init(sih) (0)
210#define si_eci_notify_bt(sih, type, val, interrupt) (0)
211
212
213
214extern int si_devpath(si_t *sih, char *path, int size);
215
216extern char *si_getdevpathvar(si_t *sih, const char *name);
217extern int si_getdevpathintvar(si_t *sih, const char *name);
218
219
220extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val);
221extern void si_war42780_clkreq(si_t *sih, bool clkreq);
222extern void si_pci_sleep(si_t *sih);
223extern void si_pci_down(si_t *sih);
224extern void si_pci_up(si_t *sih);
225extern void si_pcie_war_ovr_disable(si_t *sih);
226extern void si_pcie_extendL1timer(si_t *sih, bool extend);
227extern int si_pci_fixcfg(si_t *sih);
228
229
230
231
232
233
234
235#endif
diff --git a/drivers/net/wireless/bcm4329/include/spid.h b/drivers/net/wireless/bcm4329/include/spid.h
new file mode 100644
index 00000000000..c740296de9a
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/spid.h
@@ -0,0 +1,153 @@
1/*
2 * SPI device spec header file
3 *
4 * Copyright (C) 2010, Broadcom Corporation
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
11 *
12 * $Id: spid.h,v 1.7.10.1.16.3 2009/04/09 19:23:14 Exp $
13 */
14
15#ifndef _SPI_H
16#define _SPI_H
17
18/*
19 * Brcm SPI Device Register Map.
20 *
21 */
22
23typedef volatile struct {
24 uint8 config; /* 0x00, len, endian, clock, speed, polarity, wakeup */
25 uint8 response_delay; /* 0x01, read response delay in bytes (corerev < 3) */
26 uint8 status_enable; /* 0x02, status-enable, intr with status, response_delay
27 * function selection, command/data error check
28 */
29 uint8 reset_bp; /* 0x03, reset on wlan/bt backplane reset (corerev >= 1) */
30 uint16 intr_reg; /* 0x04, Intr status register */
31 uint16 intr_en_reg; /* 0x06, Intr mask register */
32 uint32 status_reg; /* 0x08, RO, Status bits of last spi transfer */
33 uint16 f1_info_reg; /* 0x0c, RO, enabled, ready for data transfer, blocksize */
34 uint16 f2_info_reg; /* 0x0e, RO, enabled, ready for data transfer, blocksize */
35 uint16 f3_info_reg; /* 0x10, RO, enabled, ready for data transfer, blocksize */
36 uint32 test_read; /* 0x14, RO 0xfeedbead signature */
37 uint32 test_rw; /* 0x18, RW */
38 uint8 resp_delay_f0; /* 0x1c, read resp delay bytes for F0 (corerev >= 3) */
39 uint8 resp_delay_f1; /* 0x1d, read resp delay bytes for F1 (corerev >= 3) */
40 uint8 resp_delay_f2; /* 0x1e, read resp delay bytes for F2 (corerev >= 3) */
41 uint8 resp_delay_f3; /* 0x1f, read resp delay bytes for F3 (corerev >= 3) */
42} spi_regs_t;
43
44/* SPI device register offsets */
45#define SPID_CONFIG 0x00
46#define SPID_RESPONSE_DELAY 0x01
47#define SPID_STATUS_ENABLE 0x02
48#define SPID_RESET_BP 0x03 /* (corerev >= 1) */
49#define SPID_INTR_REG 0x04 /* 16 bits - Interrupt status */
50#define SPID_INTR_EN_REG 0x06 /* 16 bits - Interrupt mask */
51#define SPID_STATUS_REG 0x08 /* 32 bits */
52#define SPID_F1_INFO_REG 0x0C /* 16 bits */
53#define SPID_F2_INFO_REG 0x0E /* 16 bits */
54#define SPID_F3_INFO_REG 0x10 /* 16 bits */
55#define SPID_TEST_READ 0x14 /* 32 bits */
56#define SPID_TEST_RW 0x18 /* 32 bits */
57#define SPID_RESP_DELAY_F0 0x1c /* 8 bits (corerev >= 3) */
58#define SPID_RESP_DELAY_F1 0x1d /* 8 bits (corerev >= 3) */
59#define SPID_RESP_DELAY_F2 0x1e /* 8 bits (corerev >= 3) */
60#define SPID_RESP_DELAY_F3 0x1f /* 8 bits (corerev >= 3) */
61
62/* Bit masks for SPID_CONFIG device register */
63#define WORD_LENGTH_32 0x1 /* 0/1 16/32 bit word length */
64#define ENDIAN_BIG 0x2 /* 0/1 Little/Big Endian */
65#define CLOCK_PHASE 0x4 /* 0/1 clock phase delay */
66#define CLOCK_POLARITY 0x8 /* 0/1 Idle state clock polarity is low/high */
67#define HIGH_SPEED_MODE 0x10 /* 1/0 High Speed mode / Normal mode */
68#define INTR_POLARITY 0x20 /* 1/0 Interrupt active polarity is high/low */
69#define WAKE_UP 0x80 /* 0/1 Wake-up command from Host to WLAN */
70
71/* Bit mask for SPID_RESPONSE_DELAY device register */
72#define RESPONSE_DELAY_MASK 0xFF /* Configurable rd response delay in multiples of 8 bits */
73
74/* Bit mask for SPID_STATUS_ENABLE device register */
75#define STATUS_ENABLE 0x1 /* 1/0 Status sent/not sent to host after read/write */
76#define INTR_WITH_STATUS 0x2 /* 0/1 Do-not / do-interrupt if status is sent */
77#define RESP_DELAY_ALL 0x4 /* Applicability of resp delay to F1 or all func's read */
78#define DWORD_PKT_LEN_EN 0x8 /* Packet len denoted in dwords instead of bytes */
79#define CMD_ERR_CHK_EN 0x20 /* Command error check enable */
80#define DATA_ERR_CHK_EN 0x40 /* Data error check enable */
81
82/* Bit mask for SPID_RESET_BP device register */
83#define RESET_ON_WLAN_BP_RESET 0x4 /* enable reset for WLAN backplane */
84#define RESET_ON_BT_BP_RESET 0x8 /* enable reset for BT backplane */
85#define RESET_SPI 0x80 /* reset the above enabled logic */
86
87/* Bit mask for SPID_INTR_REG device register */
88#define DATA_UNAVAILABLE 0x0001 /* Requested data not available; Clear by writing a "1" */
89#define F2_F3_FIFO_RD_UNDERFLOW 0x0002
90#define F2_F3_FIFO_WR_OVERFLOW 0x0004
91#define COMMAND_ERROR 0x0008 /* Cleared by writing 1 */
92#define DATA_ERROR 0x0010 /* Cleared by writing 1 */
93#define F2_PACKET_AVAILABLE 0x0020
94#define F3_PACKET_AVAILABLE 0x0040
95#define F1_OVERFLOW 0x0080 /* Due to last write. Bkplane has pending write requests */
96#define MISC_INTR0 0x0100
97#define MISC_INTR1 0x0200
98#define MISC_INTR2 0x0400
99#define MISC_INTR3 0x0800
100#define MISC_INTR4 0x1000
101#define F1_INTR 0x2000
102#define F2_INTR 0x4000
103#define F3_INTR 0x8000
104
105/* Bit mask for 32bit SPID_STATUS_REG device register */
106#define STATUS_DATA_NOT_AVAILABLE 0x00000001
107#define STATUS_UNDERFLOW 0x00000002
108#define STATUS_OVERFLOW 0x00000004
109#define STATUS_F2_INTR 0x00000008
110#define STATUS_F3_INTR 0x00000010
111#define STATUS_F2_RX_READY 0x00000020
112#define STATUS_F3_RX_READY 0x00000040
113#define STATUS_HOST_CMD_DATA_ERR 0x00000080
114#define STATUS_F2_PKT_AVAILABLE 0x00000100
115#define STATUS_F2_PKT_LEN_MASK 0x000FFE00
116#define STATUS_F2_PKT_LEN_SHIFT 9
117#define STATUS_F3_PKT_AVAILABLE 0x00100000
118#define STATUS_F3_PKT_LEN_MASK 0xFFE00000
119#define STATUS_F3_PKT_LEN_SHIFT 21
120
121/* Bit mask for 16 bits SPID_F1_INFO_REG device register */
122#define F1_ENABLED 0x0001
123#define F1_RDY_FOR_DATA_TRANSFER 0x0002
124#define F1_MAX_PKT_SIZE 0x01FC
125
126/* Bit mask for 16 bits SPID_F2_INFO_REG device register */
127#define F2_ENABLED 0x0001
128#define F2_RDY_FOR_DATA_TRANSFER 0x0002
129#define F2_MAX_PKT_SIZE 0x3FFC
130
131/* Bit mask for 16 bits SPID_F3_INFO_REG device register */
132#define F3_ENABLED 0x0001
133#define F3_RDY_FOR_DATA_TRANSFER 0x0002
134#define F3_MAX_PKT_SIZE 0x3FFC
135
136/* Bit mask for 32 bits SPID_TEST_READ device register read in 16bit LE mode */
137#define TEST_RO_DATA_32BIT_LE 0xFEEDBEAD
138
139/* Maximum number of I/O funcs */
140#define SPI_MAX_IOFUNCS 4
141
142#define SPI_MAX_PKT_LEN (2048*4)
143
144/* Misc defines */
145#define SPI_FUNC_0 0
146#define SPI_FUNC_1 1
147#define SPI_FUNC_2 2
148#define SPI_FUNC_3 3
149
150#define WAIT_F2RXFIFORDY 100
151#define WAIT_F2RXFIFORDY_DELAY 20
152
153#endif /* _SPI_H */
diff --git a/drivers/net/wireless/bcm4329/include/trxhdr.h b/drivers/net/wireless/bcm4329/include/trxhdr.h
new file mode 100644
index 00000000000..8f5eed9410e
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/trxhdr.h
@@ -0,0 +1,46 @@
1/*
2 * TRX image file header format.
3 *
4 * Copyright (C) 1999-2010, 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.11.310.1 2008/08/17 12:58:58 Exp $
25 */
26
27#include <typedefs.h>
28
29#define TRX_MAGIC 0x30524448 /* "HDR0" */
30#define TRX_VERSION 1 /* Version 1 */
31#define TRX_MAX_LEN 0x3A0000 /* Max length */
32#define TRX_NO_HEADER 1 /* Do not write TRX header */
33#define TRX_GZ_FILES 0x2 /* Contains up to TRX_MAX_OFFSET individual gzip files */
34#define TRX_MAX_OFFSET 3 /* Max number of individual files */
35#define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */
36
37struct trx_header {
38 uint32 magic; /* "HDR0" */
39 uint32 len; /* Length of file including header */
40 uint32 crc32; /* 32-bit CRC from flag_version to end of file */
41 uint32 flag_version; /* 0:15 flags, 16:31 version */
42 uint32 offsets[TRX_MAX_OFFSET]; /* Offsets of partitions from start of header */
43};
44
45/* Compatibility */
46typedef struct trx_header TRXHDR, *PTRXHDR;
diff --git a/drivers/net/wireless/bcm4329/include/typedefs.h b/drivers/net/wireless/bcm4329/include/typedefs.h
new file mode 100644
index 00000000000..4d9dd761ed6
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/typedefs.h
@@ -0,0 +1,303 @@
1/*
2 * Copyright (C) 1999-2010, 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.85.34.1.2.5 2009/01/27 04:09:40 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#if defined(TARGETOS_nucleus)
62
63#include <stddef.h>
64
65
66#define TYPEDEF_FLOAT_T
67#endif
68
69#if defined(_NEED_SIZE_T_)
70typedef long unsigned int size_t;
71#endif
72
73#ifdef __DJGPP__
74typedef long unsigned int size_t;
75#endif
76
77
78
79
80
81#define TYPEDEF_UINT
82#ifndef TARGETENV_android
83#define TYPEDEF_USHORT
84#define TYPEDEF_ULONG
85#endif
86#ifdef __KERNEL__
87#include <linux/version.h>
88#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19))
89#define TYPEDEF_BOOL
90#endif
91#endif
92
93
94
95
96
97#if defined(__GNUC__) && defined(__STRICT_ANSI__)
98#define TYPEDEF_INT64
99#define TYPEDEF_UINT64
100#endif
101
102
103#if defined(__ICL)
104
105#define TYPEDEF_INT64
106
107#if defined(__STDC__)
108#define TYPEDEF_UINT64
109#endif
110
111#endif
112
113#if !defined(__DJGPP__) && !defined(TARGETOS_nucleus)
114
115
116#if defined(__KERNEL__)
117
118#include <linux/types.h>
119
120#else
121
122
123#include <sys/types.h>
124
125#endif
126
127#endif
128
129
130
131
132#define USE_TYPEDEF_DEFAULTS
133
134#endif
135
136
137
138
139#ifdef USE_TYPEDEF_DEFAULTS
140#undef USE_TYPEDEF_DEFAULTS
141
142#ifndef TYPEDEF_BOOL
143typedef unsigned char bool;
144#endif
145
146
147
148#ifndef TYPEDEF_UCHAR
149typedef unsigned char uchar;
150#endif
151
152#ifndef TYPEDEF_USHORT
153typedef unsigned short ushort;
154#endif
155
156#ifndef TYPEDEF_UINT
157typedef unsigned int uint;
158#endif
159
160#ifndef TYPEDEF_ULONG
161typedef unsigned long ulong;
162#endif
163
164
165
166#ifndef TYPEDEF_UINT8
167typedef unsigned char uint8;
168#endif
169
170#ifndef TYPEDEF_UINT16
171typedef unsigned short uint16;
172#endif
173
174#ifndef TYPEDEF_UINT32
175typedef unsigned int uint32;
176#endif
177
178#ifndef TYPEDEF_UINT64
179typedef unsigned long long uint64;
180#endif
181
182#ifndef TYPEDEF_UINTPTR
183typedef unsigned int uintptr;
184#endif
185
186#ifndef TYPEDEF_INT8
187typedef signed char int8;
188#endif
189
190#ifndef TYPEDEF_INT16
191typedef signed short int16;
192#endif
193
194#ifndef TYPEDEF_INT32
195typedef signed int int32;
196#endif
197
198#ifndef TYPEDEF_INT64
199typedef signed long long int64;
200#endif
201
202
203
204#ifndef TYPEDEF_FLOAT32
205typedef float float32;
206#endif
207
208#ifndef TYPEDEF_FLOAT64
209typedef double float64;
210#endif
211
212
213
214#ifndef TYPEDEF_FLOAT_T
215
216#if defined(FLOAT32)
217typedef float32 float_t;
218#else
219typedef float64 float_t;
220#endif
221
222#endif
223
224
225
226#ifndef FALSE
227#define FALSE 0
228#endif
229
230#ifndef TRUE
231#define TRUE 1
232#endif
233
234#ifndef NULL
235#define NULL 0
236#endif
237
238#ifndef OFF
239#define OFF 0
240#endif
241
242#ifndef ON
243#define ON 1
244#endif
245
246#define AUTO (-1)
247
248
249
250#ifndef PTRSZ
251#define PTRSZ sizeof(char*)
252#endif
253
254
255
256#if defined(__GNUC__)
257 #define BWL_COMPILER_GNU
258#elif defined(__CC_ARM)
259 #define BWL_COMPILER_ARMCC
260#else
261 #error "Unknown compiler!"
262#endif
263
264
265#ifndef INLINE
266 #if defined(BWL_COMPILER_MICROSOFT)
267 #define INLINE __inline
268 #elif defined(BWL_COMPILER_GNU)
269 #define INLINE __inline__
270 #elif defined(BWL_COMPILER_ARMCC)
271 #define INLINE __inline
272 #else
273 #define INLINE
274 #endif
275#endif
276
277#undef TYPEDEF_BOOL
278#undef TYPEDEF_UCHAR
279#undef TYPEDEF_USHORT
280#undef TYPEDEF_UINT
281#undef TYPEDEF_ULONG
282#undef TYPEDEF_UINT8
283#undef TYPEDEF_UINT16
284#undef TYPEDEF_UINT32
285#undef TYPEDEF_UINT64
286#undef TYPEDEF_UINTPTR
287#undef TYPEDEF_INT8
288#undef TYPEDEF_INT16
289#undef TYPEDEF_INT32
290#undef TYPEDEF_INT64
291#undef TYPEDEF_FLOAT32
292#undef TYPEDEF_FLOAT64
293#undef TYPEDEF_FLOAT_T
294
295#endif
296
297
298#define UNUSED_PARAMETER(x) (void)(x)
299
300
301#include <bcmdefs.h>
302
303#endif
diff --git a/drivers/net/wireless/bcm4329/include/wlioctl.h b/drivers/net/wireless/bcm4329/include/wlioctl.h
new file mode 100644
index 00000000000..00c61f10782
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/include/wlioctl.h
@@ -0,0 +1,1673 @@
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-2010, 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.601.4.15.2.14.2.62.4.3 2011/02/09 23:31:02 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
42
43#define ACTION_FRAME_SIZE 1040
44
45typedef struct wl_action_frame {
46 struct ether_addr da;
47 uint16 len;
48 uint32 packetId;
49 uint8 data[ACTION_FRAME_SIZE];
50} wl_action_frame_t;
51
52#define WL_WIFI_ACTION_FRAME_SIZE sizeof(struct wl_action_frame)
53
54
55#define BWL_DEFAULT_PACKING
56#include <packed_section_start.h>
57
58#define RWL_ACTION_WIFI_CATEGORY 127
59#define RWL_WIFI_OUI_BYTE1 0x90
60#define RWL_WIFI_OUI_BYTE2 0x4C
61#define RWL_WIFI_OUI_BYTE3 0x0F
62#define RWL_WIFI_ACTION_FRAME_SIZE sizeof(struct dot11_action_wifi_vendor_specific)
63#define RWL_WIFI_DEFAULT 0x00
64#define RWL_WIFI_FIND_MY_PEER 0x09
65#define RWL_WIFI_FOUND_PEER 0x0A
66#define RWL_ACTION_WIFI_FRAG_TYPE 0x55
67
68typedef struct ssid_info
69{
70 uint8 ssid_len;
71 uint8 ssid[32];
72} ssid_info_t;
73
74typedef struct cnt_rx
75{
76 uint32 cnt_rxundec;
77 uint32 cnt_rxframe;
78} cnt_rx_t;
79
80
81
82#define RWL_REF_MAC_ADDRESS_OFFSET 17
83#define RWL_DUT_MAC_ADDRESS_OFFSET 23
84#define RWL_WIFI_CLIENT_CHANNEL_OFFSET 50
85#define RWL_WIFI_SERVER_CHANNEL_OFFSET 51
86
87
88
89
90
91#define WL_BSS_INFO_VERSION 108
92
93
94typedef struct wl_bss_info {
95 uint32 version;
96 uint32 length;
97 struct ether_addr BSSID;
98 uint16 beacon_period;
99 uint16 capability;
100 uint8 SSID_len;
101 uint8 SSID[32];
102 struct {
103 uint count;
104 uint8 rates[16];
105 } rateset;
106 chanspec_t chanspec;
107 uint16 atim_window;
108 uint8 dtim_period;
109 int16 RSSI;
110 int8 phy_noise;
111
112 uint8 n_cap;
113 uint32 nbss_cap;
114 uint8 ctl_ch;
115 uint32 reserved32[1];
116 uint8 flags;
117 uint8 reserved[3];
118 uint8 basic_mcs[MCSSET_LEN];
119
120 uint16 ie_offset;
121 uint32 ie_length;
122
123
124} wl_bss_info_t;
125
126typedef struct wlc_ssid {
127 uint32 SSID_len;
128 uchar SSID[32];
129} wlc_ssid_t;
130
131
132#define WL_BSSTYPE_INFRA 1
133#define WL_BSSTYPE_INDEP 0
134#define WL_BSSTYPE_ANY 2
135
136
137#define WL_SCANFLAGS_PASSIVE 0x01
138#define WL_SCANFLAGS_PROHIBITED 0x04
139
140typedef struct wl_scan_params {
141 wlc_ssid_t ssid;
142 struct ether_addr bssid;
143 int8 bss_type;
144 int8 scan_type;
145 int32 nprobes;
146 int32 active_time;
147 int32 passive_time;
148 int32 home_time;
149 int32 channel_num;
150 uint16 channel_list[1];
151} wl_scan_params_t;
152
153#define WL_SCAN_PARAMS_FIXED_SIZE 64
154
155
156#define WL_SCAN_PARAMS_COUNT_MASK 0x0000ffff
157#define WL_SCAN_PARAMS_NSSID_SHIFT 16
158
159#define WL_SCAN_ACTION_START 1
160#define WL_SCAN_ACTION_CONTINUE 2
161#define WL_SCAN_ACTION_ABORT 3
162
163#define ISCAN_REQ_VERSION 1
164
165
166typedef struct wl_iscan_params {
167 uint32 version;
168 uint16 action;
169 uint16 scan_duration;
170 wl_scan_params_t params;
171} wl_iscan_params_t;
172
173#define WL_ISCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_iscan_params_t, params) + sizeof(wlc_ssid_t))
174
175typedef struct wl_scan_results {
176 uint32 buflen;
177 uint32 version;
178 uint32 count;
179 wl_bss_info_t bss_info[1];
180} wl_scan_results_t;
181
182#define WL_SCAN_RESULTS_FIXED_SIZE 12
183
184
185#define WL_SCAN_RESULTS_SUCCESS 0
186#define WL_SCAN_RESULTS_PARTIAL 1
187#define WL_SCAN_RESULTS_PENDING 2
188#define WL_SCAN_RESULTS_ABORTED 3
189#define WL_SCAN_RESULTS_NO_MEM 4
190
191#define ESCAN_REQ_VERSION 1
192
193typedef struct wl_escan_params {
194 uint32 version;
195 uint16 action;
196 uint16 sync_id;
197 wl_scan_params_t params;
198} wl_escan_params_t;
199
200#define WL_ESCAN_PARAMS_FIXED_SIZE (OFFSETOF(wl_escan_params_t, params) + sizeof(wlc_ssid_t))
201
202typedef struct wl_escan_result {
203 uint32 buflen;
204 uint32 version;
205 uint16 sync_id;
206 uint16 bss_count;
207 wl_bss_info_t bss_info[1];
208} wl_escan_result_t;
209
210#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(wl_escan_result_t) - sizeof(wl_bss_info_t))
211
212
213typedef struct wl_iscan_results {
214 uint32 status;
215 wl_scan_results_t results;
216} wl_iscan_results_t;
217
218#define WL_ISCAN_RESULTS_FIXED_SIZE \
219 (WL_SCAN_RESULTS_FIXED_SIZE + OFFSETOF(wl_iscan_results_t, results))
220
221#define WL_NUMRATES 16
222typedef struct wl_rateset {
223 uint32 count;
224 uint8 rates[WL_NUMRATES];
225} wl_rateset_t;
226
227
228typedef struct wl_uint32_list {
229
230 uint32 count;
231
232 uint32 element[1];
233} wl_uint32_list_t;
234
235
236typedef struct wl_assoc_params {
237 struct ether_addr bssid;
238 uint16 bssid_cnt;
239 int32 chanspec_num;
240 chanspec_t chanspec_list[1];
241} wl_assoc_params_t;
242#define WL_ASSOC_PARAMS_FIXED_SIZE (sizeof(wl_assoc_params_t) - sizeof(chanspec_t))
243
244
245typedef wl_assoc_params_t wl_reassoc_params_t;
246#define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE
247
248
249typedef struct wl_join_params {
250 wlc_ssid_t ssid;
251 wl_assoc_params_t params;
252} wl_join_params_t;
253#define WL_JOIN_PARAMS_FIXED_SIZE (sizeof(wl_join_params_t) - sizeof(chanspec_t))
254
255#define WLC_CNTRY_BUF_SZ 4
256
257typedef struct wl_country {
258 char country_abbrev[WLC_CNTRY_BUF_SZ];
259 int32 rev;
260 char ccode[WLC_CNTRY_BUF_SZ];
261} wl_country_t;
262
263typedef enum sup_auth_status {
264
265 WLC_SUP_DISCONNECTED = 0,
266 WLC_SUP_CONNECTING,
267 WLC_SUP_IDREQUIRED,
268 WLC_SUP_AUTHENTICATING,
269 WLC_SUP_AUTHENTICATED,
270 WLC_SUP_KEYXCHANGE,
271 WLC_SUP_KEYED,
272 WLC_SUP_TIMEOUT,
273 WLC_SUP_LAST_BASIC_STATE,
274
275
276 WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED,
277
278 WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE,
279
280 WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE,
281
282 WLC_SUP_KEYXCHANGE_PREP_M4,
283 WLC_SUP_KEYXCHANGE_WAIT_G1,
284 WLC_SUP_KEYXCHANGE_PREP_G2
285} sup_auth_status_t;
286
287
288#define CRYPTO_ALGO_OFF 0
289#define CRYPTO_ALGO_WEP1 1
290#define CRYPTO_ALGO_TKIP 2
291#define CRYPTO_ALGO_WEP128 3
292#define CRYPTO_ALGO_AES_CCM 4
293#define CRYPTO_ALGO_AES_OCB_MSDU 5
294#define CRYPTO_ALGO_AES_OCB_MPDU 6
295#define CRYPTO_ALGO_NALG 7
296#define CRYPTO_ALGO_SMS4 11
297
298#define WSEC_GEN_MIC_ERROR 0x0001
299#define WSEC_GEN_REPLAY 0x0002
300#define WSEC_GEN_ICV_ERROR 0x0004
301
302#define WL_SOFT_KEY (1 << 0)
303#define WL_PRIMARY_KEY (1 << 1)
304#define WL_KF_RES_4 (1 << 4)
305#define WL_KF_RES_5 (1 << 5)
306#define WL_IBSS_PEER_GROUP_KEY (1 << 6)
307
308typedef struct wl_wsec_key {
309 uint32 index;
310 uint32 len;
311 uint8 data[DOT11_MAX_KEY_SIZE];
312 uint32 pad_1[18];
313 uint32 algo;
314 uint32 flags;
315 uint32 pad_2[2];
316 int pad_3;
317 int iv_initialized;
318 int pad_4;
319
320 struct {
321 uint32 hi;
322 uint16 lo;
323 } rxiv;
324 uint32 pad_5[2];
325 struct ether_addr ea;
326} wl_wsec_key_t;
327
328#define WSEC_MIN_PSK_LEN 8
329#define WSEC_MAX_PSK_LEN 64
330
331
332#define WSEC_PASSPHRASE (1<<0)
333
334
335typedef struct {
336 ushort key_len;
337 ushort flags;
338 uint8 key[WSEC_MAX_PSK_LEN];
339} wsec_pmk_t;
340
341
342#define WEP_ENABLED 0x0001
343#define TKIP_ENABLED 0x0002
344#define AES_ENABLED 0x0004
345#define WSEC_SWFLAG 0x0008
346#define SES_OW_ENABLED 0x0040
347#define SMS4_ENABLED 0x0100
348
349
350#define WPA_AUTH_DISABLED 0x0000
351#define WPA_AUTH_NONE 0x0001
352#define WPA_AUTH_UNSPECIFIED 0x0002
353#define WPA_AUTH_PSK 0x0004
354
355#define WPA2_AUTH_UNSPECIFIED 0x0040
356#define WPA2_AUTH_PSK 0x0080
357#define BRCM_AUTH_PSK 0x0100
358#define BRCM_AUTH_DPT 0x0200
359#define WPA_AUTH_WAPI 0x0400
360
361#define WPA_AUTH_PFN_ANY 0xffffffff
362
363
364#define MAXPMKID 16
365
366typedef struct _pmkid {
367 struct ether_addr BSSID;
368 uint8 PMKID[WPA2_PMKID_LEN];
369} pmkid_t;
370
371typedef struct _pmkid_list {
372 uint32 npmkid;
373 pmkid_t pmkid[1];
374} pmkid_list_t;
375
376typedef struct _pmkid_cand {
377 struct ether_addr BSSID;
378 uint8 preauth;
379} pmkid_cand_t;
380
381typedef struct _pmkid_cand_list {
382 uint32 npmkid_cand;
383 pmkid_cand_t pmkid_cand[1];
384} pmkid_cand_list_t;
385
386
387
388
389typedef struct {
390 uint32 val;
391 struct ether_addr ea;
392} scb_val_t;
393
394
395
396typedef struct channel_info {
397 int hw_channel;
398 int target_channel;
399 int scan_channel;
400} channel_info_t;
401
402
403struct maclist {
404 uint count;
405 struct ether_addr ea[1];
406};
407
408
409typedef struct get_pktcnt {
410 uint rx_good_pkt;
411 uint rx_bad_pkt;
412 uint tx_good_pkt;
413 uint tx_bad_pkt;
414 uint rx_ocast_good_pkt;
415} get_pktcnt_t;
416
417
418typedef struct wl_ioctl {
419 uint cmd;
420 void *buf;
421 uint len;
422 uint8 set;
423 uint used;
424 uint needed;
425} wl_ioctl_t;
426
427
428
429#define WLC_IOCTL_MAGIC 0x14e46c77
430
431
432#define WLC_IOCTL_VERSION 1
433
434#define WLC_IOCTL_MAXLEN 8192
435#define WLC_IOCTL_SMLEN 256
436#define WLC_IOCTL_MEDLEN 1536
437
438
439
440#define WLC_GET_MAGIC 0
441#define WLC_GET_VERSION 1
442#define WLC_UP 2
443#define WLC_DOWN 3
444#define WLC_GET_LOOP 4
445#define WLC_SET_LOOP 5
446#define WLC_DUMP 6
447#define WLC_GET_MSGLEVEL 7
448#define WLC_SET_MSGLEVEL 8
449#define WLC_GET_PROMISC 9
450#define WLC_SET_PROMISC 10
451
452#define WLC_GET_RATE 12
453
454#define WLC_GET_INSTANCE 14
455
456
457
458
459#define WLC_GET_INFRA 19
460#define WLC_SET_INFRA 20
461#define WLC_GET_AUTH 21
462#define WLC_SET_AUTH 22
463#define WLC_GET_BSSID 23
464#define WLC_SET_BSSID 24
465#define WLC_GET_SSID 25
466#define WLC_SET_SSID 26
467#define WLC_RESTART 27
468
469#define WLC_GET_CHANNEL 29
470#define WLC_SET_CHANNEL 30
471#define WLC_GET_SRL 31
472#define WLC_SET_SRL 32
473#define WLC_GET_LRL 33
474#define WLC_SET_LRL 34
475#define WLC_GET_PLCPHDR 35
476#define WLC_SET_PLCPHDR 36
477#define WLC_GET_RADIO 37
478#define WLC_SET_RADIO 38
479#define WLC_GET_PHYTYPE 39
480#define WLC_DUMP_RATE 40
481#define WLC_SET_RATE_PARAMS 41
482
483
484#define WLC_GET_KEY 44
485#define WLC_SET_KEY 45
486#define WLC_GET_REGULATORY 46
487#define WLC_SET_REGULATORY 47
488#define WLC_GET_PASSIVE_SCAN 48
489#define WLC_SET_PASSIVE_SCAN 49
490#define WLC_SCAN 50
491#define WLC_SCAN_RESULTS 51
492#define WLC_DISASSOC 52
493#define WLC_REASSOC 53
494#define WLC_GET_ROAM_TRIGGER 54
495#define WLC_SET_ROAM_TRIGGER 55
496#define WLC_GET_ROAM_DELTA 56
497#define WLC_SET_ROAM_DELTA 57
498#define WLC_GET_ROAM_SCAN_PERIOD 58
499#define WLC_SET_ROAM_SCAN_PERIOD 59
500#define WLC_EVM 60
501#define WLC_GET_TXANT 61
502#define WLC_SET_TXANT 62
503#define WLC_GET_ANTDIV 63
504#define WLC_SET_ANTDIV 64
505
506
507#define WLC_GET_CLOSED 67
508#define WLC_SET_CLOSED 68
509#define WLC_GET_MACLIST 69
510#define WLC_SET_MACLIST 70
511#define WLC_GET_RATESET 71
512#define WLC_SET_RATESET 72
513
514#define WLC_LONGTRAIN 74
515#define WLC_GET_BCNPRD 75
516#define WLC_SET_BCNPRD 76
517#define WLC_GET_DTIMPRD 77
518#define WLC_SET_DTIMPRD 78
519#define WLC_GET_SROM 79
520#define WLC_SET_SROM 80
521#define WLC_GET_WEP_RESTRICT 81
522#define WLC_SET_WEP_RESTRICT 82
523#define WLC_GET_COUNTRY 83
524#define WLC_SET_COUNTRY 84
525#define WLC_GET_PM 85
526#define WLC_SET_PM 86
527#define WLC_GET_WAKE 87
528#define WLC_SET_WAKE 88
529
530#define WLC_GET_FORCELINK 90
531#define WLC_SET_FORCELINK 91
532#define WLC_FREQ_ACCURACY 92
533#define WLC_CARRIER_SUPPRESS 93
534#define WLC_GET_PHYREG 94
535#define WLC_SET_PHYREG 95
536#define WLC_GET_RADIOREG 96
537#define WLC_SET_RADIOREG 97
538#define WLC_GET_REVINFO 98
539#define WLC_GET_UCANTDIV 99
540#define WLC_SET_UCANTDIV 100
541#define WLC_R_REG 101
542#define WLC_W_REG 102
543
544
545#define WLC_GET_MACMODE 105
546#define WLC_SET_MACMODE 106
547#define WLC_GET_MONITOR 107
548#define WLC_SET_MONITOR 108
549#define WLC_GET_GMODE 109
550#define WLC_SET_GMODE 110
551#define WLC_GET_LEGACY_ERP 111
552#define WLC_SET_LEGACY_ERP 112
553#define WLC_GET_RX_ANT 113
554#define WLC_GET_CURR_RATESET 114
555#define WLC_GET_SCANSUPPRESS 115
556#define WLC_SET_SCANSUPPRESS 116
557#define WLC_GET_AP 117
558#define WLC_SET_AP 118
559#define WLC_GET_EAP_RESTRICT 119
560#define WLC_SET_EAP_RESTRICT 120
561#define WLC_SCB_AUTHORIZE 121
562#define WLC_SCB_DEAUTHORIZE 122
563#define WLC_GET_WDSLIST 123
564#define WLC_SET_WDSLIST 124
565#define WLC_GET_ATIM 125
566#define WLC_SET_ATIM 126
567#define WLC_GET_RSSI 127
568#define WLC_GET_PHYANTDIV 128
569#define WLC_SET_PHYANTDIV 129
570#define WLC_AP_RX_ONLY 130
571#define WLC_GET_TX_PATH_PWR 131
572#define WLC_SET_TX_PATH_PWR 132
573#define WLC_GET_WSEC 133
574#define WLC_SET_WSEC 134
575#define WLC_GET_PHY_NOISE 135
576#define WLC_GET_BSS_INFO 136
577#define WLC_GET_PKTCNTS 137
578#define WLC_GET_LAZYWDS 138
579#define WLC_SET_LAZYWDS 139
580#define WLC_GET_BANDLIST 140
581#define WLC_GET_BAND 141
582#define WLC_SET_BAND 142
583#define WLC_SCB_DEAUTHENTICATE 143
584#define WLC_GET_SHORTSLOT 144
585#define WLC_GET_SHORTSLOT_OVERRIDE 145
586#define WLC_SET_SHORTSLOT_OVERRIDE 146
587#define WLC_GET_SHORTSLOT_RESTRICT 147
588#define WLC_SET_SHORTSLOT_RESTRICT 148
589#define WLC_GET_GMODE_PROTECTION 149
590#define WLC_GET_GMODE_PROTECTION_OVERRIDE 150
591#define WLC_SET_GMODE_PROTECTION_OVERRIDE 151
592#define WLC_UPGRADE 152
593
594
595#define WLC_GET_IGNORE_BCNS 155
596#define WLC_SET_IGNORE_BCNS 156
597#define WLC_GET_SCB_TIMEOUT 157
598#define WLC_SET_SCB_TIMEOUT 158
599#define WLC_GET_ASSOCLIST 159
600#define WLC_GET_CLK 160
601#define WLC_SET_CLK 161
602#define WLC_GET_UP 162
603#define WLC_OUT 163
604#define WLC_GET_WPA_AUTH 164
605#define WLC_SET_WPA_AUTH 165
606#define WLC_GET_UCFLAGS 166
607#define WLC_SET_UCFLAGS 167
608#define WLC_GET_PWRIDX 168
609#define WLC_SET_PWRIDX 169
610#define WLC_GET_TSSI 170
611#define WLC_GET_SUP_RATESET_OVERRIDE 171
612#define WLC_SET_SUP_RATESET_OVERRIDE 172
613
614
615
616
617
618#define WLC_GET_PROTECTION_CONTROL 178
619#define WLC_SET_PROTECTION_CONTROL 179
620#define WLC_GET_PHYLIST 180
621#define WLC_ENCRYPT_STRENGTH 181
622#define WLC_DECRYPT_STATUS 182
623#define WLC_GET_KEY_SEQ 183
624#define WLC_GET_SCAN_CHANNEL_TIME 184
625#define WLC_SET_SCAN_CHANNEL_TIME 185
626#define WLC_GET_SCAN_UNASSOC_TIME 186
627#define WLC_SET_SCAN_UNASSOC_TIME 187
628#define WLC_GET_SCAN_HOME_TIME 188
629#define WLC_SET_SCAN_HOME_TIME 189
630#define WLC_GET_SCAN_NPROBES 190
631#define WLC_SET_SCAN_NPROBES 191
632#define WLC_GET_PRB_RESP_TIMEOUT 192
633#define WLC_SET_PRB_RESP_TIMEOUT 193
634#define WLC_GET_ATTEN 194
635#define WLC_SET_ATTEN 195
636#define WLC_GET_SHMEM 196
637#define WLC_SET_SHMEM 197
638
639
640#define WLC_SET_WSEC_TEST 200
641#define WLC_SCB_DEAUTHENTICATE_FOR_REASON 201
642#define WLC_TKIP_COUNTERMEASURES 202
643#define WLC_GET_PIOMODE 203
644#define WLC_SET_PIOMODE 204
645#define WLC_SET_ASSOC_PREFER 205
646#define WLC_GET_ASSOC_PREFER 206
647#define WLC_SET_ROAM_PREFER 207
648#define WLC_GET_ROAM_PREFER 208
649#define WLC_SET_LED 209
650#define WLC_GET_LED 210
651#define WLC_GET_INTERFERENCE_MODE 211
652#define WLC_SET_INTERFERENCE_MODE 212
653#define WLC_GET_CHANNEL_QA 213
654#define WLC_START_CHANNEL_QA 214
655#define WLC_GET_CHANNEL_SEL 215
656#define WLC_START_CHANNEL_SEL 216
657#define WLC_GET_VALID_CHANNELS 217
658#define WLC_GET_FAKEFRAG 218
659#define WLC_SET_FAKEFRAG 219
660#define WLC_GET_PWROUT_PERCENTAGE 220
661#define WLC_SET_PWROUT_PERCENTAGE 221
662#define WLC_SET_BAD_FRAME_PREEMPT 222
663#define WLC_GET_BAD_FRAME_PREEMPT 223
664#define WLC_SET_LEAP_LIST 224
665#define WLC_GET_LEAP_LIST 225
666#define WLC_GET_CWMIN 226
667#define WLC_SET_CWMIN 227
668#define WLC_GET_CWMAX 228
669#define WLC_SET_CWMAX 229
670#define WLC_GET_WET 230
671#define WLC_SET_WET 231
672#define WLC_GET_PUB 232
673
674
675#define WLC_GET_KEY_PRIMARY 235
676#define WLC_SET_KEY_PRIMARY 236
677
678#define WLC_GET_ACI_ARGS 238
679#define WLC_SET_ACI_ARGS 239
680#define WLC_UNSET_CALLBACK 240
681#define WLC_SET_CALLBACK 241
682#define WLC_GET_RADAR 242
683#define WLC_SET_RADAR 243
684#define WLC_SET_SPECT_MANAGMENT 244
685#define WLC_GET_SPECT_MANAGMENT 245
686#define WLC_WDS_GET_REMOTE_HWADDR 246
687#define WLC_WDS_GET_WPA_SUP 247
688#define WLC_SET_CS_SCAN_TIMER 248
689#define WLC_GET_CS_SCAN_TIMER 249
690#define WLC_MEASURE_REQUEST 250
691#define WLC_INIT 251
692#define WLC_SEND_QUIET 252
693#define WLC_KEEPALIVE 253
694#define WLC_SEND_PWR_CONSTRAINT 254
695#define WLC_UPGRADE_STATUS 255
696#define WLC_CURRENT_PWR 256
697#define WLC_GET_SCAN_PASSIVE_TIME 257
698#define WLC_SET_SCAN_PASSIVE_TIME 258
699#define WLC_LEGACY_LINK_BEHAVIOR 259
700#define WLC_GET_CHANNELS_IN_COUNTRY 260
701#define WLC_GET_COUNTRY_LIST 261
702#define WLC_GET_VAR 262
703#define WLC_SET_VAR 263
704#define WLC_NVRAM_GET 264
705#define WLC_NVRAM_SET 265
706#define WLC_NVRAM_DUMP 266
707#define WLC_REBOOT 267
708#define WLC_SET_WSEC_PMK 268
709#define WLC_GET_AUTH_MODE 269
710#define WLC_SET_AUTH_MODE 270
711#define WLC_GET_WAKEENTRY 271
712#define WLC_SET_WAKEENTRY 272
713#define WLC_NDCONFIG_ITEM 273
714#define WLC_NVOTPW 274
715#define WLC_OTPW 275
716#define WLC_IOV_BLOCK_GET 276
717#define WLC_IOV_MODULES_GET 277
718#define WLC_SOFT_RESET 278
719#define WLC_GET_ALLOW_MODE 279
720#define WLC_SET_ALLOW_MODE 280
721#define WLC_GET_DESIRED_BSSID 281
722#define WLC_SET_DESIRED_BSSID 282
723#define WLC_DISASSOC_MYAP 283
724#define WLC_GET_NBANDS 284
725#define WLC_GET_BANDSTATES 285
726#define WLC_GET_WLC_BSS_INFO 286
727#define WLC_GET_ASSOC_INFO 287
728#define WLC_GET_OID_PHY 288
729#define WLC_SET_OID_PHY 289
730#define WLC_SET_ASSOC_TIME 290
731#define WLC_GET_DESIRED_SSID 291
732#define WLC_GET_CHANSPEC 292
733#define WLC_GET_ASSOC_STATE 293
734#define WLC_SET_PHY_STATE 294
735#define WLC_GET_SCAN_PENDING 295
736#define WLC_GET_SCANREQ_PENDING 296
737#define WLC_GET_PREV_ROAM_REASON 297
738#define WLC_SET_PREV_ROAM_REASON 298
739#define WLC_GET_BANDSTATES_PI 299
740#define WLC_GET_PHY_STATE 300
741#define WLC_GET_BSS_WPA_RSN 301
742#define WLC_GET_BSS_WPA2_RSN 302
743#define WLC_GET_BSS_BCN_TS 303
744#define WLC_GET_INT_DISASSOC 304
745#define WLC_SET_NUM_PEERS 305
746#define WLC_GET_NUM_BSS 306
747#define WLC_LAST 307
748
749
750
751#define WL_RADIO_SW_DISABLE (1<<0)
752#define WL_RADIO_HW_DISABLE (1<<1)
753#define WL_RADIO_MPC_DISABLE (1<<2)
754#define WL_RADIO_COUNTRY_DISABLE (1<<3)
755
756
757#define WL_TXPWR_OVERRIDE (1U<<31)
758
759#define WL_PHY_PAVARS_LEN 6
760
761
762#define WL_DIAG_INTERRUPT 1
763#define WL_DIAG_LOOPBACK 2
764#define WL_DIAG_MEMORY 3
765#define WL_DIAG_LED 4
766#define WL_DIAG_REG 5
767#define WL_DIAG_SROM 6
768#define WL_DIAG_DMA 7
769
770#define WL_DIAGERR_SUCCESS 0
771#define WL_DIAGERR_FAIL_TO_RUN 1
772#define WL_DIAGERR_NOT_SUPPORTED 2
773#define WL_DIAGERR_INTERRUPT_FAIL 3
774#define WL_DIAGERR_LOOPBACK_FAIL 4
775#define WL_DIAGERR_SROM_FAIL 5
776#define WL_DIAGERR_SROM_BADCRC 6
777#define WL_DIAGERR_REG_FAIL 7
778#define WL_DIAGERR_MEMORY_FAIL 8
779#define WL_DIAGERR_NOMEM 9
780#define WL_DIAGERR_DMA_FAIL 10
781
782#define WL_DIAGERR_MEMORY_TIMEOUT 11
783#define WL_DIAGERR_MEMORY_BADPATTERN 12
784
785
786#define WLC_BAND_AUTO 0
787#define WLC_BAND_5G 1
788#define WLC_BAND_2G 2
789#define WLC_BAND_ALL 3
790
791
792#define WL_CHAN_FREQ_RANGE_2G 0
793#define WL_CHAN_FREQ_RANGE_5GL 1
794#define WL_CHAN_FREQ_RANGE_5GM 2
795#define WL_CHAN_FREQ_RANGE_5GH 3
796
797
798#define WLC_PHY_TYPE_A 0
799#define WLC_PHY_TYPE_B 1
800#define WLC_PHY_TYPE_G 2
801#define WLC_PHY_TYPE_N 4
802#define WLC_PHY_TYPE_LP 5
803#define WLC_PHY_TYPE_SSN 6
804#define WLC_PHY_TYPE_NULL 0xf
805
806
807#define WLC_MACMODE_DISABLED 0
808#define WLC_MACMODE_DENY 1
809#define WLC_MACMODE_ALLOW 2
810
811
812#define GMODE_LEGACY_B 0
813#define GMODE_AUTO 1
814#define GMODE_ONLY 2
815#define GMODE_B_DEFERRED 3
816#define GMODE_PERFORMANCE 4
817#define GMODE_LRS 5
818#define GMODE_MAX 6
819
820
821#define WLC_PLCP_AUTO -1
822#define WLC_PLCP_SHORT 0
823#define WLC_PLCP_LONG 1
824
825
826#define WLC_PROTECTION_AUTO -1
827#define WLC_PROTECTION_OFF 0
828#define WLC_PROTECTION_ON 1
829#define WLC_PROTECTION_MMHDR_ONLY 2
830#define WLC_PROTECTION_CTS_ONLY 3
831
832
833#define WLC_PROTECTION_CTL_OFF 0
834#define WLC_PROTECTION_CTL_LOCAL 1
835#define WLC_PROTECTION_CTL_OVERLAP 2
836
837
838#define WLC_N_PROTECTION_OFF 0
839#define WLC_N_PROTECTION_OPTIONAL 1
840#define WLC_N_PROTECTION_20IN40 2
841#define WLC_N_PROTECTION_MIXEDMODE 3
842
843
844#define WLC_N_PREAMBLE_MIXEDMODE 0
845#define WLC_N_PREAMBLE_GF 1
846
847
848#define WLC_N_BW_20ALL 0
849#define WLC_N_BW_40ALL 1
850#define WLC_N_BW_20IN2G_40IN5G 2
851
852
853#define WLC_N_TXRX_CHAIN0 0
854#define WLC_N_TXRX_CHAIN1 1
855
856
857#define WLC_N_SGI_20 0x01
858#define WLC_N_SGI_40 0x02
859
860
861#define PM_OFF 0
862#define PM_MAX 1
863#define PM_FAST 2
864
865#define LISTEN_INTERVAL 10
866
867#define INTERFERE_NONE 0
868#define NON_WLAN 1
869#define WLAN_MANUAL 2
870#define WLAN_AUTO 3
871#define AUTO_ACTIVE (1 << 7)
872
873typedef struct wl_aci_args {
874 int enter_aci_thresh;
875 int exit_aci_thresh;
876 int usec_spin;
877 int glitch_delay;
878 uint16 nphy_adcpwr_enter_thresh;
879 uint16 nphy_adcpwr_exit_thresh;
880 uint16 nphy_repeat_ctr;
881 uint16 nphy_num_samples;
882 uint16 nphy_undetect_window_sz;
883 uint16 nphy_b_energy_lo_aci;
884 uint16 nphy_b_energy_md_aci;
885 uint16 nphy_b_energy_hi_aci;
886} wl_aci_args_t;
887
888#define WL_ACI_ARGS_LEGACY_LENGTH 16
889
890
891
892#define WL_ERROR_VAL 0x00000001
893#define WL_TRACE_VAL 0x00000002
894#define WL_PRHDRS_VAL 0x00000004
895#define WL_PRPKT_VAL 0x00000008
896#define WL_INFORM_VAL 0x00000010
897#define WL_TMP_VAL 0x00000020
898#define WL_OID_VAL 0x00000040
899#define WL_RATE_VAL 0x00000080
900#define WL_ASSOC_VAL 0x00000100
901#define WL_PRUSR_VAL 0x00000200
902#define WL_PS_VAL 0x00000400
903#define WL_TXPWR_VAL 0x00000800
904#define WL_PORT_VAL 0x00001000
905#define WL_DUAL_VAL 0x00002000
906#define WL_WSEC_VAL 0x00004000
907#define WL_WSEC_DUMP_VAL 0x00008000
908#define WL_LOG_VAL 0x00010000
909#define WL_NRSSI_VAL 0x00020000
910#define WL_LOFT_VAL 0x00040000
911#define WL_REGULATORY_VAL 0x00080000
912#define WL_PHYCAL_VAL 0x00100000
913#define WL_RADAR_VAL 0x00200000
914#define WL_MPC_VAL 0x00400000
915#define WL_APSTA_VAL 0x00800000
916#define WL_DFS_VAL 0x01000000
917#define WL_BA_VAL 0x02000000
918#define WL_MBSS_VAL 0x04000000
919#define WL_CAC_VAL 0x08000000
920#define WL_AMSDU_VAL 0x10000000
921#define WL_AMPDU_VAL 0x20000000
922#define WL_FFPLD_VAL 0x40000000
923
924
925#define WL_DPT_VAL 0x00000001
926#define WL_SCAN_VAL 0x00000002
927#define WL_WOWL_VAL 0x00000004
928#define WL_COEX_VAL 0x00000008
929#define WL_RTDC_VAL 0x00000010
930#define WL_BTA_VAL 0x00000040
931
932
933#define WL_LED_NUMGPIO 16
934
935
936#define WL_LED_OFF 0
937#define WL_LED_ON 1
938#define WL_LED_ACTIVITY 2
939#define WL_LED_RADIO 3
940#define WL_LED_ARADIO 4
941#define WL_LED_BRADIO 5
942#define WL_LED_BGMODE 6
943#define WL_LED_WI1 7
944#define WL_LED_WI2 8
945#define WL_LED_WI3 9
946#define WL_LED_ASSOC 10
947#define WL_LED_INACTIVE 11
948#define WL_LED_ASSOCACT 12
949#define WL_LED_NUMBEHAVIOR 13
950
951
952#define WL_LED_BEH_MASK 0x7f
953#define WL_LED_AL_MASK 0x80
954
955
956#define WL_NUMCHANNELS 64
957#define WL_NUMCHANSPECS 100
958
959
960#define WL_WDS_WPA_ROLE_AUTH 0
961#define WL_WDS_WPA_ROLE_SUP 1
962#define WL_WDS_WPA_ROLE_AUTO 255
963
964
965#define WL_EVENTING_MASK_LEN 16
966
967
968#define VNDR_IE_CMD_LEN 4
969
970
971#define VNDR_IE_BEACON_FLAG 0x1
972#define VNDR_IE_PRBRSP_FLAG 0x2
973#define VNDR_IE_ASSOCRSP_FLAG 0x4
974#define VNDR_IE_AUTHRSP_FLAG 0x8
975#define VNDR_IE_PRBREQ_FLAG 0x10
976#define VNDR_IE_ASSOCREQ_FLAG 0x20
977#define VNDR_IE_CUSTOM_FLAG 0x100
978
979#define VNDR_IE_INFO_HDR_LEN (sizeof(uint32))
980
981typedef struct {
982 uint32 pktflag;
983 vndr_ie_t vndr_ie_data;
984} vndr_ie_info_t;
985
986typedef struct {
987 int iecount;
988 vndr_ie_info_t vndr_ie_list[1];
989} vndr_ie_buf_t;
990
991typedef struct {
992 char cmd[VNDR_IE_CMD_LEN];
993 vndr_ie_buf_t vndr_ie_buffer;
994} vndr_ie_setbuf_t;
995
996
997
998
999#define WL_JOIN_PREF_RSSI 1
1000#define WL_JOIN_PREF_WPA 2
1001#define WL_JOIN_PREF_BAND 3
1002
1003
1004#define WLJP_BAND_ASSOC_PREF 255
1005
1006
1007#define WL_WPA_ACP_MCS_ANY "\x00\x00\x00\x00"
1008
1009struct tsinfo_arg {
1010 uint8 octets[3];
1011};
1012
1013
1014#define NFIFO 6
1015
1016#define WL_CNT_T_VERSION 5
1017#define WL_CNT_EXT_T_VERSION 1
1018
1019typedef struct {
1020 uint16 version;
1021 uint16 length;
1022
1023
1024 uint32 txframe;
1025 uint32 txbyte;
1026 uint32 txretrans;
1027 uint32 txerror;
1028 uint32 txctl;
1029 uint32 txprshort;
1030 uint32 txserr;
1031 uint32 txnobuf;
1032 uint32 txnoassoc;
1033 uint32 txrunt;
1034 uint32 txchit;
1035 uint32 txcmiss;
1036
1037
1038 uint32 txuflo;
1039 uint32 txphyerr;
1040 uint32 txphycrs;
1041
1042
1043 uint32 rxframe;
1044 uint32 rxbyte;
1045 uint32 rxerror;
1046 uint32 rxctl;
1047 uint32 rxnobuf;
1048 uint32 rxnondata;
1049 uint32 rxbadds;
1050 uint32 rxbadcm;
1051 uint32 rxfragerr;
1052 uint32 rxrunt;
1053 uint32 rxgiant;
1054 uint32 rxnoscb;
1055 uint32 rxbadproto;
1056 uint32 rxbadsrcmac;
1057 uint32 rxbadda;
1058 uint32 rxfilter;
1059
1060
1061 uint32 rxoflo;
1062 uint32 rxuflo[NFIFO];
1063
1064 uint32 d11cnt_txrts_off;
1065 uint32 d11cnt_rxcrc_off;
1066 uint32 d11cnt_txnocts_off;
1067
1068
1069 uint32 dmade;
1070 uint32 dmada;
1071 uint32 dmape;
1072 uint32 reset;
1073 uint32 tbtt;
1074 uint32 txdmawar;
1075 uint32 pkt_callback_reg_fail;
1076
1077
1078 uint32 txallfrm;
1079 uint32 txrtsfrm;
1080 uint32 txctsfrm;
1081 uint32 txackfrm;
1082 uint32 txdnlfrm;
1083 uint32 txbcnfrm;
1084 uint32 txfunfl[8];
1085 uint32 txtplunfl;
1086 uint32 txphyerror;
1087 uint32 rxfrmtoolong;
1088 uint32 rxfrmtooshrt;
1089 uint32 rxinvmachdr;
1090 uint32 rxbadfcs;
1091 uint32 rxbadplcp;
1092 uint32 rxcrsglitch;
1093 uint32 rxstrt;
1094 uint32 rxdfrmucastmbss;
1095 uint32 rxmfrmucastmbss;
1096 uint32 rxcfrmucast;
1097 uint32 rxrtsucast;
1098 uint32 rxctsucast;
1099 uint32 rxackucast;
1100 uint32 rxdfrmocast;
1101 uint32 rxmfrmocast;
1102 uint32 rxcfrmocast;
1103 uint32 rxrtsocast;
1104 uint32 rxctsocast;
1105 uint32 rxdfrmmcast;
1106 uint32 rxmfrmmcast;
1107 uint32 rxcfrmmcast;
1108 uint32 rxbeaconmbss;
1109 uint32 rxdfrmucastobss;
1110 uint32 rxbeaconobss;
1111 uint32 rxrsptmout;
1112 uint32 bcntxcancl;
1113 uint32 rxf0ovfl;
1114 uint32 rxf1ovfl;
1115 uint32 rxf2ovfl;
1116 uint32 txsfovfl;
1117 uint32 pmqovfl;
1118 uint32 rxcgprqfrm;
1119 uint32 rxcgprsqovfl;
1120 uint32 txcgprsfail;
1121 uint32 txcgprssuc;
1122 uint32 prs_timeout;
1123 uint32 rxnack;
1124 uint32 frmscons;
1125 uint32 txnack;
1126 uint32 txglitch_nack;
1127 uint32 txburst;
1128
1129
1130 uint32 txfrag;
1131 uint32 txmulti;
1132 uint32 txfail;
1133 uint32 txretry;
1134 uint32 txretrie;
1135 uint32 rxdup;
1136 uint32 txrts;
1137 uint32 txnocts;
1138 uint32 txnoack;
1139 uint32 rxfrag;
1140 uint32 rxmulti;
1141 uint32 rxcrc;
1142 uint32 txfrmsnt;
1143 uint32 rxundec;
1144
1145
1146 uint32 tkipmicfaill;
1147 uint32 tkipcntrmsr;
1148 uint32 tkipreplay;
1149 uint32 ccmpfmterr;
1150 uint32 ccmpreplay;
1151 uint32 ccmpundec;
1152 uint32 fourwayfail;
1153 uint32 wepundec;
1154 uint32 wepicverr;
1155 uint32 decsuccess;
1156 uint32 tkipicverr;
1157 uint32 wepexcluded;
1158
1159 uint32 txchanrej;
1160 uint32 psmwds;
1161 uint32 phywatchdog;
1162
1163
1164 uint32 prq_entries_handled;
1165 uint32 prq_undirected_entries;
1166 uint32 prq_bad_entries;
1167 uint32 atim_suppress_count;
1168 uint32 bcn_template_not_ready;
1169 uint32 bcn_template_not_ready_done;
1170 uint32 late_tbtt_dpc;
1171
1172
1173 uint32 rx1mbps;
1174 uint32 rx2mbps;
1175 uint32 rx5mbps5;
1176 uint32 rx6mbps;
1177 uint32 rx9mbps;
1178 uint32 rx11mbps;
1179 uint32 rx12mbps;
1180 uint32 rx18mbps;
1181 uint32 rx24mbps;
1182 uint32 rx36mbps;
1183 uint32 rx48mbps;
1184 uint32 rx54mbps;
1185 uint32 rx108mbps;
1186 uint32 rx162mbps;
1187 uint32 rx216mbps;
1188 uint32 rx270mbps;
1189 uint32 rx324mbps;
1190 uint32 rx378mbps;
1191 uint32 rx432mbps;
1192 uint32 rx486mbps;
1193 uint32 rx540mbps;
1194
1195 uint32 pktengrxducast;
1196 uint32 pktengrxdmcast;
1197} wl_cnt_t;
1198
1199typedef struct {
1200 uint16 version;
1201 uint16 length;
1202
1203 uint32 rxampdu_sgi;
1204 uint32 rxampdu_stbc;
1205 uint32 rxmpdu_sgi;
1206 uint32 rxmpdu_stbc;
1207 uint32 rxmcs0_40M;
1208 uint32 rxmcs1_40M;
1209 uint32 rxmcs2_40M;
1210 uint32 rxmcs3_40M;
1211 uint32 rxmcs4_40M;
1212 uint32 rxmcs5_40M;
1213 uint32 rxmcs6_40M;
1214 uint32 rxmcs7_40M;
1215 uint32 rxmcs32_40M;
1216
1217 uint32 txfrmsnt_20Mlo;
1218 uint32 txfrmsnt_20Mup;
1219 uint32 txfrmsnt_40M;
1220
1221 uint32 rx_20ul;
1222} wl_cnt_ext_t;
1223
1224#define WL_RXDIV_STATS_T_VERSION 1
1225typedef struct {
1226 uint16 version;
1227 uint16 length;
1228
1229 uint32 rxant[4];
1230} wl_rxdiv_stats_t;
1231
1232#define WL_DELTA_STATS_T_VERSION 1
1233
1234typedef struct {
1235 uint16 version;
1236 uint16 length;
1237
1238
1239 uint32 txframe;
1240 uint32 txbyte;
1241 uint32 txretrans;
1242 uint32 txfail;
1243
1244
1245 uint32 rxframe;
1246 uint32 rxbyte;
1247
1248
1249 uint32 rx1mbps;
1250 uint32 rx2mbps;
1251 uint32 rx5mbps5;
1252 uint32 rx6mbps;
1253 uint32 rx9mbps;
1254 uint32 rx11mbps;
1255 uint32 rx12mbps;
1256 uint32 rx18mbps;
1257 uint32 rx24mbps;
1258 uint32 rx36mbps;
1259 uint32 rx48mbps;
1260 uint32 rx54mbps;
1261 uint32 rx108mbps;
1262 uint32 rx162mbps;
1263 uint32 rx216mbps;
1264 uint32 rx270mbps;
1265 uint32 rx324mbps;
1266 uint32 rx378mbps;
1267 uint32 rx432mbps;
1268 uint32 rx486mbps;
1269 uint32 rx540mbps;
1270} wl_delta_stats_t;
1271
1272#define WL_WME_CNT_VERSION 1
1273
1274typedef struct {
1275 uint32 packets;
1276 uint32 bytes;
1277} wl_traffic_stats_t;
1278
1279typedef struct {
1280 uint16 version;
1281 uint16 length;
1282
1283 wl_traffic_stats_t tx[AC_COUNT];
1284 wl_traffic_stats_t tx_failed[AC_COUNT];
1285 wl_traffic_stats_t rx[AC_COUNT];
1286 wl_traffic_stats_t rx_failed[AC_COUNT];
1287
1288 wl_traffic_stats_t forward[AC_COUNT];
1289
1290 wl_traffic_stats_t tx_expired[AC_COUNT];
1291
1292} wl_wme_cnt_t;
1293
1294
1295
1296#define WLC_ROAM_TRIGGER_DEFAULT 0
1297#define WLC_ROAM_TRIGGER_BANDWIDTH 1
1298#define WLC_ROAM_TRIGGER_DISTANCE 2
1299#define WLC_ROAM_TRIGGER_MAX_VALUE 2
1300
1301
1302enum {
1303 PFN_LIST_ORDER,
1304 PFN_RSSI
1305};
1306
1307enum {
1308 DISABLE,
1309 ENABLE
1310};
1311
1312#define SORT_CRITERIA_BIT 0
1313#define AUTO_NET_SWITCH_BIT 1
1314#define ENABLE_BKGRD_SCAN_BIT 2
1315#define IMMEDIATE_SCAN_BIT 3
1316#define AUTO_CONNECT_BIT 4
1317#define ENABLE_BD_SCAN_BIT 5
1318#define ENABLE_ADAPTSCAN_BIT 6
1319
1320#define SORT_CRITERIA_MASK 0x01
1321#define AUTO_NET_SWITCH_MASK 0x02
1322#define ENABLE_BKGRD_SCAN_MASK 0x04
1323#define IMMEDIATE_SCAN_MASK 0x08
1324#define AUTO_CONNECT_MASK 0x10
1325#define ENABLE_BD_SCAN_MASK 0x20
1326#define ENABLE_ADAPTSCAN_MASK 0x40
1327
1328#define PFN_VERSION 1
1329
1330#define MAX_PFN_LIST_COUNT 16
1331
1332
1333typedef struct wl_pfn_param {
1334 int32 version;
1335 int32 scan_freq;
1336 int32 lost_network_timeout;
1337 int16 flags;
1338 int16 rssi_margin;
1339 int32 repeat_scan;
1340 int32 max_freq_adjust;
1341} wl_pfn_param_t;
1342
1343typedef struct wl_pfn {
1344 wlc_ssid_t ssid;
1345 int32 bss_type;
1346 int32 infra;
1347 int32 auth;
1348 uint32 wpa_auth;
1349 int32 wsec;
1350} wl_pfn_t;
1351
1352#define PNO_SCAN_MAX_FW 508*1000
1353#define PNO_SCAN_MAX_FW_SEC PNO_SCAN_MAX_FW/1000
1354#define PNO_SCAN_MIN_FW_SEC 10
1355
1356
1357#define TOE_TX_CSUM_OL 0x00000001
1358#define TOE_RX_CSUM_OL 0x00000002
1359
1360
1361#define TOE_ERRTEST_TX_CSUM 0x00000001
1362#define TOE_ERRTEST_RX_CSUM 0x00000002
1363#define TOE_ERRTEST_RX_CSUM2 0x00000004
1364
1365struct toe_ol_stats_t {
1366
1367 uint32 tx_summed;
1368
1369
1370 uint32 tx_iph_fill;
1371 uint32 tx_tcp_fill;
1372 uint32 tx_udp_fill;
1373 uint32 tx_icmp_fill;
1374
1375
1376 uint32 rx_iph_good;
1377 uint32 rx_iph_bad;
1378 uint32 rx_tcp_good;
1379 uint32 rx_tcp_bad;
1380 uint32 rx_udp_good;
1381 uint32 rx_udp_bad;
1382 uint32 rx_icmp_good;
1383 uint32 rx_icmp_bad;
1384
1385
1386 uint32 tx_tcp_errinj;
1387 uint32 tx_udp_errinj;
1388 uint32 tx_icmp_errinj;
1389
1390
1391 uint32 rx_tcp_errinj;
1392 uint32 rx_udp_errinj;
1393 uint32 rx_icmp_errinj;
1394};
1395
1396
1397#define ARP_OL_AGENT 0x00000001
1398#define ARP_OL_SNOOP 0x00000002
1399#define ARP_OL_HOST_AUTO_REPLY 0x00000004
1400#define ARP_OL_PEER_AUTO_REPLY 0x00000008
1401
1402
1403#define ARP_ERRTEST_REPLY_PEER 0x1
1404#define ARP_ERRTEST_REPLY_HOST 0x2
1405
1406#define ARP_MULTIHOMING_MAX 8
1407
1408
1409struct arp_ol_stats_t {
1410 uint32 host_ip_entries;
1411 uint32 host_ip_overflow;
1412
1413 uint32 arp_table_entries;
1414 uint32 arp_table_overflow;
1415
1416 uint32 host_request;
1417 uint32 host_reply;
1418 uint32 host_service;
1419
1420 uint32 peer_request;
1421 uint32 peer_request_drop;
1422 uint32 peer_reply;
1423 uint32 peer_reply_drop;
1424 uint32 peer_service;
1425};
1426
1427
1428
1429
1430
1431typedef struct wl_keep_alive_pkt {
1432 uint32 period_msec;
1433 uint16 len_bytes;
1434 uint8 data[1];
1435} wl_keep_alive_pkt_t;
1436
1437#define WL_KEEP_ALIVE_FIXED_LEN OFFSETOF(wl_keep_alive_pkt_t, data)
1438
1439
1440
1441
1442
1443typedef enum wl_pkt_filter_type {
1444 WL_PKT_FILTER_TYPE_PATTERN_MATCH
1445} wl_pkt_filter_type_t;
1446
1447#define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t
1448
1449
1450typedef struct wl_pkt_filter_pattern {
1451 uint32 offset;
1452 uint32 size_bytes;
1453 uint8 mask_and_pattern[1];
1454} wl_pkt_filter_pattern_t;
1455
1456
1457typedef struct wl_pkt_filter {
1458 uint32 id;
1459 uint32 type;
1460 uint32 negate_match;
1461 union {
1462 wl_pkt_filter_pattern_t pattern;
1463 } u;
1464} wl_pkt_filter_t;
1465
1466#define WL_PKT_FILTER_FIXED_LEN OFFSETOF(wl_pkt_filter_t, u)
1467#define WL_PKT_FILTER_PATTERN_FIXED_LEN OFFSETOF(wl_pkt_filter_pattern_t, mask_and_pattern)
1468
1469
1470typedef struct wl_pkt_filter_enable {
1471 uint32 id;
1472 uint32 enable;
1473} wl_pkt_filter_enable_t;
1474
1475
1476typedef struct wl_pkt_filter_list {
1477 uint32 num;
1478 wl_pkt_filter_t filter[1];
1479} wl_pkt_filter_list_t;
1480
1481#define WL_PKT_FILTER_LIST_FIXED_LEN OFFSETOF(wl_pkt_filter_list_t, filter)
1482
1483
1484typedef struct wl_pkt_filter_stats {
1485 uint32 num_pkts_matched;
1486 uint32 num_pkts_forwarded;
1487 uint32 num_pkts_discarded;
1488} wl_pkt_filter_stats_t;
1489
1490
1491typedef struct wl_seq_cmd_ioctl {
1492 uint32 cmd;
1493 uint32 len;
1494} wl_seq_cmd_ioctl_t;
1495
1496#define WL_SEQ_CMD_ALIGN_BYTES 4
1497
1498
1499#define WL_SEQ_CMDS_GET_IOCTL_FILTER(cmd) \
1500 (((cmd) == WLC_GET_MAGIC) || \
1501 ((cmd) == WLC_GET_VERSION) || \
1502 ((cmd) == WLC_GET_AP) || \
1503 ((cmd) == WLC_GET_INSTANCE))
1504
1505
1506
1507#define WL_PKTENG_PER_TX_START 0x01
1508#define WL_PKTENG_PER_TX_STOP 0x02
1509#define WL_PKTENG_PER_RX_START 0x04
1510#define WL_PKTENG_PER_RX_WITH_ACK_START 0x05
1511#define WL_PKTENG_PER_TX_WITH_ACK_START 0x06
1512#define WL_PKTENG_PER_RX_STOP 0x08
1513#define WL_PKTENG_PER_MASK 0xff
1514
1515#define WL_PKTENG_SYNCHRONOUS 0x100
1516
1517typedef struct wl_pkteng {
1518 uint32 flags;
1519 uint32 delay;
1520 uint32 nframes;
1521 uint32 length;
1522 uint8 seqno;
1523 struct ether_addr dest;
1524 struct ether_addr src;
1525} wl_pkteng_t;
1526
1527#define NUM_80211b_RATES 4
1528#define NUM_80211ag_RATES 8
1529#define NUM_80211n_RATES 32
1530#define NUM_80211_RATES (NUM_80211b_RATES+NUM_80211ag_RATES+NUM_80211n_RATES)
1531typedef struct wl_pkteng_stats {
1532 uint32 lostfrmcnt;
1533 int32 rssi;
1534 int32 snr;
1535 uint16 rxpktcnt[NUM_80211_RATES+1];
1536} wl_pkteng_stats_t;
1537
1538#define WL_WOWL_MAGIC (1 << 0)
1539#define WL_WOWL_NET (1 << 1)
1540#define WL_WOWL_DIS (1 << 2)
1541#define WL_WOWL_RETR (1 << 3)
1542#define WL_WOWL_BCN (1 << 4)
1543#define WL_WOWL_TST (1 << 5)
1544#define WL_WOWL_BCAST (1 << 15)
1545
1546#define MAGIC_PKT_MINLEN 102
1547
1548typedef struct {
1549 uint masksize;
1550 uint offset;
1551 uint patternoffset;
1552 uint patternsize;
1553
1554
1555} wl_wowl_pattern_t;
1556
1557typedef struct {
1558 uint count;
1559 wl_wowl_pattern_t pattern[1];
1560} wl_wowl_pattern_list_t;
1561
1562typedef struct {
1563 uint8 pci_wakeind;
1564 uint16 ucode_wakeind;
1565} wl_wowl_wakeind_t;
1566
1567
1568typedef struct wl_txrate_class {
1569 uint8 init_rate;
1570 uint8 min_rate;
1571 uint8 max_rate;
1572} wl_txrate_class_t;
1573
1574
1575
1576
1577#define WLC_OBSS_SCAN_PASSIVE_DWELL_DEFAULT 100
1578#define WLC_OBSS_SCAN_PASSIVE_DWELL_MIN 5
1579#define WLC_OBSS_SCAN_PASSIVE_DWELL_MAX 1000
1580#define WLC_OBSS_SCAN_ACTIVE_DWELL_DEFAULT 20
1581#define WLC_OBSS_SCAN_ACTIVE_DWELL_MIN 10
1582#define WLC_OBSS_SCAN_ACTIVE_DWELL_MAX 1000
1583#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_DEFAULT 300
1584#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MIN 10
1585#define WLC_OBSS_SCAN_WIDTHSCAN_INTERVAL_MAX 900
1586#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_DEFAULT 5
1587#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MIN 5
1588#define WLC_OBSS_SCAN_CHANWIDTH_TRANSITION_DLY_MAX 100
1589#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_DEFAULT 200
1590#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MIN 200
1591#define WLC_OBSS_SCAN_PASSIVE_TOTAL_PER_CHANNEL_MAX 10000
1592#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_DEFAULT 20
1593#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MIN 20
1594#define WLC_OBSS_SCAN_ACTIVE_TOTAL_PER_CHANNEL_MAX 10000
1595#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_DEFAULT 25
1596#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MIN 0
1597#define WLC_OBSS_SCAN_ACTIVITY_THRESHOLD_MAX 100
1598
1599
1600typedef struct wl_obss_scan_arg {
1601 int16 passive_dwell;
1602 int16 active_dwell;
1603 int16 bss_widthscan_interval;
1604 int16 passive_total;
1605 int16 active_total;
1606 int16 chanwidth_transition_delay;
1607 int16 activity_threshold;
1608} wl_obss_scan_arg_t;
1609#define WL_OBSS_SCAN_PARAM_LEN sizeof(wl_obss_scan_arg_t)
1610#define WL_MIN_NUM_OBSS_SCAN_ARG 7
1611
1612#define WL_COEX_INFO_MASK 0x07
1613#define WL_COEX_INFO_REQ 0x01
1614#define WL_COEX_40MHZ_INTOLERANT 0x02
1615#define WL_COEX_WIDTH20 0x04
1616
1617typedef struct wl_action_obss_coex_req {
1618 uint8 info;
1619 uint8 num;
1620 uint8 ch_list[1];
1621} wl_action_obss_coex_req_t;
1622
1623
1624#define MAX_RSSI_LEVELS 8
1625
1626
1627typedef struct wl_rssi_event {
1628
1629 uint32 rate_limit_msec;
1630
1631 uint8 num_rssi_levels;
1632
1633 int8 rssi_levels[MAX_RSSI_LEVELS];
1634} wl_rssi_event_t;
1635
1636
1637
1638#define WLFEATURE_DISABLE_11N 0x00000001
1639#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002
1640#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004
1641#define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008
1642#define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010
1643#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020
1644#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040
1645#define WLFEATURE_DISABLE_11N_GF 0x00000080
1646
1647
1648
1649#include <packed_section_end.h>
1650
1651
1652#include <packed_section_start.h>
1653
1654
1655typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_hdr {
1656 struct ether_addr staAddr;
1657 uint16 ieLen;
1658} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_hdr_t;
1659
1660typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_data {
1661 sta_prbreq_wps_ie_hdr_t hdr;
1662 uint8 ieData[1];
1663} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_data_t;
1664
1665typedef BWL_PRE_PACKED_STRUCT struct sta_prbreq_wps_ie_list {
1666 uint32 totLen;
1667 uint8 ieDataList[1];
1668} BWL_POST_PACKED_STRUCT sta_prbreq_wps_ie_list_t;
1669
1670
1671#include <packed_section_end.h>
1672
1673#endif
diff --git a/drivers/net/wireless/bcm4329/linux_osl.c b/drivers/net/wireless/bcm4329/linux_osl.c
new file mode 100644
index 00000000000..cf72a077bd9
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/linux_osl.c
@@ -0,0 +1,625 @@
1/*
2 * Linux OS Independent Layer
3 *
4 * Copyright (C) 1999-2010, 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.125.12.3.8.7 2010/05/04 21:10:04 Exp $
25 */
26
27
28#define LINUX_OSL
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#include <linux/mutex.h>
39
40#define PCI_CFG_RETRY 10
41
42#define OS_HANDLE_MAGIC 0x1234abcd
43#define BCM_MEM_FILENAME_LEN 24
44
45#ifdef DHD_USE_STATIC_BUF
46#define MAX_STATIC_BUF_NUM 16
47#define STATIC_BUF_SIZE (PAGE_SIZE*2)
48#define STATIC_BUF_TOTAL_LEN (MAX_STATIC_BUF_NUM*STATIC_BUF_SIZE)
49typedef struct bcm_static_buf {
50 struct mutex static_sem;
51 unsigned char *buf_ptr;
52 unsigned char buf_use[MAX_STATIC_BUF_NUM];
53} bcm_static_buf_t;
54
55static bcm_static_buf_t *bcm_static_buf = 0;
56
57#define MAX_STATIC_PKT_NUM 8
58typedef struct bcm_static_pkt {
59 struct sk_buff *skb_4k[MAX_STATIC_PKT_NUM];
60 struct sk_buff *skb_8k[MAX_STATIC_PKT_NUM];
61 struct mutex osl_pkt_sem;
62 unsigned char pkt_use[MAX_STATIC_PKT_NUM*2];
63} bcm_static_pkt_t;
64static bcm_static_pkt_t *bcm_static_skb = 0;
65
66#endif
67typedef struct bcm_mem_link {
68 struct bcm_mem_link *prev;
69 struct bcm_mem_link *next;
70 uint size;
71 int line;
72 char file[BCM_MEM_FILENAME_LEN];
73} bcm_mem_link_t;
74
75struct osl_info {
76 osl_pubinfo_t pub;
77 uint magic;
78 void *pdev;
79 uint malloced;
80 uint failed;
81 uint bustype;
82 bcm_mem_link_t *dbgmem_list;
83};
84
85static int16 linuxbcmerrormap[] =
86{ 0,
87 -EINVAL,
88 -EINVAL,
89 -EINVAL,
90 -EINVAL,
91 -EINVAL,
92 -EINVAL,
93 -EINVAL,
94 -EINVAL,
95 -EINVAL,
96 -EINVAL,
97 -EINVAL,
98 -EINVAL,
99 -EINVAL,
100 -E2BIG,
101 -E2BIG,
102 -EBUSY,
103 -EINVAL,
104 -EINVAL,
105 -EINVAL,
106 -EINVAL,
107 -EFAULT,
108 -ENOMEM,
109 -EOPNOTSUPP,
110 -EMSGSIZE,
111 -EINVAL,
112 -EPERM,
113 -ENOMEM,
114 -EINVAL,
115 -ERANGE,
116 -EINVAL,
117 -EINVAL,
118 -EINVAL,
119 -EINVAL,
120 -EINVAL,
121 -EIO,
122 -ENODEV,
123 -EINVAL,
124 -EIO,
125 -EIO,
126 -EINVAL,
127 -EINVAL,
128
129
130
131#if BCME_LAST != -41
132#error "You need to add a OS error translation in the linuxbcmerrormap \
133 for new error code defined in bcmutils.h"
134#endif
135};
136
137
138int
139osl_error(int bcmerror)
140{
141 if (bcmerror > 0)
142 bcmerror = 0;
143 else if (bcmerror < BCME_LAST)
144 bcmerror = BCME_ERROR;
145
146
147 return linuxbcmerrormap[-bcmerror];
148}
149
150void * dhd_os_prealloc(int section, unsigned long size);
151osl_t *
152osl_attach(void *pdev, uint bustype, bool pkttag)
153{
154 osl_t *osh;
155 gfp_t flags;
156
157 flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
158 osh = kmalloc(sizeof(osl_t), flags);
159 ASSERT(osh);
160
161 bzero(osh, sizeof(osl_t));
162
163
164 ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1));
165
166 osh->magic = OS_HANDLE_MAGIC;
167 osh->malloced = 0;
168 osh->failed = 0;
169 osh->dbgmem_list = NULL;
170 osh->pdev = pdev;
171 osh->pub.pkttag = pkttag;
172 osh->bustype = bustype;
173
174 switch (bustype) {
175 case PCI_BUS:
176 case SI_BUS:
177 case PCMCIA_BUS:
178 osh->pub.mmbus = TRUE;
179 break;
180 case JTAG_BUS:
181 case SDIO_BUS:
182 case USB_BUS:
183 case SPI_BUS:
184 osh->pub.mmbus = FALSE;
185 break;
186 default:
187 ASSERT(FALSE);
188 break;
189 }
190
191#ifdef DHD_USE_STATIC_BUF
192
193
194 if (!bcm_static_buf) {
195 if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(3, STATIC_BUF_SIZE+
196 STATIC_BUF_TOTAL_LEN))) {
197 printk("can not alloc static buf!\n");
198 }
199 else {
200 /* printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf); */
201 }
202
203 mutex_init(&bcm_static_buf->static_sem);
204
205
206 bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
207
208 }
209
210 if (!bcm_static_skb)
211 {
212 int i;
213 void *skb_buff_ptr = 0;
214 bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048);
215 skb_buff_ptr = dhd_os_prealloc(4, 0);
216
217 bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *)*16);
218 for (i = 0; i < MAX_STATIC_PKT_NUM*2; i++)
219 bcm_static_skb->pkt_use[i] = 0;
220
221 mutex_init(&bcm_static_skb->osl_pkt_sem);
222 }
223#endif
224 return osh;
225}
226
227void
228osl_detach(osl_t *osh)
229{
230 if (osh == NULL)
231 return;
232
233#ifdef DHD_USE_STATIC_BUF
234 if (bcm_static_buf) {
235 bcm_static_buf = 0;
236 }
237 if (bcm_static_skb) {
238 bcm_static_skb = 0;
239 }
240#endif
241 ASSERT(osh->magic == OS_HANDLE_MAGIC);
242 kfree(osh);
243}
244
245
246void*
247osl_pktget(osl_t *osh, uint len)
248{
249 struct sk_buff *skb;
250 gfp_t flags;
251
252 flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
253 if ((skb = __dev_alloc_skb(len, flags))) {
254 skb_put(skb, len);
255 skb->priority = 0;
256
257
258 osh->pub.pktalloced++;
259 }
260
261 return ((void*) skb);
262}
263
264
265void
266osl_pktfree(osl_t *osh, void *p, bool send)
267{
268 struct sk_buff *skb, *nskb;
269
270 skb = (struct sk_buff*) p;
271
272 if (send && osh->pub.tx_fn)
273 osh->pub.tx_fn(osh->pub.tx_ctx, p, 0);
274
275
276 while (skb) {
277 nskb = skb->next;
278 skb->next = NULL;
279
280
281 if (skb->destructor) {
282
283 dev_kfree_skb_any(skb);
284 } else {
285
286 dev_kfree_skb(skb);
287 }
288
289 osh->pub.pktalloced--;
290
291 skb = nskb;
292 }
293}
294
295#ifdef DHD_USE_STATIC_BUF
296void*
297osl_pktget_static(osl_t *osh, uint len)
298{
299 int i = 0;
300 struct sk_buff *skb;
301
302
303 if (len > (PAGE_SIZE*2))
304 {
305 printk("Do we really need this big skb??\n");
306 return osl_pktget(osh, len);
307 }
308
309
310 mutex_lock(&bcm_static_skb->osl_pkt_sem);
311 if (len <= PAGE_SIZE)
312 {
313
314 for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
315 {
316 if (bcm_static_skb->pkt_use[i] == 0)
317 break;
318 }
319
320 if (i != MAX_STATIC_PKT_NUM)
321 {
322 bcm_static_skb->pkt_use[i] = 1;
323 mutex_unlock(&bcm_static_skb->osl_pkt_sem);
324
325 skb = bcm_static_skb->skb_4k[i];
326 skb->tail = skb->data + len;
327 skb->len = len;
328
329 return skb;
330 }
331 }
332
333
334 for (i = 0; i < MAX_STATIC_PKT_NUM; i++)
335 {
336 if (bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] == 0)
337 break;
338 }
339
340 if (i != MAX_STATIC_PKT_NUM)
341 {
342 bcm_static_skb->pkt_use[i+MAX_STATIC_PKT_NUM] = 1;
343 mutex_unlock(&bcm_static_skb->osl_pkt_sem);
344 skb = bcm_static_skb->skb_8k[i];
345 skb->tail = skb->data + len;
346 skb->len = len;
347
348 return skb;
349 }
350
351
352
353 mutex_unlock(&bcm_static_skb->osl_pkt_sem);
354 printk("all static pkt in use!\n");
355 return osl_pktget(osh, len);
356}
357
358
359void
360osl_pktfree_static(osl_t *osh, void *p, bool send)
361{
362 int i;
363
364 for (i = 0; i < MAX_STATIC_PKT_NUM*2; i++)
365 {
366 if (p == bcm_static_skb->skb_4k[i])
367 {
368 mutex_lock(&bcm_static_skb->osl_pkt_sem);
369 bcm_static_skb->pkt_use[i] = 0;
370 mutex_unlock(&bcm_static_skb->osl_pkt_sem);
371
372
373 return;
374 }
375 }
376 return osl_pktfree(osh, p, send);
377}
378#endif
379uint32
380osl_pci_read_config(osl_t *osh, uint offset, uint size)
381{
382 uint val = 0;
383 uint retry = PCI_CFG_RETRY;
384
385 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
386
387
388 ASSERT(size == 4);
389
390 do {
391 pci_read_config_dword(osh->pdev, offset, &val);
392 if (val != 0xffffffff)
393 break;
394 } while (retry--);
395
396
397 return (val);
398}
399
400void
401osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
402{
403 uint retry = PCI_CFG_RETRY;
404
405 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
406
407
408 ASSERT(size == 4);
409
410 do {
411 pci_write_config_dword(osh->pdev, offset, val);
412 if (offset != PCI_BAR0_WIN)
413 break;
414 if (osl_pci_read_config(osh, offset, size) == val)
415 break;
416 } while (retry--);
417
418}
419
420
421uint
422osl_pci_bus(osl_t *osh)
423{
424 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
425
426 return ((struct pci_dev *)osh->pdev)->bus->number;
427}
428
429
430uint
431osl_pci_slot(osl_t *osh)
432{
433 ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
434
435 return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
436}
437
438static void
439osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write)
440{
441}
442
443void
444osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size)
445{
446 osl_pcmcia_attr(osh, offset, (char *) buf, size, FALSE);
447}
448
449void
450osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size)
451{
452 osl_pcmcia_attr(osh, offset, (char *) buf, size, TRUE);
453}
454
455
456
457void*
458osl_malloc(osl_t *osh, uint size)
459{
460 void *addr;
461 gfp_t flags;
462
463 if (osh)
464 ASSERT(osh->magic == OS_HANDLE_MAGIC);
465
466#ifdef DHD_USE_STATIC_BUF
467 if (bcm_static_buf)
468 {
469 int i = 0;
470 if ((size >= PAGE_SIZE)&&(size <= STATIC_BUF_SIZE))
471 {
472 mutex_lock(&bcm_static_buf->static_sem);
473
474 for (i = 0; i < MAX_STATIC_BUF_NUM; i++)
475 {
476 if (bcm_static_buf->buf_use[i] == 0)
477 break;
478 }
479
480 if (i == MAX_STATIC_BUF_NUM)
481 {
482 mutex_unlock(&bcm_static_buf->static_sem);
483 printk("all static buff in use!\n");
484 goto original;
485 }
486
487 bcm_static_buf->buf_use[i] = 1;
488 mutex_unlock(&bcm_static_buf->static_sem);
489
490 bzero(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i, size);
491 if (osh)
492 osh->malloced += size;
493
494 return ((void *)(bcm_static_buf->buf_ptr+STATIC_BUF_SIZE*i));
495 }
496 }
497original:
498#endif
499 flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
500 if ((addr = kmalloc(size, flags)) == NULL) {
501 if (osh)
502 osh->failed++;
503 return (NULL);
504 }
505 if (osh)
506 osh->malloced += size;
507
508 return (addr);
509}
510
511void
512osl_mfree(osl_t *osh, void *addr, uint size)
513{
514#ifdef DHD_USE_STATIC_BUF
515 if (bcm_static_buf)
516 {
517 if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr
518 <= ((unsigned char *)bcm_static_buf + STATIC_BUF_TOTAL_LEN)))
519 {
520 int buf_idx = 0;
521
522 buf_idx = ((unsigned char *)addr - bcm_static_buf->buf_ptr)/STATIC_BUF_SIZE;
523
524 mutex_lock(&bcm_static_buf->static_sem);
525 bcm_static_buf->buf_use[buf_idx] = 0;
526 mutex_unlock(&bcm_static_buf->static_sem);
527
528 if (osh) {
529 ASSERT(osh->magic == OS_HANDLE_MAGIC);
530 osh->malloced -= size;
531 }
532 return;
533 }
534 }
535#endif
536 if (osh) {
537 ASSERT(osh->magic == OS_HANDLE_MAGIC);
538 osh->malloced -= size;
539 }
540 kfree(addr);
541}
542
543uint
544osl_malloced(osl_t *osh)
545{
546 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
547 return (osh->malloced);
548}
549
550uint
551osl_malloc_failed(osl_t *osh)
552{
553 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
554 return (osh->failed);
555}
556
557void*
558osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap)
559{
560 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
561
562 return (pci_alloc_consistent(osh->pdev, size, (dma_addr_t*)pap));
563}
564
565void
566osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa)
567{
568 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
569
570 pci_free_consistent(osh->pdev, size, va, (dma_addr_t)pa);
571}
572
573uint
574osl_dma_map(osl_t *osh, void *va, uint size, int direction)
575{
576 int dir;
577
578 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
579 dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
580 return (pci_map_single(osh->pdev, va, size, dir));
581}
582
583void
584osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
585{
586 int dir;
587
588 ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
589 dir = (direction == DMA_TX)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE;
590 pci_unmap_single(osh->pdev, (uint32)pa, size, dir);
591}
592
593
594void
595osl_delay(uint usec)
596{
597 uint d;
598
599 while (usec > 0) {
600 d = MIN(usec, 1000);
601 udelay(d);
602 usec -= d;
603 }
604}
605
606
607
608void *
609osl_pktdup(osl_t *osh, void *skb)
610{
611 void * p;
612 gfp_t flags;
613
614 flags = (in_atomic()) ? GFP_ATOMIC : GFP_KERNEL;
615 if ((p = skb_clone((struct sk_buff*)skb, flags)) == NULL)
616 return NULL;
617
618
619 if (osh->pub.pkttag)
620 bzero((void*)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ);
621
622
623 osh->pub.pktalloced++;
624 return (p);
625}
diff --git a/drivers/net/wireless/bcm4329/miniopt.c b/drivers/net/wireless/bcm4329/miniopt.c
new file mode 100644
index 00000000000..6a184a75f06
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/miniopt.c
@@ -0,0 +1,163 @@
1/*
2 * Description.
3 *
4 * Copyright (C) 1999-2010, 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.c,v 1.1.6.4 2009/09/25 00:32:01 Exp $
24 */
25
26/* ---- Include Files ---------------------------------------------------- */
27
28#include <typedefs.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include "miniopt.h"
33
34
35/* ---- Public Variables ------------------------------------------------- */
36/* ---- Private Constants and Types -------------------------------------- */
37
38
39
40/* ---- Private Variables ------------------------------------------------ */
41/* ---- Private Function Prototypes -------------------------------------- */
42/* ---- Functions -------------------------------------------------------- */
43
44/* ----------------------------------------------------------------------- */
45void
46miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags)
47{
48 static const char *null_flags = "";
49
50 memset(t, 0, sizeof(miniopt_t));
51 t->name = name;
52 if (flags == NULL)
53 t->flags = null_flags;
54 else
55 t->flags = flags;
56 t->longflags = longflags;
57}
58
59
60/* ----------------------------------------------------------------------- */
61int
62miniopt(miniopt_t *t, char **argv)
63{
64 int keylen;
65 char *p, *eq, *valstr, *endptr = NULL;
66 int err = 0;
67
68 t->consumed = 0;
69 t->positional = FALSE;
70 memset(t->key, 0, MINIOPT_MAXKEY);
71 t->opt = '\0';
72 t->valstr = NULL;
73 t->good_int = FALSE;
74 valstr = NULL;
75
76 if (*argv == NULL) {
77 err = -1;
78 goto exit;
79 }
80
81 p = *argv++;
82 t->consumed++;
83
84 if (!t->opt_end && !strcmp(p, "--")) {
85 t->opt_end = TRUE;
86 if (*argv == NULL) {
87 err = -1;
88 goto exit;
89 }
90 p = *argv++;
91 t->consumed++;
92 }
93
94 if (t->opt_end) {
95 t->positional = TRUE;
96 valstr = p;
97 }
98 else if (!strncmp(p, "--", 2)) {
99 eq = strchr(p, '=');
100 if (eq == NULL && !t->longflags) {
101 fprintf(stderr,
102 "%s: missing \" = \" in long param \"%s\"\n", t->name, p);
103 err = 1;
104 goto exit;
105 }
106 keylen = eq ? (eq - (p + 2)) : (int)strlen(p) - 2;
107 if (keylen > 63) keylen = 63;
108 memcpy(t->key, p + 2, keylen);
109
110 if (eq) {
111 valstr = eq + 1;
112 if (*valstr == '\0') {
113 fprintf(stderr,
114 "%s: missing value after \" = \" in long param \"%s\"\n",
115 t->name, p);
116 err = 1;
117 goto exit;
118 }
119 }
120 }
121 else if (!strncmp(p, "-", 1)) {
122 t->opt = p[1];
123 if (strlen(p) > 2) {
124 fprintf(stderr,
125 "%s: only single char options, error on param \"%s\"\n",
126 t->name, p);
127 err = 1;
128 goto exit;
129 }
130 if (strchr(t->flags, t->opt)) {
131 /* this is a flag option, no value expected */
132 valstr = NULL;
133 } else {
134 if (*argv == NULL) {
135 fprintf(stderr,
136 "%s: missing value parameter after \"%s\"\n", t->name, p);
137 err = 1;
138 goto exit;
139 }
140 valstr = *argv;
141 argv++;
142 t->consumed++;
143 }
144 } else {
145 t->positional = TRUE;
146 valstr = p;
147 }
148
149 /* parse valstr as int just in case */
150 if (valstr) {
151 t->uval = (uint)strtoul(valstr, &endptr, 0);
152 t->val = (int)t->uval;
153 t->good_int = (*endptr == '\0');
154 }
155
156 t->valstr = valstr;
157
158exit:
159 if (err == 1)
160 t->opt = '?';
161
162 return err;
163}
diff --git a/drivers/net/wireless/bcm4329/sbutils.c b/drivers/net/wireless/bcm4329/sbutils.c
new file mode 100644
index 00000000000..46cd51010b7
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/sbutils.c
@@ -0,0 +1,1004 @@
1/*
2 * Misc utility routines for accessing chip-specific features
3 * of the SiliconBackplane-based Broadcom chips.
4 *
5 * Copyright (C) 1999-2010, 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.662.4.10.2.7.4.2 2010/04/19 05:48:48 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/* local prototypes */
42static uint _sb_coreidx(si_info_t *sii, uint32 sba);
43static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba,
44 uint ncores);
45static uint32 _sb_coresba(si_info_t *sii);
46static void *_sb_setcoreidx(si_info_t *sii, uint coreidx);
47
48#define SET_SBREG(sii, r, mask, val) \
49 W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val)))
50#define REGS2SB(va) (sbconfig_t*) ((int8*)(va) + SBCONFIGOFF)
51
52/* sonicsrev */
53#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT)
54#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT)
55
56#define R_SBREG(sii, sbr) sb_read_sbreg((sii), (sbr))
57#define W_SBREG(sii, sbr, v) sb_write_sbreg((sii), (sbr), (v))
58#define AND_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v)))
59#define OR_SBREG(sii, sbr, v) W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v)))
60
61static uint32
62sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr)
63{
64 uint8 tmp;
65 uint32 val, intr_val = 0;
66
67
68 /*
69 * compact flash only has 11 bits address, while we needs 12 bits address.
70 * MEM_SEG will be OR'd with other 11 bits address in hardware,
71 * so we program MEM_SEG with 12th bit when necessary(access sb regsiters).
72 * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special
73 */
74 if (PCMCIA(sii)) {
75 INTR_OFF(sii, intr_val);
76 tmp = 1;
77 OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1);
78 sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */
79 }
80
81 val = R_REG(sii->osh, sbr);
82
83 if (PCMCIA(sii)) {
84 tmp = 0;
85 OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1);
86 INTR_RESTORE(sii, intr_val);
87 }
88
89 return (val);
90}
91
92static void
93sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v)
94{
95 uint8 tmp;
96 volatile uint32 dummy;
97 uint32 intr_val = 0;
98
99
100 /*
101 * compact flash only has 11 bits address, while we needs 12 bits address.
102 * MEM_SEG will be OR'd with other 11 bits address in hardware,
103 * so we program MEM_SEG with 12th bit when necessary(access sb regsiters).
104 * For normal PCMCIA bus(CFTable_regwinsz > 2k), do nothing special
105 */
106 if (PCMCIA(sii)) {
107 INTR_OFF(sii, intr_val);
108 tmp = 1;
109 OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1);
110 sbr = (volatile uint32 *)((uintptr)sbr & ~(1 << 11)); /* mask out bit 11 */
111 }
112
113 if (BUSTYPE(sii->pub.bustype) == PCMCIA_BUS) {
114#ifdef IL_BIGENDIAN
115 dummy = R_REG(sii->osh, sbr);
116 W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff));
117 dummy = R_REG(sii->osh, sbr);
118 W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff));
119#else
120 dummy = R_REG(sii->osh, sbr);
121 W_REG(sii->osh, (volatile uint16 *)sbr, (uint16)(v & 0xffff));
122 dummy = R_REG(sii->osh, sbr);
123 W_REG(sii->osh, ((volatile uint16 *)sbr + 1), (uint16)((v >> 16) & 0xffff));
124#endif /* IL_BIGENDIAN */
125 } else
126 W_REG(sii->osh, sbr, v);
127
128 if (PCMCIA(sii)) {
129 tmp = 0;
130 OSL_PCMCIA_WRITE_ATTR(sii->osh, MEM_SEG, &tmp, 1);
131 INTR_RESTORE(sii, intr_val);
132 }
133}
134
135uint
136sb_coreid(si_t *sih)
137{
138 si_info_t *sii;
139 sbconfig_t *sb;
140
141 sii = SI_INFO(sih);
142 sb = REGS2SB(sii->curmap);
143
144 return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT);
145}
146
147uint
148sb_flag(si_t *sih)
149{
150 si_info_t *sii;
151 sbconfig_t *sb;
152
153 sii = SI_INFO(sih);
154 sb = REGS2SB(sii->curmap);
155
156 return R_SBREG(sii, &sb->sbtpsflag) & SBTPS_NUM0_MASK;
157}
158
159void
160sb_setint(si_t *sih, int siflag)
161{
162 si_info_t *sii;
163 sbconfig_t *sb;
164 uint32 vec;
165
166 sii = SI_INFO(sih);
167 sb = REGS2SB(sii->curmap);
168
169 if (siflag == -1)
170 vec = 0;
171 else
172 vec = 1 << siflag;
173 W_SBREG(sii, &sb->sbintvec, vec);
174}
175
176/* return core index of the core with address 'sba' */
177static uint
178_sb_coreidx(si_info_t *sii, uint32 sba)
179{
180 uint i;
181
182 for (i = 0; i < sii->numcores; i ++)
183 if (sba == sii->common_info->coresba[i])
184 return i;
185 return BADIDX;
186}
187
188/* return core address of the current core */
189static uint32
190_sb_coresba(si_info_t *sii)
191{
192 uint32 sbaddr;
193
194
195 switch (BUSTYPE(sii->pub.bustype)) {
196 case SI_BUS: {
197 sbconfig_t *sb = REGS2SB(sii->curmap);
198 sbaddr = sb_base(R_SBREG(sii, &sb->sbadmatch0));
199 break;
200 }
201
202 case PCI_BUS:
203 sbaddr = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32));
204 break;
205
206 case PCMCIA_BUS: {
207 uint8 tmp = 0;
208 OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1);
209 sbaddr = (uint32)tmp << 12;
210 OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1);
211 sbaddr |= (uint32)tmp << 16;
212 OSL_PCMCIA_READ_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1);
213 sbaddr |= (uint32)tmp << 24;
214 break;
215 }
216
217 case SPI_BUS:
218 case SDIO_BUS:
219 sbaddr = (uint32)(uintptr)sii->curmap;
220 break;
221
222
223 default:
224 sbaddr = BADCOREADDR;
225 break;
226 }
227
228 return sbaddr;
229}
230
231uint
232sb_corevendor(si_t *sih)
233{
234 si_info_t *sii;
235 sbconfig_t *sb;
236
237 sii = SI_INFO(sih);
238 sb = REGS2SB(sii->curmap);
239
240 return ((R_SBREG(sii, &sb->sbidhigh) & SBIDH_VC_MASK) >> SBIDH_VC_SHIFT);
241}
242
243uint
244sb_corerev(si_t *sih)
245{
246 si_info_t *sii;
247 sbconfig_t *sb;
248 uint sbidh;
249
250 sii = SI_INFO(sih);
251 sb = REGS2SB(sii->curmap);
252 sbidh = R_SBREG(sii, &sb->sbidhigh);
253
254 return (SBCOREREV(sbidh));
255}
256
257/* set core-specific control flags */
258void
259sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
260{
261 si_info_t *sii;
262 sbconfig_t *sb;
263 uint32 w;
264
265 sii = SI_INFO(sih);
266 sb = REGS2SB(sii->curmap);
267
268 ASSERT((val & ~mask) == 0);
269
270 /* mask and set */
271 w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) |
272 (val << SBTML_SICF_SHIFT);
273 W_SBREG(sii, &sb->sbtmstatelow, w);
274}
275
276/* set/clear core-specific control flags */
277uint32
278sb_core_cflags(si_t *sih, uint32 mask, uint32 val)
279{
280 si_info_t *sii;
281 sbconfig_t *sb;
282 uint32 w;
283
284 sii = SI_INFO(sih);
285 sb = REGS2SB(sii->curmap);
286
287 ASSERT((val & ~mask) == 0);
288
289 /* mask and set */
290 if (mask || val) {
291 w = (R_SBREG(sii, &sb->sbtmstatelow) & ~(mask << SBTML_SICF_SHIFT)) |
292 (val << SBTML_SICF_SHIFT);
293 W_SBREG(sii, &sb->sbtmstatelow, w);
294 }
295
296 /* return the new value
297 * for write operation, the following readback ensures the completion of write opration.
298 */
299 return (R_SBREG(sii, &sb->sbtmstatelow) >> SBTML_SICF_SHIFT);
300}
301
302/* set/clear core-specific status flags */
303uint32
304sb_core_sflags(si_t *sih, uint32 mask, uint32 val)
305{
306 si_info_t *sii;
307 sbconfig_t *sb;
308 uint32 w;
309
310 sii = SI_INFO(sih);
311 sb = REGS2SB(sii->curmap);
312
313 ASSERT((val & ~mask) == 0);
314 ASSERT((mask & ~SISF_CORE_BITS) == 0);
315
316 /* mask and set */
317 if (mask || val) {
318 w = (R_SBREG(sii, &sb->sbtmstatehigh) & ~(mask << SBTMH_SISF_SHIFT)) |
319 (val << SBTMH_SISF_SHIFT);
320 W_SBREG(sii, &sb->sbtmstatehigh, w);
321 }
322
323 /* return the new value */
324 return (R_SBREG(sii, &sb->sbtmstatehigh) >> SBTMH_SISF_SHIFT);
325}
326
327bool
328sb_iscoreup(si_t *sih)
329{
330 si_info_t *sii;
331 sbconfig_t *sb;
332
333 sii = SI_INFO(sih);
334 sb = REGS2SB(sii->curmap);
335
336 return ((R_SBREG(sii, &sb->sbtmstatelow) &
337 (SBTML_RESET | SBTML_REJ_MASK | (SICF_CLOCK_EN << SBTML_SICF_SHIFT))) ==
338 (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
339}
340
341/*
342 * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set operation,
343 * switch back to the original core, and return the new value.
344 *
345 * When using the silicon backplane, no fidleing with interrupts or core switches are needed.
346 *
347 * Also, when using pci/pcie, we can optimize away the core switching for pci registers
348 * and (on newer pci cores) chipcommon registers.
349 */
350uint
351sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
352{
353 uint origidx = 0;
354 uint32 *r = NULL;
355 uint w;
356 uint intr_val = 0;
357 bool fast = FALSE;
358 si_info_t *sii;
359
360 sii = SI_INFO(sih);
361
362 ASSERT(GOODIDX(coreidx));
363 ASSERT(regoff < SI_CORE_SIZE);
364 ASSERT((val & ~mask) == 0);
365
366 if (coreidx >= SI_MAXCORES)
367 return 0;
368
369 if (BUSTYPE(sii->pub.bustype) == SI_BUS) {
370 /* If internal bus, we can always get at everything */
371 fast = TRUE;
372 /* map if does not exist */
373 if (!sii->common_info->regs[coreidx]) {
374 sii->common_info->regs[coreidx] =
375 REG_MAP(sii->common_info->coresba[coreidx], SI_CORE_SIZE);
376 ASSERT(GOODREGS(sii->common_info->regs[coreidx]));
377 }
378 r = (uint32 *)((uchar *)sii->common_info->regs[coreidx] + regoff);
379 } else if (BUSTYPE(sii->pub.bustype) == PCI_BUS) {
380 /* If pci/pcie, we can get at pci/pcie regs and on newer cores to chipc */
381
382 if ((sii->common_info->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) {
383 /* Chipc registers are mapped at 12KB */
384
385 fast = TRUE;
386 r = (uint32 *)((char *)sii->curmap + PCI_16KB0_CCREGS_OFFSET + regoff);
387 } else if (sii->pub.buscoreidx == coreidx) {
388 /* pci registers are at either in the last 2KB of an 8KB window
389 * or, in pcie and pci rev 13 at 8KB
390 */
391 fast = TRUE;
392 if (SI_FAST(sii))
393 r = (uint32 *)((char *)sii->curmap +
394 PCI_16KB0_PCIREGS_OFFSET + regoff);
395 else
396 r = (uint32 *)((char *)sii->curmap +
397 ((regoff >= SBCONFIGOFF) ?
398 PCI_BAR0_PCISBR_OFFSET : PCI_BAR0_PCIREGS_OFFSET) +
399 regoff);
400 }
401 }
402
403 if (!fast) {
404 INTR_OFF(sii, intr_val);
405
406 /* save current core index */
407 origidx = si_coreidx(&sii->pub);
408
409 /* switch core */
410 r = (uint32*) ((uchar*)sb_setcoreidx(&sii->pub, coreidx) + regoff);
411 }
412 ASSERT(r != NULL);
413
414 /* mask and set */
415 if (mask || val) {
416 if (regoff >= SBCONFIGOFF) {
417 w = (R_SBREG(sii, r) & ~mask) | val;
418 W_SBREG(sii, r, w);
419 } else {
420 w = (R_REG(sii->osh, r) & ~mask) | val;
421 W_REG(sii->osh, r, w);
422 }
423 }
424
425 /* readback */
426 if (regoff >= SBCONFIGOFF)
427 w = R_SBREG(sii, r);
428 else {
429 if ((CHIPID(sii->pub.chip) == BCM5354_CHIP_ID) &&
430 (coreidx == SI_CC_IDX) &&
431 (regoff == OFFSETOF(chipcregs_t, watchdog))) {
432 w = val;
433 } else
434 w = R_REG(sii->osh, r);
435 }
436
437 if (!fast) {
438 /* restore core index */
439 if (origidx != coreidx)
440 sb_setcoreidx(&sii->pub, origidx);
441
442 INTR_RESTORE(sii, intr_val);
443 }
444
445 return (w);
446}
447
448/* Scan the enumeration space to find all cores starting from the given
449 * bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba'
450 * is the default core address at chip POR time and 'regs' is the virtual
451 * address that the default core is mapped at. 'ncores' is the number of
452 * cores expected on bus 'sbba'. It returns the total number of cores
453 * starting from bus 'sbba', inclusive.
454 */
455#define SB_MAXBUSES 2
456static uint
457_sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, uint numcores)
458{
459 uint next;
460 uint ncc = 0;
461 uint i;
462
463 if (bus >= SB_MAXBUSES) {
464 SI_ERROR(("_sb_scan: bus 0x%08x at level %d is too deep to scan\n", sbba, bus));
465 return 0;
466 }
467 SI_MSG(("_sb_scan: scan bus 0x%08x assume %u cores\n", sbba, numcores));
468
469 /* Scan all cores on the bus starting from core 0.
470 * Core addresses must be contiguous on each bus.
471 */
472 for (i = 0, next = sii->numcores; i < numcores && next < SB_BUS_MAXCORES; i++, next++) {
473 sii->common_info->coresba[next] = sbba + (i * SI_CORE_SIZE);
474
475 /* keep and reuse the initial register mapping */
476 if ((BUSTYPE(sii->pub.bustype) == SI_BUS) &&
477 (sii->common_info->coresba[next] == sba)) {
478 SI_MSG(("_sb_scan: reuse mapped regs %p for core %u\n", regs, next));
479 sii->common_info->regs[next] = regs;
480 }
481
482 /* change core to 'next' and read its coreid */
483 sii->curmap = _sb_setcoreidx(sii, next);
484 sii->curidx = next;
485
486 sii->common_info->coreid[next] = sb_coreid(&sii->pub);
487
488 /* core specific processing... */
489 /* chipc provides # cores */
490 if (sii->common_info->coreid[next] == CC_CORE_ID) {
491 chipcregs_t *cc = (chipcregs_t *)sii->curmap;
492 uint32 ccrev = sb_corerev(&sii->pub);
493
494 /* determine numcores - this is the total # cores in the chip */
495 if (((ccrev == 4) || (ccrev >= 6)))
496 numcores = (R_REG(sii->osh, &cc->chipid) & CID_CC_MASK) >>
497 CID_CC_SHIFT;
498 else {
499 /* Older chips */
500 uint chip = sii->pub.chip;
501
502 if (chip == BCM4306_CHIP_ID) /* < 4306c0 */
503 numcores = 6;
504 else if (chip == BCM4704_CHIP_ID)
505 numcores = 9;
506 else if (chip == BCM5365_CHIP_ID)
507 numcores = 7;
508 else {
509 SI_ERROR(("sb_chip2numcores: unsupported chip 0x%x\n",
510 chip));
511 ASSERT(0);
512 numcores = 1;
513 }
514 }
515 SI_MSG(("_sb_scan: there are %u cores in the chip %s\n", numcores,
516 sii->pub.issim ? "QT" : ""));
517 }
518 /* scan bridged SB(s) and add results to the end of the list */
519 else if (sii->common_info->coreid[next] == OCP_CORE_ID) {
520 sbconfig_t *sb = REGS2SB(sii->curmap);
521 uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1);
522 uint nsbcc;
523
524 sii->numcores = next + 1;
525
526 if ((nsbba & 0xfff00000) != SI_ENUM_BASE)
527 continue;
528 nsbba &= 0xfffff000;
529 if (_sb_coreidx(sii, nsbba) != BADIDX)
530 continue;
531
532 nsbcc = (R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >> 16;
533 nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc);
534 if (sbba == SI_ENUM_BASE)
535 numcores -= nsbcc;
536 ncc += nsbcc;
537 }
538 }
539
540 SI_MSG(("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba));
541
542 sii->numcores = i + ncc;
543 return sii->numcores;
544}
545
546/* scan the sb enumerated space to identify all cores */
547void
548sb_scan(si_t *sih, void *regs, uint devid)
549{
550 si_info_t *sii;
551 uint32 origsba;
552
553 sii = SI_INFO(sih);
554
555 /* Save the current core info and validate it later till we know
556 * for sure what is good and what is bad.
557 */
558 origsba = _sb_coresba(sii);
559
560 /* scan all SB(s) starting from SI_ENUM_BASE */
561 sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1);
562}
563
564/*
565 * This function changes logical "focus" to the indicated core;
566 * must be called with interrupts off.
567 * Moreover, callers should keep interrupts off during switching out of and back to d11 core
568 */
569void *
570sb_setcoreidx(si_t *sih, uint coreidx)
571{
572 si_info_t *sii;
573
574 sii = SI_INFO(sih);
575
576 if (coreidx >= sii->numcores)
577 return (NULL);
578
579 /*
580 * If the user has provided an interrupt mask enabled function,
581 * then assert interrupts are disabled before switching the core.
582 */
583 ASSERT((sii->intrsenabled_fn == NULL) || !(*(sii)->intrsenabled_fn)((sii)->intr_arg));
584
585 sii->curmap = _sb_setcoreidx(sii, coreidx);
586 sii->curidx = coreidx;
587
588 return (sii->curmap);
589}
590
591/* This function changes the logical "focus" to the indicated core.
592 * Return the current core's virtual address.
593 */
594static void *
595_sb_setcoreidx(si_info_t *sii, uint coreidx)
596{
597 uint32 sbaddr = sii->common_info->coresba[coreidx];
598 void *regs;
599
600 switch (BUSTYPE(sii->pub.bustype)) {
601 case SI_BUS:
602 /* map new one */
603 if (!sii->common_info->regs[coreidx]) {
604 sii->common_info->regs[coreidx] = REG_MAP(sbaddr, SI_CORE_SIZE);
605 ASSERT(GOODREGS(sii->common_info->regs[coreidx]));
606 }
607 regs = sii->common_info->regs[coreidx];
608 break;
609
610 case PCI_BUS:
611 /* point bar0 window */
612 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, sbaddr);
613 regs = sii->curmap;
614 break;
615
616 case PCMCIA_BUS: {
617 uint8 tmp = (sbaddr >> 12) & 0x0f;
618 OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR0, &tmp, 1);
619 tmp = (sbaddr >> 16) & 0xff;
620 OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR1, &tmp, 1);
621 tmp = (sbaddr >> 24) & 0xff;
622 OSL_PCMCIA_WRITE_ATTR(sii->osh, PCMCIA_ADDR2, &tmp, 1);
623 regs = sii->curmap;
624 break;
625 }
626 case SPI_BUS:
627 case SDIO_BUS:
628 /* map new one */
629 if (!sii->common_info->regs[coreidx]) {
630 sii->common_info->regs[coreidx] = (void *)(uintptr)sbaddr;
631 ASSERT(GOODREGS(sii->common_info->regs[coreidx]));
632 }
633 regs = sii->common_info->regs[coreidx];
634 break;
635
636
637 default:
638 ASSERT(0);
639 regs = NULL;
640 break;
641 }
642
643 return regs;
644}
645
646/* Return the address of sbadmatch0/1/2/3 register */
647static volatile uint32 *
648sb_admatch(si_info_t *sii, uint asidx)
649{
650 sbconfig_t *sb;
651 volatile uint32 *addrm;
652
653 sb = REGS2SB(sii->curmap);
654
655 switch (asidx) {
656 case 0:
657 addrm = &sb->sbadmatch0;
658 break;
659
660 case 1:
661 addrm = &sb->sbadmatch1;
662 break;
663
664 case 2:
665 addrm = &sb->sbadmatch2;
666 break;
667
668 case 3:
669 addrm = &sb->sbadmatch3;
670 break;
671
672 default:
673 SI_ERROR(("%s: Address space index (%d) out of range\n", __FUNCTION__, asidx));
674 return 0;
675 }
676
677 return (addrm);
678}
679
680/* Return the number of address spaces in current core */
681int
682sb_numaddrspaces(si_t *sih)
683{
684 si_info_t *sii;
685 sbconfig_t *sb;
686
687 sii = SI_INFO(sih);
688 sb = REGS2SB(sii->curmap);
689
690 /* + 1 because of enumeration space */
691 return ((R_SBREG(sii, &sb->sbidlow) & SBIDL_AR_MASK) >> SBIDL_AR_SHIFT) + 1;
692}
693
694/* Return the address of the nth address space in the current core */
695uint32
696sb_addrspace(si_t *sih, uint asidx)
697{
698 si_info_t *sii;
699
700 sii = SI_INFO(sih);
701
702 return (sb_base(R_SBREG(sii, sb_admatch(sii, asidx))));
703}
704
705/* Return the size of the nth address space in the current core */
706uint32
707sb_addrspacesize(si_t *sih, uint asidx)
708{
709 si_info_t *sii;
710
711 sii = SI_INFO(sih);
712
713 return (sb_size(R_SBREG(sii, sb_admatch(sii, asidx))));
714}
715
716
717/* do buffered registers update */
718void
719sb_commit(si_t *sih)
720{
721 si_info_t *sii;
722 uint origidx;
723 uint intr_val = 0;
724
725 sii = SI_INFO(sih);
726
727 origidx = sii->curidx;
728 ASSERT(GOODIDX(origidx));
729
730 INTR_OFF(sii, intr_val);
731
732 /* switch over to chipcommon core if there is one, else use pci */
733 if (sii->pub.ccrev != NOREV) {
734 chipcregs_t *ccregs = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
735
736 /* do the buffer registers update */
737 W_REG(sii->osh, &ccregs->broadcastaddress, SB_COMMIT);
738 W_REG(sii->osh, &ccregs->broadcastdata, 0x0);
739 } else
740 ASSERT(0);
741
742 /* restore core index */
743 sb_setcoreidx(sih, origidx);
744 INTR_RESTORE(sii, intr_val);
745}
746
747void
748sb_core_disable(si_t *sih, uint32 bits)
749{
750 si_info_t *sii;
751 volatile uint32 dummy;
752 sbconfig_t *sb;
753
754 sii = SI_INFO(sih);
755
756 ASSERT(GOODREGS(sii->curmap));
757 sb = REGS2SB(sii->curmap);
758
759 /* if core is already in reset, just return */
760 if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET)
761 return;
762
763 /* if clocks are not enabled, put into reset and return */
764 if ((R_SBREG(sii, &sb->sbtmstatelow) & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0)
765 goto disable;
766
767 /* set target reject and spin until busy is clear (preserve core-specific bits) */
768 OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ);
769 dummy = R_SBREG(sii, &sb->sbtmstatelow);
770 OSL_DELAY(1);
771 SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000);
772 if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY)
773 SI_ERROR(("%s: target state still busy\n", __FUNCTION__));
774
775 if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) {
776 OR_SBREG(sii, &sb->sbimstate, SBIM_RJ);
777 dummy = R_SBREG(sii, &sb->sbimstate);
778 OSL_DELAY(1);
779 SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000);
780 }
781
782 /* set reset and reject while enabling the clocks */
783 W_SBREG(sii, &sb->sbtmstatelow,
784 (((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
785 SBTML_REJ | SBTML_RESET));
786 dummy = R_SBREG(sii, &sb->sbtmstatelow);
787 OSL_DELAY(10);
788
789 /* don't forget to clear the initiator reject bit */
790 if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT)
791 AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ);
792
793disable:
794 /* leave reset and reject asserted */
795 W_SBREG(sii, &sb->sbtmstatelow, ((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET));
796 OSL_DELAY(1);
797}
798
799/* reset and re-enable a core
800 * inputs:
801 * bits - core specific bits that are set during and after reset sequence
802 * resetbits - core specific bits that are set only during reset sequence
803 */
804void
805sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
806{
807 si_info_t *sii;
808 sbconfig_t *sb;
809 volatile uint32 dummy;
810
811 sii = SI_INFO(sih);
812 ASSERT(GOODREGS(sii->curmap));
813 sb = REGS2SB(sii->curmap);
814
815 /*
816 * Must do the disable sequence first to work for arbitrary current core state.
817 */
818 sb_core_disable(sih, (bits | resetbits));
819
820 /*
821 * Now do the initialization sequence.
822 */
823
824 /* set reset while enabling the clock and forcing them on throughout the core */
825 W_SBREG(sii, &sb->sbtmstatelow,
826 (((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
827 SBTML_RESET));
828 dummy = R_SBREG(sii, &sb->sbtmstatelow);
829 OSL_DELAY(1);
830
831 if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR) {
832 W_SBREG(sii, &sb->sbtmstatehigh, 0);
833 }
834 if ((dummy = R_SBREG(sii, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO)) {
835 AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO));
836 }
837
838 /* clear reset and allow it to propagate throughout the core */
839 W_SBREG(sii, &sb->sbtmstatelow,
840 ((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT));
841 dummy = R_SBREG(sii, &sb->sbtmstatelow);
842 OSL_DELAY(1);
843
844 /* leave clock enabled */
845 W_SBREG(sii, &sb->sbtmstatelow, ((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT));
846 dummy = R_SBREG(sii, &sb->sbtmstatelow);
847 OSL_DELAY(1);
848}
849
850void
851sb_core_tofixup(si_t *sih)
852{
853 si_info_t *sii;
854 sbconfig_t *sb;
855
856 sii = SI_INFO(sih);
857
858 if ((BUSTYPE(sii->pub.bustype) != PCI_BUS) || PCIE(sii) ||
859 (PCI(sii) && (sii->pub.buscorerev >= 5)))
860 return;
861
862 ASSERT(GOODREGS(sii->curmap));
863 sb = REGS2SB(sii->curmap);
864
865 if (BUSTYPE(sii->pub.bustype) == SI_BUS) {
866 SET_SBREG(sii, &sb->sbimconfiglow,
867 SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
868 (0x5 << SBIMCL_RTO_SHIFT) | 0x3);
869 } else {
870 if (sb_coreid(sih) == PCI_CORE_ID) {
871 SET_SBREG(sii, &sb->sbimconfiglow,
872 SBIMCL_RTO_MASK | SBIMCL_STO_MASK,
873 (0x3 << SBIMCL_RTO_SHIFT) | 0x2);
874 } else {
875 SET_SBREG(sii, &sb->sbimconfiglow, (SBIMCL_RTO_MASK | SBIMCL_STO_MASK), 0);
876 }
877 }
878
879 sb_commit(sih);
880}
881
882/*
883 * Set the initiator timeout for the "master core".
884 * The master core is defined to be the core in control
885 * of the chip and so it issues accesses to non-memory
886 * locations (Because of dma *any* core can access memeory).
887 *
888 * The routine uses the bus to decide who is the master:
889 * SI_BUS => mips
890 * JTAG_BUS => chipc
891 * PCI_BUS => pci or pcie
892 * PCMCIA_BUS => pcmcia
893 * SDIO_BUS => pcmcia
894 *
895 * This routine exists so callers can disable initiator
896 * timeouts so accesses to very slow devices like otp
897 * won't cause an abort. The routine allows arbitrary
898 * settings of the service and request timeouts, though.
899 *
900 * Returns the timeout state before changing it or -1
901 * on error.
902 */
903
904#define TO_MASK (SBIMCL_RTO_MASK | SBIMCL_STO_MASK)
905
906uint32
907sb_set_initiator_to(si_t *sih, uint32 to, uint idx)
908{
909 si_info_t *sii;
910 uint origidx;
911 uint intr_val = 0;
912 uint32 tmp, ret = 0xffffffff;
913 sbconfig_t *sb;
914
915 sii = SI_INFO(sih);
916
917 if ((to & ~TO_MASK) != 0)
918 return ret;
919
920 /* Figure out the master core */
921 if (idx == BADIDX) {
922 switch (BUSTYPE(sii->pub.bustype)) {
923 case PCI_BUS:
924 idx = sii->pub.buscoreidx;
925 break;
926 case JTAG_BUS:
927 idx = SI_CC_IDX;
928 break;
929 case PCMCIA_BUS:
930 case SDIO_BUS:
931 idx = si_findcoreidx(sih, PCMCIA_CORE_ID, 0);
932 break;
933 case SI_BUS:
934 idx = si_findcoreidx(sih, MIPS33_CORE_ID, 0);
935 break;
936 default:
937 ASSERT(0);
938 }
939 if (idx == BADIDX)
940 return ret;
941 }
942
943 INTR_OFF(sii, intr_val);
944 origidx = si_coreidx(sih);
945
946 sb = REGS2SB(sb_setcoreidx(sih, idx));
947
948 tmp = R_SBREG(sii, &sb->sbimconfiglow);
949 ret = tmp & TO_MASK;
950 W_SBREG(sii, &sb->sbimconfiglow, (tmp & ~TO_MASK) | to);
951
952 sb_commit(sih);
953 sb_setcoreidx(sih, origidx);
954 INTR_RESTORE(sii, intr_val);
955 return ret;
956}
957
958uint32
959sb_base(uint32 admatch)
960{
961 uint32 base;
962 uint type;
963
964 type = admatch & SBAM_TYPE_MASK;
965 ASSERT(type < 3);
966
967 base = 0;
968
969 if (type == 0) {
970 base = admatch & SBAM_BASE0_MASK;
971 } else if (type == 1) {
972 ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
973 base = admatch & SBAM_BASE1_MASK;
974 } else if (type == 2) {
975 ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
976 base = admatch & SBAM_BASE2_MASK;
977 }
978
979 return (base);
980}
981
982uint32
983sb_size(uint32 admatch)
984{
985 uint32 size;
986 uint type;
987
988 type = admatch & SBAM_TYPE_MASK;
989 ASSERT(type < 3);
990
991 size = 0;
992
993 if (type == 0) {
994 size = 1 << (((admatch & SBAM_ADINT0_MASK) >> SBAM_ADINT0_SHIFT) + 1);
995 } else if (type == 1) {
996 ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
997 size = 1 << (((admatch & SBAM_ADINT1_MASK) >> SBAM_ADINT1_SHIFT) + 1);
998 } else if (type == 2) {
999 ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
1000 size = 1 << (((admatch & SBAM_ADINT2_MASK) >> SBAM_ADINT2_SHIFT) + 1);
1001 }
1002
1003 return (size);
1004}
diff --git a/drivers/net/wireless/bcm4329/siutils.c b/drivers/net/wireless/bcm4329/siutils.c
new file mode 100644
index 00000000000..1814db0f9dd
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/siutils.c
@@ -0,0 +1,1527 @@
1/*
2 * Misc utility routines for accessing chip-specific features
3 * of the SiliconBackplane-based Broadcom chips.
4 *
5 * Copyright (C) 1999-2010, 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.662.4.4.4.16.4.28 2010/06/23 21:37:54 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;
59static void *common_info_alloced = NULL;
60
61/* global flag to prevent shared resources from being initialized multiple times in si_attach() */
62
63/*
64 * Allocate a si handle.
65 * devid - pci device id (used to determine chip#)
66 * osh - opaque OS handle
67 * regs - virtual address of initial core registers
68 * bustype - pci/pcmcia/sb/sdio/etc
69 * vars - pointer to a pointer area for "environment" variables
70 * varsz - pointer to int to return the size of the vars
71 */
72si_t *
73si_attach(uint devid, osl_t *osh, void *regs,
74 uint bustype, void *sdh, char **vars, uint *varsz)
75{
76 si_info_t *sii;
77
78 /* alloc si_info_t */
79 if ((sii = MALLOC(osh, sizeof (si_info_t))) == NULL) {
80 SI_ERROR(("si_attach: malloc failed! malloced %d bytes\n", MALLOCED(osh)));
81 return (NULL);
82 }
83
84 if (si_doattach(sii, devid, osh, regs, bustype, sdh, vars, varsz) == NULL) {
85 if (NULL != sii->common_info)
86 MFREE(osh, sii->common_info, sizeof(si_common_info_t));
87 MFREE(osh, sii, sizeof(si_info_t));
88 return (NULL);
89 }
90 sii->vars = vars ? *vars : NULL;
91 sii->varsz = varsz ? *varsz : 0;
92
93 return (si_t *)sii;
94}
95
96/* global kernel resource */
97static si_info_t ksii;
98
99static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */
100
101/* generic kernel variant of si_attach() */
102si_t *
103si_kattach(osl_t *osh)
104{
105 static bool ksii_attached = FALSE;
106
107 if (!ksii_attached) {
108 void *regs = REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE);
109
110 if (si_doattach(&ksii, BCM4710_DEVICE_ID, osh, regs,
111 SI_BUS, NULL,
112 osh != SI_OSH ? &ksii.vars : NULL,
113 osh != SI_OSH ? &ksii.varsz : NULL) == NULL) {
114 if (NULL != ksii.common_info)
115 MFREE(osh, ksii.common_info, sizeof(si_common_info_t));
116 SI_ERROR(("si_kattach: si_doattach failed\n"));
117 REG_UNMAP(regs);
118 return NULL;
119 }
120 REG_UNMAP(regs);
121
122 /* save ticks normalized to ms for si_watchdog_ms() */
123 if (PMUCTL_ENAB(&ksii.pub)) {
124 /* based on 32KHz ILP clock */
125 wd_msticks = 32;
126 } else {
127 wd_msticks = ALP_CLOCK / 1000;
128 }
129
130 ksii_attached = TRUE;
131 SI_MSG(("si_kattach done. ccrev = %d, wd_msticks = %d\n",
132 ksii.pub.ccrev, wd_msticks));
133 }
134
135 return &ksii.pub;
136}
137
138
139static bool
140si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh)
141{
142 /* need to set memseg flag for CF card first before any sb registers access */
143 if (BUSTYPE(bustype) == PCMCIA_BUS)
144 sii->memseg = TRUE;
145
146
147 if (BUSTYPE(bustype) == SDIO_BUS) {
148 int err;
149 uint8 clkset;
150
151 /* Try forcing SDIO core to do ALPAvail request only */
152 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
153 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
154 if (!err) {
155 uint8 clkval;
156
157 /* If register supported, wait for ALPAvail and then force ALP */
158 clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, NULL);
159 if ((clkval & ~SBSDIO_AVBITS) == clkset) {
160 SPINWAIT(((clkval = bcmsdh_cfg_read(sdh, SDIO_FUNC_1,
161 SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)),
162 PMU_MAX_TRANSITION_DLY);
163 if (!SBSDIO_ALPAV(clkval)) {
164 SI_ERROR(("timeout on ALPAV wait, clkval 0x%02x\n",
165 clkval));
166 return FALSE;
167 }
168 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
169 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
170 clkset, &err);
171 OSL_DELAY(65);
172 }
173 }
174
175 /* Also, disable the extra SDIO pull-ups */
176 bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
177 }
178
179
180 return TRUE;
181}
182
183static bool
184si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin,
185 uint *origidx, void *regs)
186{
187 bool pci, pcie;
188 uint i;
189 uint pciidx, pcieidx, pcirev, pcierev;
190
191 cc = si_setcoreidx(&sii->pub, SI_CC_IDX);
192 ASSERT((uintptr)cc);
193
194 /* get chipcommon rev */
195 sii->pub.ccrev = (int)si_corerev(&sii->pub);
196
197 /* get chipcommon chipstatus */
198 if (sii->pub.ccrev >= 11)
199 sii->pub.chipst = R_REG(sii->osh, &cc->chipstatus);
200
201 /* get chipcommon capabilites */
202 sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities);
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_MSG(("CORE[%d]: id 0x%x rev %d base 0x%x regs 0x%p\n",
232 i, cid, crev, sii->common_info->coresba[i], sii->common_info->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->common_info->coresba[i])) ||
261 (regs == sii->common_info->regs[i]))
262 *origidx = i;
263 }
264
265
266 SI_MSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx, sii->pub.buscoretype,
267 sii->pub.buscorerev));
268
269 if (BUSTYPE(sii->pub.bustype) == SI_BUS && (CHIPID(sii->pub.chip) == BCM4712_CHIP_ID) &&
270 (sii->pub.chippkg != BCM4712LARGE_PKG_ID) && (sii->pub.chiprev <= 3))
271 OR_REG(sii->osh, &cc->slow_clk_ctl, SCC_SS_XTAL);
272
273
274 /* Make sure any on-chip ARM is off (in case strapping is wrong), or downloaded code was
275 * already running.
276 */
277 if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) {
278 if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) ||
279 si_setcore(&sii->pub, ARMCM3_CORE_ID, 0))
280 si_core_disable(&sii->pub, 0);
281 }
282
283 /* return to the original core */
284 si_setcoreidx(&sii->pub, *origidx);
285
286 return TRUE;
287}
288
289
290
291static si_info_t *
292si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs,
293 uint bustype, void *sdh, char **vars, uint *varsz)
294{
295 struct si_pub *sih = &sii->pub;
296 uint32 w, savewin;
297 chipcregs_t *cc;
298 char *pvars = NULL;
299 uint origidx;
300
301 ASSERT(GOODREGS(regs));
302
303 bzero((uchar*)sii, sizeof(si_info_t));
304
305
306 {
307 if (NULL == (common_info_alloced = (void *)MALLOC(osh, sizeof(si_common_info_t)))) {
308 SI_ERROR(("si_doattach: malloc failed! malloced %dbytes\n", MALLOCED(osh)));
309 return (NULL);
310 }
311 bzero((uchar*)(common_info_alloced), sizeof(si_common_info_t));
312 }
313 sii->common_info = (si_common_info_t *)common_info_alloced;
314 sii->common_info->attach_count++;
315
316 savewin = 0;
317
318 sih->buscoreidx = BADIDX;
319
320 sii->curmap = regs;
321 sii->sdh = sdh;
322 sii->osh = osh;
323
324
325 /* find Chipcommon address */
326 if (bustype == PCI_BUS) {
327 savewin = OSL_PCI_READ_CONFIG(sii->osh, PCI_BAR0_WIN, sizeof(uint32));
328 if (!GOODCOREADDR(savewin, SI_ENUM_BASE))
329 savewin = SI_ENUM_BASE;
330 OSL_PCI_WRITE_CONFIG(sii->osh, PCI_BAR0_WIN, 4, SI_ENUM_BASE);
331 cc = (chipcregs_t *)regs;
332 } else
333 if ((bustype == SDIO_BUS) || (bustype == SPI_BUS)) {
334 cc = (chipcregs_t *)sii->curmap;
335 } else {
336 cc = (chipcregs_t *)REG_MAP(SI_ENUM_BASE, SI_CORE_SIZE);
337 }
338
339 sih->bustype = bustype;
340 if (bustype != BUSTYPE(bustype)) {
341 SI_ERROR(("si_doattach: bus type %d does not match configured bus type %d\n",
342 bustype, BUSTYPE(bustype)));
343 return NULL;
344 }
345
346 /* bus/core/clk setup for register access */
347 if (!si_buscore_prep(sii, bustype, devid, sdh)) {
348 SI_ERROR(("si_doattach: si_core_clk_prep failed %d\n", bustype));
349 return NULL;
350 }
351
352 /* ChipID recognition.
353 * We assume we can read chipid at offset 0 from the regs arg.
354 * If we add other chiptypes (or if we need to support old sdio hosts w/o chipcommon),
355 * some way of recognizing them needs to be added here.
356 */
357 w = R_REG(osh, &cc->chipid);
358 sih->socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
359 /* Might as wll fill in chip id rev & pkg */
360 sih->chip = w & CID_ID_MASK;
361 sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
362 sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
363 if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chippkg != BCM4329_289PIN_PKG_ID))
364 sih->chippkg = BCM4329_182PIN_PKG_ID;
365 sih->issim = IS_SIM(sih->chippkg);
366
367 /* scan for cores */
368 if (CHIPTYPE(sii->pub.socitype) == SOCI_SB) {
369 SI_MSG(("Found chip type SB (0x%08x)\n", w));
370 sb_scan(&sii->pub, regs, devid);
371 } else if (CHIPTYPE(sii->pub.socitype) == SOCI_AI) {
372 SI_MSG(("Found chip type AI (0x%08x)\n", w));
373 /* pass chipc address instead of original core base */
374 ai_scan(&sii->pub, (void *)cc, devid);
375 } else {
376 SI_ERROR(("Found chip of unkown type (0x%08x)\n", w));
377 return NULL;
378 }
379 /* no cores found, bail out */
380 if (sii->numcores == 0) {
381 SI_ERROR(("si_doattach: could not find any cores\n"));
382 return NULL;
383 }
384 /* bus/core/clk setup */
385 origidx = SI_CC_IDX;
386 if (!si_buscore_setup(sii, cc, bustype, savewin, &origidx, regs)) {
387 SI_ERROR(("si_doattach: si_buscore_setup failed\n"));
388 return NULL;
389 }
390
391 pvars = NULL;
392
393
394
395 if (sii->pub.ccrev >= 20) {
396 cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
397 W_REG(osh, &cc->gpiopullup, 0);
398 W_REG(osh, &cc->gpiopulldown, 0);
399 si_setcoreidx(sih, origidx);
400 }
401
402 /* Skip PMU initialization from the Dongle Host.
403 * Firmware will take care of it when it comes up.
404 */
405
406
407
408 return (sii);
409}
410
411/* may be called with core in reset */
412void
413si_detach(si_t *sih)
414{
415 si_info_t *sii;
416 uint idx;
417
418 sii = SI_INFO(sih);
419
420 if (sii == NULL)
421 return;
422
423 if (BUSTYPE(sih->bustype) == SI_BUS)
424 for (idx = 0; idx < SI_MAXCORES; idx++)
425 if (sii->common_info->regs[idx]) {
426 REG_UNMAP(sii->common_info->regs[idx]);
427 sii->common_info->regs[idx] = NULL;
428 }
429
430
431 if (1 == sii->common_info->attach_count--) {
432 MFREE(sii->osh, sii->common_info, sizeof(si_common_info_t));
433 common_info_alloced = NULL;
434 }
435
436#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS)
437 if (sii != &ksii)
438#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */
439 MFREE(sii->osh, sii, sizeof(si_info_t));
440}
441
442void *
443si_osh(si_t *sih)
444{
445 si_info_t *sii;
446
447 sii = SI_INFO(sih);
448 return sii->osh;
449}
450
451void
452si_setosh(si_t *sih, osl_t *osh)
453{
454 si_info_t *sii;
455
456 sii = SI_INFO(sih);
457 if (sii->osh != NULL) {
458 SI_ERROR(("osh is already set....\n"));
459 ASSERT(!sii->osh);
460 }
461 sii->osh = osh;
462}
463
464/* register driver interrupt disabling and restoring callback functions */
465void
466si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn,
467 void *intrsenabled_fn, void *intr_arg)
468{
469 si_info_t *sii;
470
471 sii = SI_INFO(sih);
472 sii->intr_arg = intr_arg;
473 sii->intrsoff_fn = (si_intrsoff_t)intrsoff_fn;
474 sii->intrsrestore_fn = (si_intrsrestore_t)intrsrestore_fn;
475 sii->intrsenabled_fn = (si_intrsenabled_t)intrsenabled_fn;
476 /* save current core id. when this function called, the current core
477 * must be the core which provides driver functions(il, et, wl, etc.)
478 */
479 sii->dev_coreid = sii->common_info->coreid[sii->curidx];
480}
481
482void
483si_deregister_intr_callback(si_t *sih)
484{
485 si_info_t *sii;
486
487 sii = SI_INFO(sih);
488 sii->intrsoff_fn = NULL;
489}
490
491uint
492si_intflag(si_t *sih)
493{
494 si_info_t *sii = SI_INFO(sih);
495 if (CHIPTYPE(sih->socitype) == SOCI_SB) {
496 sbconfig_t *ccsbr = (sbconfig_t *)((uintptr)((ulong)
497 (sii->common_info->coresba[SI_CC_IDX]) + SBCONFIGOFF));
498 return R_REG(sii->osh, &ccsbr->sbflagst);
499 } else if (CHIPTYPE(sih->socitype) == SOCI_AI)
500 return R_REG(sii->osh, ((uint32 *)(uintptr)
501 (sii->common_info->oob_router + OOB_STATUSA)));
502 else {
503 ASSERT(0);
504 return 0;
505 }
506}
507
508uint
509si_flag(si_t *sih)
510{
511 if (CHIPTYPE(sih->socitype) == SOCI_SB)
512 return sb_flag(sih);
513 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
514 return ai_flag(sih);
515 else {
516 ASSERT(0);
517 return 0;
518 }
519}
520
521void
522si_setint(si_t *sih, int siflag)
523{
524 if (CHIPTYPE(sih->socitype) == SOCI_SB)
525 sb_setint(sih, siflag);
526 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
527 ai_setint(sih, siflag);
528 else
529 ASSERT(0);
530}
531
532uint
533si_coreid(si_t *sih)
534{
535 si_info_t *sii;
536
537 sii = SI_INFO(sih);
538 return sii->common_info->coreid[sii->curidx];
539}
540
541uint
542si_coreidx(si_t *sih)
543{
544 si_info_t *sii;
545
546 sii = SI_INFO(sih);
547 return sii->curidx;
548}
549
550/* return the core-type instantiation # of the current core */
551uint
552si_coreunit(si_t *sih)
553{
554 si_info_t *sii;
555 uint idx;
556 uint coreid;
557 uint coreunit;
558 uint i;
559
560 sii = SI_INFO(sih);
561 coreunit = 0;
562
563 idx = sii->curidx;
564
565 ASSERT(GOODREGS(sii->curmap));
566 coreid = si_coreid(sih);
567
568 /* count the cores of our type */
569 for (i = 0; i < idx; i++)
570 if (sii->common_info->coreid[i] == coreid)
571 coreunit++;
572
573 return (coreunit);
574}
575
576uint
577si_corevendor(si_t *sih)
578{
579 if (CHIPTYPE(sih->socitype) == SOCI_SB)
580 return sb_corevendor(sih);
581 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
582 return ai_corevendor(sih);
583 else {
584 ASSERT(0);
585 return 0;
586 }
587}
588
589bool
590si_backplane64(si_t *sih)
591{
592 return ((sih->cccaps & CC_CAP_BKPLN64) != 0);
593}
594
595uint
596si_corerev(si_t *sih)
597{
598 if (CHIPTYPE(sih->socitype) == SOCI_SB)
599 return sb_corerev(sih);
600 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
601 return ai_corerev(sih);
602 else {
603 ASSERT(0);
604 return 0;
605 }
606}
607
608/* return index of coreid or BADIDX if not found */
609uint
610si_findcoreidx(si_t *sih, uint coreid, uint coreunit)
611{
612 si_info_t *sii;
613 uint found;
614 uint i;
615
616 sii = SI_INFO(sih);
617
618 found = 0;
619
620 for (i = 0; i < sii->numcores; i++)
621 if (sii->common_info->coreid[i] == coreid) {
622 if (found == coreunit)
623 return (i);
624 found++;
625 }
626
627 return (BADIDX);
628}
629
630/* return list of found cores */
631uint
632si_corelist(si_t *sih, uint coreid[])
633{
634 si_info_t *sii;
635
636 sii = SI_INFO(sih);
637
638 bcopy((uchar*)sii->common_info->coreid, (uchar*)coreid, (sii->numcores * sizeof(uint)));
639 return (sii->numcores);
640}
641
642/* return current register mapping */
643void *
644si_coreregs(si_t *sih)
645{
646 si_info_t *sii;
647
648 sii = SI_INFO(sih);
649 ASSERT(GOODREGS(sii->curmap));
650
651 return (sii->curmap);
652}
653
654/*
655 * This function changes logical "focus" to the indicated core;
656 * must be called with interrupts off.
657 * Moreover, callers should keep interrupts off during switching out of and back to d11 core
658 */
659void *
660si_setcore(si_t *sih, uint coreid, uint coreunit)
661{
662 uint idx;
663
664 idx = si_findcoreidx(sih, coreid, coreunit);
665 if (!GOODIDX(idx))
666 return (NULL);
667
668 if (CHIPTYPE(sih->socitype) == SOCI_SB)
669 return sb_setcoreidx(sih, idx);
670 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
671 return ai_setcoreidx(sih, idx);
672 else {
673 ASSERT(0);
674 return NULL;
675 }
676}
677
678void *
679si_setcoreidx(si_t *sih, uint coreidx)
680{
681 if (CHIPTYPE(sih->socitype) == SOCI_SB)
682 return sb_setcoreidx(sih, coreidx);
683 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
684 return ai_setcoreidx(sih, coreidx);
685 else {
686 ASSERT(0);
687 return NULL;
688 }
689}
690
691/* Turn off interrupt as required by sb_setcore, before switch core */
692void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val)
693{
694 void *cc;
695 si_info_t *sii;
696
697 sii = SI_INFO(sih);
698
699 INTR_OFF(sii, *intr_val);
700 *origidx = sii->curidx;
701 cc = si_setcore(sih, coreid, 0);
702 ASSERT(cc != NULL);
703
704 return cc;
705}
706
707/* restore coreidx and restore interrupt */
708void si_restore_core(si_t *sih, uint coreid, uint intr_val)
709{
710 si_info_t *sii;
711
712 sii = SI_INFO(sih);
713
714 si_setcoreidx(sih, coreid);
715 INTR_RESTORE(sii, intr_val);
716}
717
718int
719si_numaddrspaces(si_t *sih)
720{
721 if (CHIPTYPE(sih->socitype) == SOCI_SB)
722 return sb_numaddrspaces(sih);
723 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
724 return ai_numaddrspaces(sih);
725 else {
726 ASSERT(0);
727 return 0;
728 }
729}
730
731uint32
732si_addrspace(si_t *sih, uint asidx)
733{
734 if (CHIPTYPE(sih->socitype) == SOCI_SB)
735 return sb_addrspace(sih, asidx);
736 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
737 return ai_addrspace(sih, asidx);
738 else {
739 ASSERT(0);
740 return 0;
741 }
742}
743
744uint32
745si_addrspacesize(si_t *sih, uint asidx)
746{
747 if (CHIPTYPE(sih->socitype) == SOCI_SB)
748 return sb_addrspacesize(sih, asidx);
749 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
750 return ai_addrspacesize(sih, asidx);
751 else {
752 ASSERT(0);
753 return 0;
754 }
755}
756
757uint32
758si_core_cflags(si_t *sih, uint32 mask, uint32 val)
759{
760 if (CHIPTYPE(sih->socitype) == SOCI_SB)
761 return sb_core_cflags(sih, mask, val);
762 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
763 return ai_core_cflags(sih, mask, val);
764 else {
765 ASSERT(0);
766 return 0;
767 }
768}
769
770void
771si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val)
772{
773 if (CHIPTYPE(sih->socitype) == SOCI_SB)
774 sb_core_cflags_wo(sih, mask, val);
775 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
776 ai_core_cflags_wo(sih, mask, val);
777 else
778 ASSERT(0);
779}
780
781uint32
782si_core_sflags(si_t *sih, uint32 mask, uint32 val)
783{
784 if (CHIPTYPE(sih->socitype) == SOCI_SB)
785 return sb_core_sflags(sih, mask, val);
786 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
787 return ai_core_sflags(sih, mask, val);
788 else {
789 ASSERT(0);
790 return 0;
791 }
792}
793
794bool
795si_iscoreup(si_t *sih)
796{
797 if (CHIPTYPE(sih->socitype) == SOCI_SB)
798 return sb_iscoreup(sih);
799 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
800 return ai_iscoreup(sih);
801 else {
802 ASSERT(0);
803 return FALSE;
804 }
805}
806
807void
808si_write_wrapperreg(si_t *sih, uint32 offset, uint32 val)
809{
810 /* only for 4319, no requirement for SOCI_SB */
811 if (CHIPTYPE(sih->socitype) == SOCI_AI) {
812 ai_write_wrap_reg(sih, offset, val);
813 }
814 else
815 return;
816
817 return;
818}
819
820uint
821si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
822{
823 if (CHIPTYPE(sih->socitype) == SOCI_SB)
824 return sb_corereg(sih, coreidx, regoff, mask, val);
825 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
826 return ai_corereg(sih, coreidx, regoff, mask, val);
827 else {
828 ASSERT(0);
829 return 0;
830 }
831}
832
833void
834si_core_disable(si_t *sih, uint32 bits)
835{
836 if (CHIPTYPE(sih->socitype) == SOCI_SB)
837 sb_core_disable(sih, bits);
838 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
839 ai_core_disable(sih, bits);
840}
841
842void
843si_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
844{
845 if (CHIPTYPE(sih->socitype) == SOCI_SB)
846 sb_core_reset(sih, bits, resetbits);
847 else if (CHIPTYPE(sih->socitype) == SOCI_AI)
848 ai_core_reset(sih, bits, resetbits);
849}
850
851void
852si_core_tofixup(si_t *sih)
853{
854 if (CHIPTYPE(sih->socitype) == SOCI_SB)
855 sb_core_tofixup(sih);
856}
857
858/* Run bist on current core. Caller needs to take care of core-specific bist hazards */
859int
860si_corebist(si_t *sih)
861{
862 uint32 cflags;
863 int result = 0;
864
865 /* Read core control flags */
866 cflags = si_core_cflags(sih, 0, 0);
867
868 /* Set bist & fgc */
869 si_core_cflags(sih, 0, (SICF_BIST_EN | SICF_FGC));
870
871 /* Wait for bist done */
872 SPINWAIT(((si_core_sflags(sih, 0, 0) & SISF_BIST_DONE) == 0), 100000);
873
874 if (si_core_sflags(sih, 0, 0) & SISF_BIST_ERROR)
875 result = BCME_ERROR;
876
877 /* Reset core control flags */
878 si_core_cflags(sih, 0xffff, cflags);
879
880 return result;
881}
882
883static uint32
884factor6(uint32 x)
885{
886 switch (x) {
887 case CC_F6_2: return 2;
888 case CC_F6_3: return 3;
889 case CC_F6_4: return 4;
890 case CC_F6_5: return 5;
891 case CC_F6_6: return 6;
892 case CC_F6_7: return 7;
893 default: return 0;
894 }
895}
896
897/* calculate the speed the SI would run at given a set of clockcontrol values */
898uint32
899si_clock_rate(uint32 pll_type, uint32 n, uint32 m)
900{
901 uint32 n1, n2, clock, m1, m2, m3, mc;
902
903 n1 = n & CN_N1_MASK;
904 n2 = (n & CN_N2_MASK) >> CN_N2_SHIFT;
905
906 if (pll_type == PLL_TYPE6) {
907 if (m & CC_T6_MMASK)
908 return CC_T6_M1;
909 else
910 return CC_T6_M0;
911 } else if ((pll_type == PLL_TYPE1) ||
912 (pll_type == PLL_TYPE3) ||
913 (pll_type == PLL_TYPE4) ||
914 (pll_type == PLL_TYPE7)) {
915 n1 = factor6(n1);
916 n2 += CC_F5_BIAS;
917 } else if (pll_type == PLL_TYPE2) {
918 n1 += CC_T2_BIAS;
919 n2 += CC_T2_BIAS;
920 ASSERT((n1 >= 2) && (n1 <= 7));
921 ASSERT((n2 >= 5) && (n2 <= 23));
922 } else if (pll_type == PLL_TYPE5) {
923 return (100000000);
924 } else
925 ASSERT(0);
926 /* PLL types 3 and 7 use BASE2 (25Mhz) */
927 if ((pll_type == PLL_TYPE3) ||
928 (pll_type == PLL_TYPE7)) {
929 clock = CC_CLOCK_BASE2 * n1 * n2;
930 } else
931 clock = CC_CLOCK_BASE1 * n1 * n2;
932
933 if (clock == 0)
934 return 0;
935
936 m1 = m & CC_M1_MASK;
937 m2 = (m & CC_M2_MASK) >> CC_M2_SHIFT;
938 m3 = (m & CC_M3_MASK) >> CC_M3_SHIFT;
939 mc = (m & CC_MC_MASK) >> CC_MC_SHIFT;
940
941 if ((pll_type == PLL_TYPE1) ||
942 (pll_type == PLL_TYPE3) ||
943 (pll_type == PLL_TYPE4) ||
944 (pll_type == PLL_TYPE7)) {
945 m1 = factor6(m1);
946 if ((pll_type == PLL_TYPE1) || (pll_type == PLL_TYPE3))
947 m2 += CC_F5_BIAS;
948 else
949 m2 = factor6(m2);
950 m3 = factor6(m3);
951
952 switch (mc) {
953 case CC_MC_BYPASS: return (clock);
954 case CC_MC_M1: return (clock / m1);
955 case CC_MC_M1M2: return (clock / (m1 * m2));
956 case CC_MC_M1M2M3: return (clock / (m1 * m2 * m3));
957 case CC_MC_M1M3: return (clock / (m1 * m3));
958 default: return (0);
959 }
960 } else {
961 ASSERT(pll_type == PLL_TYPE2);
962
963 m1 += CC_T2_BIAS;
964 m2 += CC_T2M2_BIAS;
965 m3 += CC_T2_BIAS;
966 ASSERT((m1 >= 2) && (m1 <= 7));
967 ASSERT((m2 >= 3) && (m2 <= 10));
968 ASSERT((m3 >= 2) && (m3 <= 7));
969
970 if ((mc & CC_T2MC_M1BYP) == 0)
971 clock /= m1;
972 if ((mc & CC_T2MC_M2BYP) == 0)
973 clock /= m2;
974 if ((mc & CC_T2MC_M3BYP) == 0)
975 clock /= m3;
976
977 return (clock);
978 }
979}
980
981
982/* set chip watchdog reset timer to fire in 'ticks' */
983void
984si_watchdog(si_t *sih, uint ticks)
985{
986 if (PMUCTL_ENAB(sih)) {
987
988 if ((sih->chip == BCM4319_CHIP_ID) && (sih->chiprev == 0) && (ticks != 0)) {
989 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, clk_ctl_st), ~0, 0x2);
990 si_setcore(sih, USB20D_CORE_ID, 0);
991 si_core_disable(sih, 1);
992 si_setcore(sih, CC_CORE_ID, 0);
993 }
994
995 if (ticks == 1)
996 ticks = 2;
997 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog), ~0, ticks);
998 } else {
999 /* instant NMI */
1000 si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog), ~0, ticks);
1001 }
1002}
1003
1004#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS)
1005/* trigger watchdog reset after ms milliseconds */
1006void
1007si_watchdog_ms(si_t *sih, uint32 ms)
1008{
1009 si_info_t *sii;
1010
1011 sii = SI_INFO(sih);
1012
1013 si_watchdog(sih, wd_msticks * ms);
1014}
1015#endif
1016
1017
1018
1019/* initialize the sdio core */
1020void
1021si_sdio_init(si_t *sih)
1022{
1023 si_info_t *sii = SI_INFO(sih);
1024
1025 if (((sih->buscoretype == PCMCIA_CORE_ID) && (sih->buscorerev >= 8)) ||
1026 (sih->buscoretype == SDIOD_CORE_ID)) {
1027 uint idx;
1028 sdpcmd_regs_t *sdpregs;
1029
1030 /* get the current core index */
1031 idx = sii->curidx;
1032 ASSERT(idx == si_findcoreidx(sih, D11_CORE_ID, 0));
1033
1034 /* switch to sdio core */
1035 if (!(sdpregs = (sdpcmd_regs_t *)si_setcore(sih, PCMCIA_CORE_ID, 0)))
1036 sdpregs = (sdpcmd_regs_t *)si_setcore(sih, SDIOD_CORE_ID, 0);
1037 ASSERT(sdpregs);
1038
1039 SI_MSG(("si_sdio_init: For PCMCIA/SDIO Corerev %d, enable ints from core %d "
1040 "through SD core %d (%p)\n",
1041 sih->buscorerev, idx, sii->curidx, sdpregs));
1042
1043 /* enable backplane error and core interrupts */
1044 W_REG(sii->osh, &sdpregs->hostintmask, I_SBINT);
1045 W_REG(sii->osh, &sdpregs->sbintmask, (I_SB_SERR | I_SB_RESPERR | (1 << idx)));
1046
1047 /* switch back to previous core */
1048 si_setcoreidx(sih, idx);
1049 }
1050
1051 /* enable interrupts */
1052 bcmsdh_intr_enable(sii->sdh);
1053
1054}
1055
1056
1057/* change logical "focus" to the gpio core for optimized access */
1058void *
1059si_gpiosetcore(si_t *sih)
1060{
1061 return (si_setcoreidx(sih, SI_CC_IDX));
1062}
1063
1064/* mask&set gpiocontrol bits */
1065uint32
1066si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1067{
1068 uint regoff;
1069
1070 regoff = 0;
1071
1072 /* gpios could be shared on router platforms
1073 * ignore reservation if it's high priority (e.g., test apps)
1074 */
1075 if ((priority != GPIO_HI_PRIORITY) &&
1076 (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1077 mask = priority ? (si_gpioreservation & mask) :
1078 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1079 val &= mask;
1080 }
1081
1082 regoff = OFFSETOF(chipcregs_t, gpiocontrol);
1083 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1084}
1085
1086/* mask&set gpio output enable bits */
1087uint32
1088si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1089{
1090 uint regoff;
1091
1092 regoff = 0;
1093
1094 /* gpios could be shared on router platforms
1095 * ignore reservation if it's high priority (e.g., test apps)
1096 */
1097 if ((priority != GPIO_HI_PRIORITY) &&
1098 (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1099 mask = priority ? (si_gpioreservation & mask) :
1100 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1101 val &= mask;
1102 }
1103
1104 regoff = OFFSETOF(chipcregs_t, gpioouten);
1105 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1106}
1107
1108/* mask&set gpio output bits */
1109uint32
1110si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1111{
1112 uint regoff;
1113
1114 regoff = 0;
1115
1116 /* gpios could be shared on router platforms
1117 * ignore reservation if it's high priority (e.g., test apps)
1118 */
1119 if ((priority != GPIO_HI_PRIORITY) &&
1120 (BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1121 mask = priority ? (si_gpioreservation & mask) :
1122 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1123 val &= mask;
1124 }
1125
1126 regoff = OFFSETOF(chipcregs_t, gpioout);
1127 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1128}
1129
1130/* reserve one gpio */
1131uint32
1132si_gpioreserve(si_t *sih, uint32 gpio_bitmask, uint8 priority)
1133{
1134 si_info_t *sii;
1135
1136 sii = SI_INFO(sih);
1137
1138 /* only cores on SI_BUS share GPIO's and only applcation users need to
1139 * reserve/release GPIO
1140 */
1141 if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) {
1142 ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority));
1143 return -1;
1144 }
1145 /* make sure only one bit is set */
1146 if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
1147 ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
1148 return -1;
1149 }
1150
1151 /* already reserved */
1152 if (si_gpioreservation & gpio_bitmask)
1153 return -1;
1154 /* set reservation */
1155 si_gpioreservation |= gpio_bitmask;
1156
1157 return si_gpioreservation;
1158}
1159
1160/* release one gpio */
1161/*
1162 * releasing the gpio doesn't change the current value on the GPIO last write value
1163 * persists till some one overwrites it
1164 */
1165
1166uint32
1167si_gpiorelease(si_t *sih, uint32 gpio_bitmask, uint8 priority)
1168{
1169 si_info_t *sii;
1170
1171 sii = SI_INFO(sih);
1172
1173 /* only cores on SI_BUS share GPIO's and only applcation users need to
1174 * reserve/release GPIO
1175 */
1176 if ((BUSTYPE(sih->bustype) != SI_BUS) || (!priority)) {
1177 ASSERT((BUSTYPE(sih->bustype) == SI_BUS) && (priority));
1178 return -1;
1179 }
1180 /* make sure only one bit is set */
1181 if ((!gpio_bitmask) || ((gpio_bitmask) & (gpio_bitmask - 1))) {
1182 ASSERT((gpio_bitmask) && !((gpio_bitmask) & (gpio_bitmask - 1)));
1183 return -1;
1184 }
1185
1186 /* already released */
1187 if (!(si_gpioreservation & gpio_bitmask))
1188 return -1;
1189
1190 /* clear reservation */
1191 si_gpioreservation &= ~gpio_bitmask;
1192
1193 return si_gpioreservation;
1194}
1195
1196/* return the current gpioin register value */
1197uint32
1198si_gpioin(si_t *sih)
1199{
1200 si_info_t *sii;
1201 uint regoff;
1202
1203 sii = SI_INFO(sih);
1204 regoff = 0;
1205
1206 regoff = OFFSETOF(chipcregs_t, gpioin);
1207 return (si_corereg(sih, SI_CC_IDX, regoff, 0, 0));
1208}
1209
1210/* mask&set gpio interrupt polarity bits */
1211uint32
1212si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1213{
1214 si_info_t *sii;
1215 uint regoff;
1216
1217 sii = SI_INFO(sih);
1218 regoff = 0;
1219
1220 /* gpios could be shared on router platforms */
1221 if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1222 mask = priority ? (si_gpioreservation & mask) :
1223 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1224 val &= mask;
1225 }
1226
1227 regoff = OFFSETOF(chipcregs_t, gpiointpolarity);
1228 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1229}
1230
1231/* mask&set gpio interrupt mask bits */
1232uint32
1233si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority)
1234{
1235 si_info_t *sii;
1236 uint regoff;
1237
1238 sii = SI_INFO(sih);
1239 regoff = 0;
1240
1241 /* gpios could be shared on router platforms */
1242 if ((BUSTYPE(sih->bustype) == SI_BUS) && (val || mask)) {
1243 mask = priority ? (si_gpioreservation & mask) :
1244 ((si_gpioreservation | mask) & ~(si_gpioreservation));
1245 val &= mask;
1246 }
1247
1248 regoff = OFFSETOF(chipcregs_t, gpiointmask);
1249 return (si_corereg(sih, SI_CC_IDX, regoff, mask, val));
1250}
1251
1252/* assign the gpio to an led */
1253uint32
1254si_gpioled(si_t *sih, uint32 mask, uint32 val)
1255{
1256 si_info_t *sii;
1257
1258 sii = SI_INFO(sih);
1259 if (sih->ccrev < 16)
1260 return -1;
1261
1262 /* gpio led powersave reg */
1263 return (si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, gpiotimeroutmask), mask, val));
1264}
1265
1266/* mask&set gpio timer val */
1267uint32
1268si_gpiotimerval(si_t *sih, uint32 mask, uint32 gpiotimerval)
1269{
1270 si_info_t *sii;
1271
1272 sii = SI_INFO(sih);
1273
1274 if (sih->ccrev < 16)
1275 return -1;
1276
1277 return (si_corereg(sih, SI_CC_IDX,
1278 OFFSETOF(chipcregs_t, gpiotimerval), mask, gpiotimerval));
1279}
1280
1281uint32
1282si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val)
1283{
1284 si_info_t *sii;
1285 uint offs;
1286
1287 sii = SI_INFO(sih);
1288 if (sih->ccrev < 20)
1289 return -1;
1290
1291 offs = (updown ? OFFSETOF(chipcregs_t, gpiopulldown) : OFFSETOF(chipcregs_t, gpiopullup));
1292 return (si_corereg(sih, SI_CC_IDX, offs, mask, val));
1293}
1294
1295uint32
1296si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val)
1297{
1298 si_info_t *sii;
1299 uint offs;
1300
1301 sii = SI_INFO(sih);
1302 if (sih->ccrev < 11)
1303 return -1;
1304
1305 if (regtype == GPIO_REGEVT)
1306 offs = OFFSETOF(chipcregs_t, gpioevent);
1307 else if (regtype == GPIO_REGEVT_INTMSK)
1308 offs = OFFSETOF(chipcregs_t, gpioeventintmask);
1309 else if (regtype == GPIO_REGEVT_INTPOL)
1310 offs = OFFSETOF(chipcregs_t, gpioeventintpolarity);
1311 else
1312 return -1;
1313
1314 return (si_corereg(sih, SI_CC_IDX, offs, mask, val));
1315}
1316
1317void *
1318si_gpio_handler_register(si_t *sih, uint32 event,
1319 bool level, gpio_handler_t cb, void *arg)
1320{
1321 si_info_t *sii;
1322 gpioh_item_t *gi;
1323
1324 ASSERT(event);
1325 ASSERT(cb != NULL);
1326
1327 sii = SI_INFO(sih);
1328 if (sih->ccrev < 11)
1329 return NULL;
1330
1331 if ((gi = MALLOC(sii->osh, sizeof(gpioh_item_t))) == NULL)
1332 return NULL;
1333
1334 bzero(gi, sizeof(gpioh_item_t));
1335 gi->event = event;
1336 gi->handler = cb;
1337 gi->arg = arg;
1338 gi->level = level;
1339
1340 gi->next = sii->gpioh_head;
1341 sii->gpioh_head = gi;
1342
1343 return (void *)(gi);
1344}
1345
1346void
1347si_gpio_handler_unregister(si_t *sih, void *gpioh)
1348{
1349 si_info_t *sii;
1350 gpioh_item_t *p, *n;
1351
1352 sii = SI_INFO(sih);
1353 if (sih->ccrev < 11)
1354 return;
1355
1356 ASSERT(sii->gpioh_head != NULL);
1357 if ((void*)sii->gpioh_head == gpioh) {
1358 sii->gpioh_head = sii->gpioh_head->next;
1359 MFREE(sii->osh, gpioh, sizeof(gpioh_item_t));
1360 return;
1361 } else {
1362 p = sii->gpioh_head;
1363 n = p->next;
1364 while (n) {
1365 if ((void*)n == gpioh) {
1366 p->next = n->next;
1367 MFREE(sii->osh, gpioh, sizeof(gpioh_item_t));
1368 return;
1369 }
1370 p = n;
1371 n = n->next;
1372 }
1373 }
1374
1375 ASSERT(0); /* Not found in list */
1376}
1377
1378void
1379si_gpio_handler_process(si_t *sih)
1380{
1381 si_info_t *sii;
1382 gpioh_item_t *h;
1383 uint32 status;
1384 uint32 level = si_gpioin(sih);
1385 uint32 edge = si_gpioevent(sih, GPIO_REGEVT, 0, 0);
1386
1387 sii = SI_INFO(sih);
1388 for (h = sii->gpioh_head; h != NULL; h = h->next) {
1389 if (h->handler) {
1390 status = (h->level ? level : edge);
1391
1392 if (status & h->event)
1393 h->handler(status, h->arg);
1394 }
1395 }
1396
1397 si_gpioevent(sih, GPIO_REGEVT, edge, edge); /* clear edge-trigger status */
1398}
1399
1400uint32
1401si_gpio_int_enable(si_t *sih, bool enable)
1402{
1403 si_info_t *sii;
1404 uint offs;
1405
1406 sii = SI_INFO(sih);
1407 if (sih->ccrev < 11)
1408 return -1;
1409
1410 offs = OFFSETOF(chipcregs_t, intmask);
1411 return (si_corereg(sih, SI_CC_IDX, offs, CI_GPIO, (enable ? CI_GPIO : 0)));
1412}
1413
1414
1415/* Return the RAM size of the SOCRAM core */
1416uint32
1417si_socram_size(si_t *sih)
1418{
1419 si_info_t *sii;
1420 uint origidx;
1421 uint intr_val = 0;
1422
1423 sbsocramregs_t *regs;
1424 bool wasup;
1425 uint corerev;
1426 uint32 coreinfo;
1427 uint memsize = 0;
1428
1429 sii = SI_INFO(sih);
1430
1431 /* Block ints and save current core */
1432 INTR_OFF(sii, intr_val);
1433 origidx = si_coreidx(sih);
1434
1435 /* Switch to SOCRAM core */
1436 if (!(regs = si_setcore(sih, SOCRAM_CORE_ID, 0)))
1437 goto done;
1438
1439 /* Get info for determining size */
1440 if (!(wasup = si_iscoreup(sih)))
1441 si_core_reset(sih, 0, 0);
1442 corerev = si_corerev(sih);
1443 coreinfo = R_REG(sii->osh, &regs->coreinfo);
1444
1445 /* Calculate size from coreinfo based on rev */
1446 if (corerev == 0)
1447 memsize = 1 << (16 + (coreinfo & SRCI_MS0_MASK));
1448 else if (corerev < 3) {
1449 memsize = 1 << (SR_BSZ_BASE + (coreinfo & SRCI_SRBSZ_MASK));
1450 memsize *= (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
1451 } else {
1452 uint nb = (coreinfo & SRCI_SRNB_MASK) >> SRCI_SRNB_SHIFT;
1453 uint bsz = (coreinfo & SRCI_SRBSZ_MASK);
1454 uint lss = (coreinfo & SRCI_LSS_MASK) >> SRCI_LSS_SHIFT;
1455 if (lss != 0)
1456 nb --;
1457 memsize = nb * (1 << (bsz + SR_BSZ_BASE));
1458 if (lss != 0)
1459 memsize += (1 << ((lss - 1) + SR_BSZ_BASE));
1460 }
1461
1462 /* Return to previous state and core */
1463 if (!wasup)
1464 si_core_disable(sih, 0);
1465 si_setcoreidx(sih, origidx);
1466
1467done:
1468 INTR_RESTORE(sii, intr_val);
1469
1470 return memsize;
1471}
1472
1473
1474void
1475si_btcgpiowar(si_t *sih)
1476{
1477 si_info_t *sii;
1478 uint origidx;
1479 uint intr_val = 0;
1480 chipcregs_t *cc;
1481
1482 sii = SI_INFO(sih);
1483
1484 /* Make sure that there is ChipCommon core present &&
1485 * UART_TX is strapped to 1
1486 */
1487 if (!(sih->cccaps & CC_CAP_UARTGPIO))
1488 return;
1489
1490 /* si_corereg cannot be used as we have to guarantee 8-bit read/writes */
1491 INTR_OFF(sii, intr_val);
1492
1493 origidx = si_coreidx(sih);
1494
1495 cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0);
1496 ASSERT(cc != NULL);
1497
1498 W_REG(sii->osh, &cc->uart0mcr, R_REG(sii->osh, &cc->uart0mcr) | 0x04);
1499
1500 /* restore the original index */
1501 si_setcoreidx(sih, origidx);
1502
1503 INTR_RESTORE(sii, intr_val);
1504}
1505
1506/* check if the device is removed */
1507bool
1508si_deviceremoved(si_t *sih)
1509{
1510 uint32 w;
1511 si_info_t *sii;
1512
1513 sii = SI_INFO(sih);
1514
1515 switch (BUSTYPE(sih->bustype)) {
1516 case PCI_BUS:
1517 ASSERT(sii->osh != NULL);
1518 w = OSL_PCI_READ_CONFIG(sii->osh, PCI_CFG_VID, sizeof(uint32));
1519 if ((w & 0xFFFF) != VENDOR_BROADCOM)
1520 return TRUE;
1521 else
1522 return FALSE;
1523 default:
1524 return FALSE;
1525 }
1526 return FALSE;
1527}
diff --git a/drivers/net/wireless/bcm4329/siutils_priv.h b/drivers/net/wireless/bcm4329/siutils_priv.h
new file mode 100644
index 00000000000..e8ad7e50958
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/siutils_priv.h
@@ -0,0 +1,213 @@
1/*
2 * Include file private to the SOC Interconnect support files.
3 *
4 * Copyright (C) 1999-2010, 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.3.10.5.4.2 2009/09/22 13:28:16 Exp $
25 */
26
27#ifndef _siutils_priv_h_
28#define _siutils_priv_h_
29
30/* debug/trace */
31#define SI_ERROR(args)
32
33#define SI_MSG(args)
34
35#define IS_SIM(chippkg) ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID))
36
37typedef uint32 (*si_intrsoff_t)(void *intr_arg);
38typedef void (*si_intrsrestore_t)(void *intr_arg, uint32 arg);
39typedef bool (*si_intrsenabled_t)(void *intr_arg);
40
41typedef struct gpioh_item {
42 void *arg;
43 bool level;
44 gpio_handler_t handler;
45 uint32 event;
46 struct gpioh_item *next;
47} gpioh_item_t;
48
49/* misc si info needed by some of the routines */
50typedef struct si_common_info {
51 void *regs[SI_MAXCORES]; /* other regs va */
52 void *regs2[SI_MAXCORES]; /* va of each core second register set (usbh20) */
53 uint coreid[SI_MAXCORES]; /* id of each core */
54 uint32 cia[SI_MAXCORES]; /* erom cia entry for each core */
55 uint32 cib[SI_MAXCORES]; /* erom cia entry for each core */
56 uint32 coresba_size[SI_MAXCORES]; /* backplane address space size */
57 uint32 coresba2_size[SI_MAXCORES]; /* second address space size */
58 uint32 coresba[SI_MAXCORES]; /* backplane address of each core */
59 uint32 coresba2[SI_MAXCORES]; /* address of each core second register set (usbh20) */
60 void *wrappers[SI_MAXCORES]; /* other cores wrapper va */
61 uint32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */
62 uint32 oob_router; /* oob router registers for axi */
63 uint8 attach_count;
64} si_common_info_t;
65
66typedef struct si_info {
67 struct si_pub pub; /* back plane public state (must be first field) */
68
69 void *osh; /* osl os handle */
70 void *sdh; /* bcmsdh handle */
71 void *pch; /* PCI/E core handle */
72 uint dev_coreid; /* the core provides driver functions */
73 void *intr_arg; /* interrupt callback function arg */
74 si_intrsoff_t intrsoff_fn; /* turns chip interrupts off */
75 si_intrsrestore_t intrsrestore_fn; /* restore chip interrupts */
76 si_intrsenabled_t intrsenabled_fn; /* check if interrupts are enabled */
77
78
79 gpioh_item_t *gpioh_head; /* GPIO event handlers list */
80
81 bool memseg; /* flag to toggle MEM_SEG register */
82
83 char *vars;
84 uint varsz;
85
86 void *curmap; /* current regs va */
87
88 uint curidx; /* current core index */
89 uint numcores; /* # discovered cores */
90 void *curwrap; /* current wrapper va */
91 si_common_info_t *common_info; /* Common information for all the cores in a chip */
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 BADIDX (SI_MAXCORES + 1)
102#define NOREV -1 /* Invalid rev */
103
104#define PCI(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \
105 ((si)->pub.buscoretype == PCI_CORE_ID))
106#define PCIE(si) ((BUSTYPE((si)->pub.bustype) == PCI_BUS) && \
107 ((si)->pub.buscoretype == PCIE_CORE_ID))
108#define PCMCIA(si) ((BUSTYPE((si)->pub.bustype) == PCMCIA_BUS) && ((si)->memseg == TRUE))
109
110/* Newer chips can access PCI/PCIE and CC core without requiring to change
111 * PCI BAR0 WIN
112 */
113#define SI_FAST(si) (((si)->pub.buscoretype == PCIE_CORE_ID) || \
114 (((si)->pub.buscoretype == PCI_CORE_ID) && (si)->pub.buscorerev >= 13))
115
116#define PCIEREGS(si) (((char *)((si)->curmap) + PCI_16KB0_PCIREGS_OFFSET))
117#define CCREGS_FAST(si) (((char *)((si)->curmap) + PCI_16KB0_CCREGS_OFFSET))
118
119/*
120 * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts before/
121 * after core switching to avoid invalid register accesss inside ISR.
122 */
123#define INTR_OFF(si, intr_val) \
124 if ((si)->intrsoff_fn && (si)->common_info->coreid[(si)->curidx] == (si)->dev_coreid) { \
125 intr_val = (*(si)->intrsoff_fn)((si)->intr_arg); }
126#define INTR_RESTORE(si, intr_val) \
127 if ((si)->intrsrestore_fn && (si)->common_info->coreid[(si)->curidx] == (si)->dev_coreid) {\
128 (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val); }
129
130/* dynamic clock control defines */
131#define LPOMINFREQ 25000 /* low power oscillator min */
132#define LPOMAXFREQ 43000 /* low power oscillator max */
133#define XTALMINFREQ 19800000 /* 20 MHz - 1% */
134#define XTALMAXFREQ 20200000 /* 20 MHz + 1% */
135#define PCIMINFREQ 25000000 /* 25 MHz */
136#define PCIMAXFREQ 34000000 /* 33 MHz + fudge */
137
138#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */
139#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */
140
141#define PCI_FORCEHT(si) \
142 (((PCIE(si)) && (si->pub.chip == BCM4311_CHIP_ID) && ((si->pub.chiprev <= 1))) || \
143 ((PCI(si) || PCIE(si)) && (si->pub.chip == BCM4321_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_flag(si_t *sih);
157extern void sb_setint(si_t *sih, int siflag);
158extern uint sb_corevendor(si_t *sih);
159extern uint sb_corerev(si_t *sih);
160extern uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val);
161extern bool sb_iscoreup(si_t *sih);
162extern void *sb_setcoreidx(si_t *sih, uint coreidx);
163extern uint32 sb_core_cflags(si_t *sih, uint32 mask, uint32 val);
164extern void sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val);
165extern uint32 sb_core_sflags(si_t *sih, uint32 mask, uint32 val);
166extern void sb_commit(si_t *sih);
167extern uint32 sb_base(uint32 admatch);
168extern uint32 sb_size(uint32 admatch);
169extern void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits);
170extern void sb_core_tofixup(si_t *sih);
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
178
179
180/* Wake-on-wireless-LAN (WOWL) */
181extern bool sb_pci_pmecap(si_t *sih);
182struct osl_info;
183extern bool sb_pci_fastpmecap(struct osl_info *osh);
184extern bool sb_pci_pmeclr(si_t *sih);
185extern void sb_pci_pmeen(si_t *sih);
186extern uint sb_pcie_readreg(void *sih, uint addrtype, uint offset);
187
188/* AMBA Interconnect exported externs */
189extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype,
190 void *sdh, char **vars, uint *varsz);
191extern si_t *ai_kattach(osl_t *osh);
192extern void ai_scan(si_t *sih, void *regs, uint devid);
193
194extern uint ai_flag(si_t *sih);
195extern void ai_setint(si_t *sih, int siflag);
196extern uint ai_coreidx(si_t *sih);
197extern uint ai_corevendor(si_t *sih);
198extern uint ai_corerev(si_t *sih);
199extern bool ai_iscoreup(si_t *sih);
200extern void *ai_setcoreidx(si_t *sih, uint coreidx);
201extern uint32 ai_core_cflags(si_t *sih, uint32 mask, uint32 val);
202extern void ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val);
203extern uint32 ai_core_sflags(si_t *sih, uint32 mask, uint32 val);
204extern uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val);
205extern void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits);
206extern void ai_core_disable(si_t *sih, uint32 bits);
207extern int ai_numaddrspaces(si_t *sih);
208extern uint32 ai_addrspace(si_t *sih, uint asidx);
209extern uint32 ai_addrspacesize(si_t *sih, uint asidx);
210extern void ai_write_wrap_reg(si_t *sih, uint32 offset, uint32 val);
211
212
213#endif /* _siutils_priv_h_ */
diff --git a/drivers/net/wireless/bcm4329/wl_iw.c b/drivers/net/wireless/bcm4329/wl_iw.c
new file mode 100644
index 00000000000..434e584f830
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/wl_iw.c
@@ -0,0 +1,8455 @@
1/*
2 * Linux Wireless Extensions support
3 *
4 * Copyright (C) 1999-2010, 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.51.4.9.2.6.4.142.4.78 2011/02/11 21:27:52 Exp $
25 */
26
27
28#include <typedefs.h>
29#include <linuxver.h>
30#include <osl.h>
31
32#include <bcmutils.h>
33#include <bcmendian.h>
34#include <proto/ethernet.h>
35
36#include <linux/if_arp.h>
37#include <asm/uaccess.h>
38
39#include <dngl_stats.h>
40#include <dhd.h>
41#include <dhdioctl.h>
42
43typedef void wlc_info_t;
44typedef void wl_info_t;
45typedef const struct si_pub si_t;
46#include <wlioctl.h>
47
48#include <proto/ethernet.h>
49#include <dngl_stats.h>
50#include <dhd.h>
51#define WL_ERROR(x) printf x
52#define WL_TRACE(x)
53#define WL_ASSOC(x)
54#define WL_INFORM(x)
55#define WL_WSEC(x)
56#define WL_SCAN(x)
57#define WL_PNO(x)
58#define WL_TRACE_COEX(x)
59
60#include <wl_iw.h>
61
62
63
64#ifndef IW_ENCODE_ALG_SM4
65#define IW_ENCODE_ALG_SM4 0x20
66#endif
67
68#ifndef IW_AUTH_WAPI_ENABLED
69#define IW_AUTH_WAPI_ENABLED 0x20
70#endif
71
72#ifndef IW_AUTH_WAPI_VERSION_1
73#define IW_AUTH_WAPI_VERSION_1 0x00000008
74#endif
75
76#ifndef IW_AUTH_CIPHER_SMS4
77#define IW_AUTH_CIPHER_SMS4 0x00000020
78#endif
79
80#ifndef IW_AUTH_KEY_MGMT_WAPI_PSK
81#define IW_AUTH_KEY_MGMT_WAPI_PSK 4
82#endif
83
84#ifndef IW_AUTH_KEY_MGMT_WAPI_CERT
85#define IW_AUTH_KEY_MGMT_WAPI_CERT 8
86#endif
87
88
89#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED))
90
91#include <linux/rtnetlink.h>
92#include <linux/mutex.h>
93
94#define WL_IW_USE_ISCAN 1
95#define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS 1
96
97#if defined(SOFTAP)
98#define WL_SOFTAP(x) printk x
99static struct net_device *priv_dev;
100static bool ap_cfg_running = FALSE;
101bool ap_fw_loaded = FALSE;
102static long ap_cfg_pid = -1;
103struct net_device *ap_net_dev = NULL;
104struct semaphore ap_eth_sema;
105static struct completion ap_cfg_exited;
106static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap);
107static int wl_iw_softap_deassoc_stations(struct net_device *dev, u8 *mac);
108#endif
109
110#define WL_IW_IOCTL_CALL(func_call) \
111 do { \
112 func_call; \
113 } while (0)
114
115static int g_onoff = G_WLAN_SET_ON;
116wl_iw_extra_params_t g_wl_iw_params;
117static struct mutex wl_cache_lock;
118
119extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status,
120 uint32 reason, char* stringBuf, uint buflen);
121#include <bcmsdbus.h>
122extern void dhd_customer_gpio_wlan_ctrl(int onoff);
123extern uint dhd_dev_reset(struct net_device *dev, uint8 flag);
124extern void dhd_dev_init_ioctl(struct net_device *dev);
125int dev_iw_write_cfg1_bss_var(struct net_device *dev, int val);
126
127uint wl_msg_level = WL_ERROR_VAL;
128
129#define MAX_WLIW_IOCTL_LEN 1024
130
131
132#if defined(IL_BIGENDIAN)
133#include <bcmendian.h>
134#define htod32(i) (bcmswap32(i))
135#define htod16(i) (bcmswap16(i))
136#define dtoh32(i) (bcmswap32(i))
137#define dtoh16(i) (bcmswap16(i))
138#define htodchanspec(i) htod16(i)
139#define dtohchanspec(i) dtoh16(i)
140#else
141#define htod32(i) i
142#define htod16(i) i
143#define dtoh32(i) i
144#define dtoh16(i) i
145#define htodchanspec(i) i
146#define dtohchanspec(i) i
147#endif
148
149#ifdef CONFIG_WIRELESS_EXT
150
151extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
152extern int dhd_wait_pend8021x(struct net_device *dev);
153#endif
154
155#if WIRELESS_EXT < 19
156#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST)
157#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST)
158#endif
159
160static void *g_scan = NULL;
161static volatile uint g_scan_specified_ssid;
162static wlc_ssid_t g_specific_ssid;
163
164static wlc_ssid_t g_ssid;
165
166bool btcoex_is_sco_active(struct net_device *dev);
167static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl;
168#if defined(CONFIG_FIRST_SCAN)
169static volatile uint g_first_broadcast_scan;
170static volatile uint g_first_counter_scans;
171#define MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN 3
172#endif
173
174
175#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
176#define DAEMONIZE(a) daemonize(a); \
177 allow_signal(SIGKILL); \
178 allow_signal(SIGTERM);
179#else
180#define RAISE_RX_SOFTIRQ() \
181 cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
182#define DAEMONIZE(a) daemonize(); \
183 do { if (a) \
184 strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
185 } while (0);
186#endif
187
188#if defined(WL_IW_USE_ISCAN)
189#if !defined(CSCAN)
190static void wl_iw_free_ss_cache(void);
191static int wl_iw_run_ss_cache_timer(int kick_off);
192#endif
193#if defined(CONFIG_FIRST_SCAN)
194int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag);
195#endif
196static int dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len);
197#define ISCAN_STATE_IDLE 0
198#define ISCAN_STATE_SCANING 1
199
200#define WLC_IW_ISCAN_MAXLEN 2048
201typedef struct iscan_buf {
202 struct iscan_buf * next;
203 char iscan_buf[WLC_IW_ISCAN_MAXLEN];
204} iscan_buf_t;
205
206typedef struct iscan_info {
207 struct net_device *dev;
208 struct timer_list timer;
209 uint32 timer_ms;
210 uint32 timer_on;
211 int iscan_state;
212 iscan_buf_t * list_hdr;
213 iscan_buf_t * list_cur;
214
215
216 long sysioc_pid;
217 struct semaphore sysioc_sem;
218 struct completion sysioc_exited;
219
220 uint32 scan_flag;
221#if defined CSCAN
222 char ioctlbuf[WLC_IOCTL_MEDLEN];
223#else
224 char ioctlbuf[WLC_IOCTL_SMLEN];
225#endif
226 wl_iscan_params_t *iscan_ex_params_p;
227 int iscan_ex_param_size;
228} iscan_info_t;
229#define COEX_DHCP 1
230
231#define BT_DHCP_eSCO_FIX
232#define BT_DHCP_USE_FLAGS
233#define BT_DHCP_OPPORTUNITY_WINDOW_TIME 2500
234#define BT_DHCP_FLAG_FORCE_TIME 5500
235static void wl_iw_bt_flag_set(struct net_device *dev, bool set);
236static void wl_iw_bt_release(void);
237
238typedef enum bt_coex_status {
239 BT_DHCP_IDLE = 0,
240 BT_DHCP_START,
241 BT_DHCP_OPPORTUNITY_WINDOW,
242 BT_DHCP_FLAG_FORCE_TIMEOUT
243} coex_status_t;
244
245typedef struct bt_info {
246 struct net_device *dev;
247 struct timer_list timer;
248 uint32 timer_ms;
249 uint32 timer_on;
250 bool dhcp_done;
251 int bt_state;
252
253 long bt_pid;
254 struct semaphore bt_sem;
255 struct completion bt_exited;
256} bt_info_t;
257
258bt_info_t *g_bt = NULL;
259static void wl_iw_bt_timerfunc(ulong data);
260iscan_info_t *g_iscan = NULL;
261static void wl_iw_timerfunc(ulong data);
262static void wl_iw_set_event_mask(struct net_device *dev);
263static int
264wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action);
265#endif
266static int
267wl_iw_set_scan(
268 struct net_device *dev,
269 struct iw_request_info *info,
270 union iwreq_data *wrqu,
271 char *extra
272);
273
274#ifndef CSCAN
275static int
276wl_iw_get_scan(
277 struct net_device *dev,
278 struct iw_request_info *info,
279 struct iw_point *dwrq,
280 char *extra
281);
282
283static uint
284wl_iw_get_scan_prep(
285 wl_scan_results_t *list,
286 struct iw_request_info *info,
287 char *extra,
288 short max_size
289);
290#endif
291
292static void swap_key_from_BE(
293 wl_wsec_key_t *key
294)
295{
296 key->index = htod32(key->index);
297 key->len = htod32(key->len);
298 key->algo = htod32(key->algo);
299 key->flags = htod32(key->flags);
300 key->rxiv.hi = htod32(key->rxiv.hi);
301 key->rxiv.lo = htod16(key->rxiv.lo);
302 key->iv_initialized = htod32(key->iv_initialized);
303}
304
305static void swap_key_to_BE(
306 wl_wsec_key_t *key
307)
308{
309 key->index = dtoh32(key->index);
310 key->len = dtoh32(key->len);
311 key->algo = dtoh32(key->algo);
312 key->flags = dtoh32(key->flags);
313 key->rxiv.hi = dtoh32(key->rxiv.hi);
314 key->rxiv.lo = dtoh16(key->rxiv.lo);
315 key->iv_initialized = dtoh32(key->iv_initialized);
316}
317
318static int
319dev_wlc_ioctl(
320 struct net_device *dev,
321 int cmd,
322 void *arg,
323 int len
324)
325{
326 struct ifreq ifr;
327 wl_ioctl_t ioc;
328 mm_segment_t fs;
329 int ret = -EINVAL;
330
331 if (!dev) {
332 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
333 return ret;
334 }
335
336 net_os_wake_lock(dev);
337
338 WL_INFORM(("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n",
339 __FUNCTION__, current->pid, cmd, arg, len));
340
341 if (g_onoff == G_WLAN_SET_ON) {
342 memset(&ioc, 0, sizeof(ioc));
343 ioc.cmd = cmd;
344 ioc.buf = arg;
345 ioc.len = len;
346
347 strcpy(ifr.ifr_name, dev->name);
348 ifr.ifr_data = (caddr_t) &ioc;
349
350 ret = dev_open(dev);
351 if (ret) {
352 WL_ERROR(("%s: Error dev_open: %d\n", __func__, ret));
353 net_os_wake_unlock(dev);
354 return ret;
355 }
356
357 fs = get_fs();
358 set_fs(get_ds());
359#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
360 ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
361#else
362 ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
363#endif
364 set_fs(fs);
365 }
366 else {
367 WL_TRACE(("%s: call after driver stop : ignored\n", __FUNCTION__));
368 }
369
370 net_os_wake_unlock(dev);
371
372 return ret;
373}
374
375
376static int
377dev_wlc_intvar_get_reg(
378 struct net_device *dev,
379 char *name,
380 uint reg,
381 int *retval)
382{
383 union {
384 char buf[WLC_IOCTL_SMLEN];
385 int val;
386 } var;
387 int error;
388
389 uint len;
390 len = bcm_mkiovar(name, (char *)(&reg), sizeof(reg), (char *)(&var), sizeof(var.buf));
391 ASSERT(len);
392 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
393
394 *retval = dtoh32(var.val);
395 return (error);
396}
397
398
399static int
400dev_wlc_intvar_set_reg(
401 struct net_device *dev,
402 char *name,
403 char *addr,
404 char * val)
405{
406 char reg_addr[8];
407
408 memset(reg_addr, 0, sizeof(reg_addr));
409 memcpy((char *)&reg_addr[0], (char *)addr, 4);
410 memcpy((char *)&reg_addr[4], (char *)val, 4);
411
412 return (dev_wlc_bufvar_set(dev, name, (char *)&reg_addr[0], sizeof(reg_addr)));
413}
414
415
416static int
417dev_wlc_intvar_set(
418 struct net_device *dev,
419 char *name,
420 int val)
421{
422 char buf[WLC_IOCTL_SMLEN];
423 uint len;
424
425 val = htod32(val);
426 len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
427 ASSERT(len);
428
429 return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len));
430}
431
432#if defined(WL_IW_USE_ISCAN)
433static int
434dev_iw_iovar_setbuf(
435 struct net_device *dev,
436 char *iovar,
437 void *param,
438 int paramlen,
439 void *bufptr,
440 int buflen)
441{
442 int iolen;
443
444 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
445 ASSERT(iolen);
446
447 if (iolen == 0)
448 return 0;
449
450 return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen));
451}
452
453static int
454dev_iw_iovar_getbuf(
455 struct net_device *dev,
456 char *iovar,
457 void *param,
458 int paramlen,
459 void *bufptr,
460 int buflen)
461{
462 int iolen;
463
464 iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
465 ASSERT(iolen);
466
467 return (dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen));
468}
469#endif
470
471
472#if WIRELESS_EXT > 17
473static int
474dev_wlc_bufvar_set(
475 struct net_device *dev,
476 char *name,
477 char *buf, int len)
478{
479 static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
480 uint buflen;
481
482 buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
483 ASSERT(buflen);
484
485 return (dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen));
486}
487#endif
488
489
490static int
491dev_wlc_bufvar_get(
492 struct net_device *dev,
493 char *name,
494 char *buf, int buflen)
495{
496 static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
497 int error;
498 uint len;
499
500 len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf));
501 ASSERT(len);
502 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_WLIW_IOCTL_LEN);
503 if (!error)
504 bcopy(ioctlbuf, buf, buflen);
505
506 return (error);
507}
508
509
510
511static int
512dev_wlc_intvar_get(
513 struct net_device *dev,
514 char *name,
515 int *retval)
516{
517 union {
518 char buf[WLC_IOCTL_SMLEN];
519 int val;
520 } var;
521 int error;
522
523 uint len;
524 uint data_null;
525
526 len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf));
527 ASSERT(len);
528 error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
529
530 *retval = dtoh32(var.val);
531
532 return (error);
533}
534
535
536#if WIRELESS_EXT > 12
537static int
538wl_iw_set_active_scan(
539 struct net_device *dev,
540 struct iw_request_info *info,
541 union iwreq_data *wrqu,
542 char *extra
543)
544{
545 int as = 0;
546 int error = 0;
547 char *p = extra;
548
549#if defined(WL_IW_USE_ISCAN)
550 if (g_iscan->iscan_state == ISCAN_STATE_IDLE)
551#endif
552 error = dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as));
553#if defined(WL_IW_USE_ISCAN)
554 else
555 g_iscan->scan_flag = as;
556#endif
557 p += snprintf(p, MAX_WX_STRING, "OK");
558
559 wrqu->data.length = p - extra + 1;
560 return error;
561}
562
563static int
564wl_iw_set_passive_scan(
565 struct net_device *dev,
566 struct iw_request_info *info,
567 union iwreq_data *wrqu,
568 char *extra
569)
570{
571 int ps = 1;
572 int error = 0;
573 char *p = extra;
574
575#if defined(WL_IW_USE_ISCAN)
576 if (g_iscan->iscan_state == ISCAN_STATE_IDLE) {
577#endif
578
579
580 if (g_scan_specified_ssid == 0) {
581 error = dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &ps, sizeof(ps));
582 }
583#if defined(WL_IW_USE_ISCAN)
584 }
585 else
586 g_iscan->scan_flag = ps;
587#endif
588
589 p += snprintf(p, MAX_WX_STRING, "OK");
590
591 wrqu->data.length = p - extra + 1;
592 return error;
593}
594
595
596static int
597wl_iw_set_txpower(
598 struct net_device *dev,
599 struct iw_request_info *info,
600 union iwreq_data *wrqu,
601 char *extra
602)
603{
604 int error = 0;
605 char *p = extra;
606 int txpower = -1;
607
608 txpower = bcm_atoi(extra + strlen(TXPOWER_SET_CMD) + 1);
609 if ((txpower >= 0) && (txpower <= 127)) {
610 txpower |= WL_TXPWR_OVERRIDE;
611 txpower = htod32(txpower);
612
613 error = dev_wlc_intvar_set(dev, "qtxpower", txpower);
614 p += snprintf(p, MAX_WX_STRING, "OK");
615 WL_TRACE(("%s: set TXpower 0x%X is OK\n", __FUNCTION__, txpower));
616 } else {
617 WL_ERROR(("%s: set tx power failed\n", __FUNCTION__));
618 p += snprintf(p, MAX_WX_STRING, "FAIL");
619 }
620
621 wrqu->data.length = p - extra + 1;
622 return error;
623}
624
625static int
626wl_iw_get_macaddr(
627 struct net_device *dev,
628 struct iw_request_info *info,
629 union iwreq_data *wrqu,
630 char *extra
631)
632{
633 int error;
634 char buf[128];
635 struct ether_addr *id;
636 char *p = extra;
637
638
639 strcpy(buf, "cur_etheraddr");
640 error = dev_wlc_ioctl(dev, WLC_GET_VAR, buf, sizeof(buf));
641 id = (struct ether_addr *) buf;
642 p += snprintf(p, MAX_WX_STRING, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
643 id->octet[0], id->octet[1], id->octet[2],
644 id->octet[3], id->octet[4], id->octet[5]);
645 wrqu->data.length = p - extra + 1;
646
647 return error;
648}
649
650
651static int
652wl_iw_set_country(
653 struct net_device *dev,
654 struct iw_request_info *info,
655 union iwreq_data *wrqu,
656 char *extra
657)
658{
659 char country_code[WLC_CNTRY_BUF_SZ];
660 int error = 0;
661 char *p = extra;
662 int country_offset;
663 int country_code_size;
664 wl_country_t cspec = {{0}, 0, {0}};
665 char smbuf[WLC_IOCTL_SMLEN];
666
667 cspec.rev = -1;
668 memset(country_code, 0, sizeof(country_code));
669 memset(smbuf, 0, sizeof(smbuf));
670
671 country_offset = strcspn(extra, " ");
672 country_code_size = strlen(extra) - country_offset;
673
674 if (country_offset != 0) {
675 strncpy(country_code, extra + country_offset +1,
676 MIN(country_code_size, sizeof(country_code)));
677
678
679 memcpy(cspec.country_abbrev, country_code, WLC_CNTRY_BUF_SZ);
680 memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ);
681
682 get_customized_country_code((char *)&cspec.country_abbrev, &cspec);
683
684 if ((error = dev_iw_iovar_setbuf(dev, "country", &cspec, \
685 sizeof(cspec), smbuf, sizeof(smbuf))) >= 0) {
686 p += snprintf(p, MAX_WX_STRING, "OK");
687 WL_ERROR(("%s: set country for %s as %s rev %d is OK\n", \
688 __FUNCTION__, country_code, cspec.ccode, cspec.rev));
689 dhd_bus_country_set(dev, &cspec);
690 goto exit;
691 }
692 }
693
694 WL_ERROR(("%s: set country for %s as %s rev %d failed\n", \
695 __FUNCTION__, country_code, cspec.ccode, cspec.rev));
696
697 p += snprintf(p, MAX_WX_STRING, "FAIL");
698
699exit:
700 wrqu->data.length = p - extra + 1;
701 return error;
702}
703
704#ifdef CUSTOMER_HW2
705static int
706wl_iw_set_power_mode(
707 struct net_device *dev,
708 struct iw_request_info *info,
709 union iwreq_data *wrqu,
710 char *extra
711)
712{
713 int error = 0;
714 char *p = extra;
715 static int pm = PM_FAST;
716 int pm_local = PM_OFF;
717 char powermode_val = 0;
718
719 WL_TRACE_COEX(("%s: DHCP session cmd:%s\n", __FUNCTION__, extra));
720
721 strncpy((char *)&powermode_val, extra + strlen("POWERMODE") + 1, 1);
722
723 if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
724
725 dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm));
726 dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local));
727
728 /* Disable packet filtering if necessary */
729 net_os_set_packet_filter(dev, 0);
730
731 g_bt->dhcp_done = false;
732 WL_TRACE_COEX(("%s: DHCP start, pm:%d changed to pm:%d\n",
733 __FUNCTION__, pm, pm_local));
734
735 } else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) {
736
737 dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
738
739 /* Enable packet filtering if was turned off */
740 net_os_set_packet_filter(dev, 1);
741
742 g_bt->dhcp_done = true;
743
744 } else {
745 WL_ERROR(("%s Unkwown yet power setting, ignored\n",
746 __FUNCTION__));
747 }
748
749 p += snprintf(p, MAX_WX_STRING, "OK");
750
751 wrqu->data.length = p - extra + 1;
752
753 return error;
754}
755#endif
756
757
758bool btcoex_is_sco_active(struct net_device *dev)
759{
760 int ioc_res = 0;
761 bool res = false;
762 int sco_id_cnt = 0;
763 int param27;
764 int i;
765
766 for (i = 0; i < 12; i++) {
767
768 ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, &param27);
769
770 WL_TRACE_COEX(("%s, sample[%d], btc params: 27:%x\n",
771 __FUNCTION__, i, param27));
772
773 if (ioc_res < 0) {
774 WL_ERROR(("%s ioc read btc params error\n", __FUNCTION__));
775 break;
776 }
777
778 if ((param27 & 0x6) == 2) {
779 sco_id_cnt++;
780 }
781
782 if (sco_id_cnt > 2) {
783 WL_TRACE_COEX(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n",
784 __FUNCTION__, sco_id_cnt, i));
785 res = true;
786 break;
787 }
788
789 msleep(5);
790 }
791
792 return res;
793}
794
795#if defined(BT_DHCP_eSCO_FIX)
796
797static int set_btc_esco_params(struct net_device *dev, bool trump_sco)
798{
799 static bool saved_status = false;
800
801 char buf_reg50va_dhcp_on[8] = { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 };
802 char buf_reg51va_dhcp_on[8] = { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
803 char buf_reg64va_dhcp_on[8] = { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
804 char buf_reg65va_dhcp_on[8] = { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
805 char buf_reg71va_dhcp_on[8] = { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 };
806
807 uint32 regaddr;
808 static uint32 saved_reg50;
809 static uint32 saved_reg51;
810 static uint32 saved_reg64;
811 static uint32 saved_reg65;
812 static uint32 saved_reg71;
813
814 if (trump_sco) {
815
816 WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n"));
817
818 if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) &&
819 (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) &&
820 (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) &&
821 (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) &&
822 (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) {
823
824 saved_status = TRUE;
825 WL_TRACE_COEX(("%s saved bt_params[50,51,64,65,71]:"
826 " 0x%x 0x%x 0x%x 0x%x 0x%x\n",
827 __FUNCTION__, saved_reg50, saved_reg51,
828 saved_reg64, saved_reg65, saved_reg71));
829
830 } else {
831 WL_ERROR((":%s: save btc_params failed\n",
832 __FUNCTION__));
833 saved_status = false;
834 return -1;
835 }
836
837 WL_TRACE_COEX(("override with [50,51,64,65,71]:"
838 " 0x%x 0x%x 0x%x 0x%x 0x%x\n",
839 *(u32 *)(buf_reg50va_dhcp_on+4),
840 *(u32 *)(buf_reg51va_dhcp_on+4),
841 *(u32 *)(buf_reg64va_dhcp_on+4),
842 *(u32 *)(buf_reg65va_dhcp_on+4),
843 *(u32 *)(buf_reg71va_dhcp_on+4)));
844
845 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg50va_dhcp_on[0], 8);
846 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg51va_dhcp_on[0], 8);
847 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg64va_dhcp_on[0], 8);
848 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg65va_dhcp_on[0], 8);
849 dev_wlc_bufvar_set(dev, "btc_params", (char *)&buf_reg71va_dhcp_on[0], 8);
850
851 saved_status = true;
852
853 } else if (saved_status) {
854
855 WL_TRACE_COEX(("Do new SCO/eSCO coex algo {save & override} \n"));
856
857 regaddr = 50;
858 dev_wlc_intvar_set_reg(dev, "btc_params",
859 (char *)&regaddr, (char *)&saved_reg50);
860 regaddr = 51;
861 dev_wlc_intvar_set_reg(dev, "btc_params",
862 (char *)&regaddr, (char *)&saved_reg51);
863 regaddr = 64;
864 dev_wlc_intvar_set_reg(dev, "btc_params",
865 (char *)&regaddr, (char *)&saved_reg64);
866 regaddr = 65;
867 dev_wlc_intvar_set_reg(dev, "btc_params",
868 (char *)&regaddr, (char *)&saved_reg65);
869 regaddr = 71;
870 dev_wlc_intvar_set_reg(dev, "btc_params",
871 (char *)&regaddr, (char *)&saved_reg71);
872
873 WL_TRACE_COEX(("restore bt_params[50,51,64,65,71]: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
874 saved_reg50, saved_reg51, saved_reg64,
875 saved_reg65, saved_reg71));
876
877 saved_status = false;
878 } else {
879 WL_ERROR((":%s att to restore not saved BTCOEX params\n",
880 __FUNCTION__));
881 return -1;
882 }
883 return 0;
884}
885#endif
886
887static int
888wl_iw_get_power_mode(
889 struct net_device *dev,
890 struct iw_request_info *info,
891 union iwreq_data *wrqu,
892 char *extra
893)
894{
895 int error;
896 char *p = extra;
897 int pm_local = PM_FAST;
898
899 error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm_local, sizeof(pm_local));
900 if (!error) {
901 WL_TRACE(("%s: Powermode = %d\n", __func__, pm_local));
902 if (pm_local == PM_OFF)
903 pm_local = 1; /* Active */
904 else
905 pm_local = 0; /* Auto */
906 p += snprintf(p, MAX_WX_STRING, "powermode = %d", pm_local);
907 }
908 else {
909 WL_TRACE(("%s: Error = %d\n", __func__, error));
910 p += snprintf(p, MAX_WX_STRING, "FAIL");
911 }
912 wrqu->data.length = p - extra + 1;
913 return error;
914}
915
916static int
917wl_iw_set_btcoex_dhcp(
918 struct net_device *dev,
919 struct iw_request_info *info,
920 union iwreq_data *wrqu,
921 char *extra
922)
923{
924 int error = 0;
925 char *p = extra;
926#ifndef CUSTOMER_HW2
927 static int pm = PM_FAST;
928 int pm_local = PM_OFF;
929#endif
930 char powermode_val = 0;
931 char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
932 char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
933 char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
934
935 uint32 regaddr;
936 static uint32 saved_reg66;
937 static uint32 saved_reg41;
938 static uint32 saved_reg68;
939 static bool saved_status = FALSE;
940
941 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
942
943#ifdef CUSTOMER_HW2
944 strncpy((char *)&powermode_val, extra + strlen("BTCOEXMODE") + 1, 1);
945#else
946 strncpy((char *)&powermode_val, extra + strlen("POWERMODE") + 1, 1);
947#endif
948
949 if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
950
951 WL_TRACE_COEX(("%s: DHCP session start, cmd:%s\n", __FUNCTION__, extra));
952
953 if ((saved_status == FALSE) &&
954#ifndef CUSTOMER_HW2
955 (!dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))) &&
956#endif
957 (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) &&
958 (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) &&
959 (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) {
960 WL_TRACE_COEX(("save regs {66,41,68} ->: 0x%x 0x%x 0x%x\n", \
961 saved_reg66, saved_reg41, saved_reg68));
962
963#ifndef CUSTOMER_HW2
964 dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local));
965#endif
966
967 if (btcoex_is_sco_active(dev)) {
968
969 dev_wlc_bufvar_set(dev, "btc_params", \
970 (char *)&buf_reg66va_dhcp_on[0], \
971 sizeof(buf_reg66va_dhcp_on));
972
973 dev_wlc_bufvar_set(dev, "btc_params", \
974 (char *)&buf_reg41va_dhcp_on[0], \
975 sizeof(buf_reg41va_dhcp_on));
976
977 dev_wlc_bufvar_set(dev, "btc_params", \
978 (char *)&buf_reg68va_dhcp_on[0], \
979 sizeof(buf_reg68va_dhcp_on));
980 saved_status = TRUE;
981
982 g_bt->bt_state = BT_DHCP_START;
983 g_bt->timer_on = 1;
984 mod_timer(&g_bt->timer, g_bt->timer.expires);
985 WL_TRACE_COEX(("%s enable BT DHCP Timer\n", \
986 __FUNCTION__));
987 }
988 }
989 else if (saved_status == TRUE) {
990 WL_ERROR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
991 }
992 }
993#ifdef CUSTOMER_HW2
994 else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
995#else
996 else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) {
997#endif
998
999#ifndef CUSTOMER_HW2
1000 dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
1001#endif
1002
1003 WL_TRACE_COEX(("%s disable BT DHCP Timer\n", __FUNCTION__));
1004 if (g_bt->timer_on) {
1005 g_bt->timer_on = 0;
1006 del_timer_sync(&g_bt->timer);
1007
1008 if (g_bt->bt_state != BT_DHCP_IDLE) {
1009 WL_TRACE_COEX(("%s bt->bt_state:%d\n",
1010 __FUNCTION__, g_bt->bt_state));
1011
1012 up(&g_bt->bt_sem);
1013 }
1014 }
1015
1016 if (saved_status == TRUE) {
1017 dev_wlc_bufvar_set(dev, "btc_flags", \
1018 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
1019
1020 regaddr = 66;
1021 dev_wlc_intvar_set_reg(dev, "btc_params", \
1022 (char *)&regaddr, (char *)&saved_reg66);
1023 regaddr = 41;
1024 dev_wlc_intvar_set_reg(dev, "btc_params", \
1025 (char *)&regaddr, (char *)&saved_reg41);
1026 regaddr = 68;
1027 dev_wlc_intvar_set_reg(dev, "btc_params", \
1028 (char *)&regaddr, (char *)&saved_reg68);
1029
1030 WL_TRACE_COEX(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", \
1031 saved_reg66, saved_reg41, saved_reg68));
1032 }
1033 saved_status = FALSE;
1034 }
1035 else {
1036 WL_ERROR(("%s Unkwown yet power setting, ignored\n",
1037 __FUNCTION__));
1038 }
1039
1040 p += snprintf(p, MAX_WX_STRING, "OK");
1041
1042 wrqu->data.length = p - extra + 1;
1043
1044 return error;
1045}
1046
1047static int
1048wl_iw_set_suspend(
1049 struct net_device *dev,
1050 struct iw_request_info *info,
1051 union iwreq_data *wrqu,
1052 char *extra
1053)
1054{
1055 int suspend_flag;
1056 int ret_now;
1057 int ret = 0;
1058
1059 suspend_flag = *(extra + strlen(SETSUSPEND_CMD) + 1) - '0';
1060
1061 if (suspend_flag != 0)
1062 suspend_flag = 1;
1063
1064 ret_now = net_os_set_suspend_disable(dev, suspend_flag);
1065
1066 if (ret_now != suspend_flag) {
1067 if (!(ret = net_os_set_suspend(dev, ret_now)))
1068 WL_ERROR(("%s: Suspend Flag %d -> %d\n", \
1069 __FUNCTION__, ret_now, suspend_flag));
1070 else
1071 WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
1072 }
1073
1074 return ret;
1075}
1076
1077
1078int
1079wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len)
1080{
1081 int i, c;
1082 char *p = ssid_buf;
1083
1084 if (ssid_len > 32) ssid_len = 32;
1085
1086 for (i = 0; i < ssid_len; i++) {
1087 c = (int)ssid[i];
1088 if (c == '\\') {
1089 *p++ = '\\';
1090 *p++ = '\\';
1091 } else if (isprint((uchar)c)) {
1092 *p++ = (char)c;
1093 } else {
1094 p += sprintf(p, "\\x%02X", c);
1095 }
1096 }
1097 *p = '\0';
1098
1099 return p - ssid_buf;
1100}
1101
1102static int
1103wl_iw_get_link_speed(
1104 struct net_device *dev,
1105 struct iw_request_info *info,
1106 union iwreq_data *wrqu,
1107 char *extra
1108)
1109{
1110 int error = 0;
1111 char *p = extra;
1112 static int link_speed;
1113
1114 net_os_wake_lock(dev);
1115 if (g_onoff == G_WLAN_SET_ON) {
1116 error = dev_wlc_ioctl(dev, WLC_GET_RATE, &link_speed, sizeof(link_speed));
1117 link_speed *= 500000;
1118 }
1119
1120 p += snprintf(p, MAX_WX_STRING, "LinkSpeed %d", link_speed/1000000);
1121
1122 wrqu->data.length = p - extra + 1;
1123
1124 net_os_wake_unlock(dev);
1125 return error;
1126}
1127
1128
1129static int
1130wl_iw_get_dtim_skip(
1131 struct net_device *dev,
1132 struct iw_request_info *info,
1133 union iwreq_data *wrqu,
1134 char *extra
1135)
1136{
1137 int error = -1;
1138 char *p = extra;
1139 char iovbuf[32];
1140
1141 net_os_wake_lock(dev);
1142 if (g_onoff == G_WLAN_SET_ON) {
1143
1144 memset(iovbuf, 0, sizeof(iovbuf));
1145 strcpy(iovbuf, "bcn_li_dtim");
1146
1147 if ((error = dev_wlc_ioctl(dev, WLC_GET_VAR,
1148 &iovbuf, sizeof(iovbuf))) >= 0) {
1149
1150 p += snprintf(p, MAX_WX_STRING, "Dtim_skip %d", iovbuf[0]);
1151 WL_TRACE(("%s: get dtim_skip = %d\n", __FUNCTION__, iovbuf[0]));
1152 wrqu->data.length = p - extra + 1;
1153 }
1154 else
1155 WL_ERROR(("%s: get dtim_skip failed code %d\n", \
1156 __FUNCTION__, error));
1157 }
1158 net_os_wake_unlock(dev);
1159 return error;
1160}
1161
1162
1163static int
1164wl_iw_set_dtim_skip(
1165 struct net_device *dev,
1166 struct iw_request_info *info,
1167 union iwreq_data *wrqu,
1168 char *extra
1169)
1170{
1171 int error = -1;
1172 char *p = extra;
1173 int bcn_li_dtim;
1174 char iovbuf[32];
1175
1176 net_os_wake_lock(dev);
1177 if (g_onoff == G_WLAN_SET_ON) {
1178
1179 bcn_li_dtim = htod32((uint)*(extra + strlen(DTIM_SKIP_SET_CMD) + 1) - '0');
1180
1181 if ((bcn_li_dtim >= 0) || ((bcn_li_dtim <= 5))) {
1182
1183 memset(iovbuf, 0, sizeof(iovbuf));
1184 bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
1185 4, iovbuf, sizeof(iovbuf));
1186
1187 if ((error = dev_wlc_ioctl(dev, WLC_SET_VAR,
1188 &iovbuf, sizeof(iovbuf))) >= 0) {
1189 p += snprintf(p, MAX_WX_STRING, "OK");
1190
1191 net_os_set_dtim_skip(dev, bcn_li_dtim);
1192
1193 WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__, \
1194 bcn_li_dtim));
1195 goto exit;
1196 }
1197 else WL_ERROR(("%s: set dtim_skip %d failed code %d\n", \
1198 __FUNCTION__, bcn_li_dtim, error));
1199 }
1200 else WL_ERROR(("%s Incorrect dtim_skip setting %d, ignored\n", \
1201 __FUNCTION__, bcn_li_dtim));
1202 }
1203
1204 p += snprintf(p, MAX_WX_STRING, "FAIL");
1205
1206exit:
1207 wrqu->data.length = p - extra + 1;
1208 net_os_wake_unlock(dev);
1209 return error;
1210}
1211
1212
1213static int
1214wl_iw_get_band(
1215 struct net_device *dev,
1216 struct iw_request_info *info,
1217 union iwreq_data *wrqu,
1218 char *extra
1219)
1220{
1221 int error = -1;
1222 char *p = extra;
1223 static int band;
1224
1225 net_os_wake_lock(dev);
1226
1227 if (g_onoff == G_WLAN_SET_ON) {
1228 error = dev_wlc_ioctl(dev, WLC_GET_BAND, &band, sizeof(band));
1229
1230 p += snprintf(p, MAX_WX_STRING, "Band %d", band);
1231
1232 wrqu->data.length = p - extra + 1;
1233 }
1234
1235 net_os_wake_unlock(dev);
1236 return error;
1237}
1238
1239
1240static int
1241wl_iw_set_band(
1242 struct net_device *dev,
1243 struct iw_request_info *info,
1244 union iwreq_data *wrqu,
1245 char *extra
1246)
1247{
1248 int error = -1;
1249 char *p = extra;
1250 uint band;
1251
1252 net_os_wake_lock(dev);
1253
1254 if (g_onoff == G_WLAN_SET_ON) {
1255
1256 band = htod32((uint)*(extra + strlen(BAND_SET_CMD) + 1) - '0');
1257
1258 if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) {
1259
1260 if ((error = dev_wlc_ioctl(dev, WLC_SET_BAND,
1261 &band, sizeof(band))) >= 0) {
1262 p += snprintf(p, MAX_WX_STRING, "OK");
1263 WL_TRACE(("%s: set band %d OK\n", __FUNCTION__, band));
1264 goto exit;
1265 }
1266 else WL_ERROR(("%s: set band %d failed code %d\n", __FUNCTION__, \
1267 band, error));
1268 }
1269 else WL_ERROR(("%s Incorrect band setting %d, ignored\n", __FUNCTION__, band));
1270 }
1271
1272 p += snprintf(p, MAX_WX_STRING, "FAIL");
1273
1274exit:
1275 wrqu->data.length = p - extra + 1;
1276 net_os_wake_unlock(dev);
1277 return error;
1278}
1279
1280#ifdef PNO_SUPPORT
1281
1282static int
1283wl_iw_set_pno_reset(
1284 struct net_device *dev,
1285 struct iw_request_info *info,
1286 union iwreq_data *wrqu,
1287 char *extra
1288)
1289{
1290 int error = -1;
1291 char *p = extra;
1292
1293 net_os_wake_lock(dev);
1294 if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) {
1295
1296 if ((error = dhd_dev_pno_reset(dev)) >= 0) {
1297 p += snprintf(p, MAX_WX_STRING, "OK");
1298 WL_TRACE(("%s: set OK\n", __FUNCTION__));
1299 goto exit;
1300 }
1301 else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error));
1302 }
1303
1304 p += snprintf(p, MAX_WX_STRING, "FAIL");
1305
1306exit:
1307 wrqu->data.length = p - extra + 1;
1308 net_os_wake_unlock(dev);
1309 return error;
1310}
1311
1312
1313
1314static int
1315wl_iw_set_pno_enable(
1316 struct net_device *dev,
1317 struct iw_request_info *info,
1318 union iwreq_data *wrqu,
1319 char *extra
1320)
1321{
1322 int error = -1;
1323 char *p = extra;
1324 int pfn_enabled;
1325
1326 net_os_wake_lock(dev);
1327 pfn_enabled = htod32((uint)*(extra + strlen(PNOENABLE_SET_CMD) + 1) - '0');
1328
1329 if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) {
1330
1331 if ((error = dhd_dev_pno_enable(dev, pfn_enabled)) >= 0) {
1332 p += snprintf(p, MAX_WX_STRING, "OK");
1333 WL_TRACE(("%s: set OK\n", __FUNCTION__));
1334 goto exit;
1335 }
1336 else WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error));
1337 }
1338
1339 p += snprintf(p, MAX_WX_STRING, "FAIL");
1340
1341exit:
1342 wrqu->data.length = p - extra + 1;
1343 net_os_wake_unlock(dev);
1344 return error;
1345}
1346
1347
1348
1349static int
1350wl_iw_set_pno_set(
1351 struct net_device *dev,
1352 struct iw_request_info *info,
1353 union iwreq_data *wrqu,
1354 char *extra
1355)
1356{
1357 int res = -1;
1358 wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
1359 int nssid = 0;
1360 cmd_tlv_t *cmd_tlv_temp;
1361 char *str_ptr;
1362 int tlv_size_left;
1363 int pno_time;
1364 int pno_repeat;
1365 int pno_freq_expo_max;
1366
1367#ifdef PNO_SET_DEBUG
1368 int i;
1369 char pno_in_example[] = {'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', \
1370 'S', '1', '2', '0',
1371 'S',
1372 0x04,
1373 'B', 'R', 'C', 'M',
1374 'S',
1375 0x04,
1376 'G', 'O', 'O', 'G',
1377 'T',
1378 '1','E',
1379 'R',
1380 '2',
1381 'M',
1382 '2',
1383 0x00
1384 };
1385#endif
1386
1387 net_os_wake_lock(dev);
1388 WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
1389 __FUNCTION__, info->cmd, info->flags,
1390 wrqu->data.pointer, wrqu->data.length));
1391
1392 if (g_onoff == G_WLAN_SET_OFF) {
1393 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
1394 goto exit_proc;
1395 }
1396
1397 if (wrqu->data.length < (strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))) {
1398 WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__, \
1399 wrqu->data.length, strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t)));
1400 goto exit_proc;
1401 }
1402
1403#ifdef PNO_SET_DEBUG
1404 if (!(extra = kmalloc(sizeof(pno_in_example) +100, GFP_KERNEL))) {
1405 res = -ENOMEM;
1406 goto exit_proc;
1407 }
1408 memcpy(extra, pno_in_example, sizeof(pno_in_example));
1409 wrqu->data.length = sizeof(pno_in_example);
1410 for (i = 0; i < wrqu->data.length; i++)
1411 printf("%02X ", extra[i]);
1412 printf("\n");
1413#endif
1414
1415 str_ptr = extra;
1416#ifdef PNO_SET_DEBUG
1417 str_ptr += strlen("PNOSETUP ");
1418 tlv_size_left = wrqu->data.length - strlen("PNOSETUP ");
1419#else
1420 str_ptr += strlen(PNOSETUP_SET_CMD);
1421 tlv_size_left = wrqu->data.length - strlen(PNOSETUP_SET_CMD);
1422#endif
1423
1424 cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
1425 memset(ssids_local, 0, sizeof(ssids_local));
1426 pno_repeat = pno_freq_expo_max = 0;
1427
1428 if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && \
1429 (cmd_tlv_temp->version == PNO_TLV_VERSION) && \
1430 (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION))
1431 {
1432 str_ptr += sizeof(cmd_tlv_t);
1433 tlv_size_left -= sizeof(cmd_tlv_t);
1434
1435 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \
1436 MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
1437 WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
1438 goto exit_proc;
1439 }
1440 else {
1441 if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
1442 WL_ERROR(("%s scan duration corrupted field size %d\n", \
1443 __FUNCTION__, tlv_size_left));
1444 goto exit_proc;
1445 }
1446 str_ptr++;
1447 pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
1448 WL_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
1449
1450 if (str_ptr[0] != 0) {
1451 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
1452 WL_ERROR(("%s pno repeat : corrupted field\n", \
1453 __FUNCTION__));
1454 goto exit_proc;
1455 }
1456 str_ptr++;
1457 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
1458 WL_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
1459 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
1460 WL_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n", \
1461 __FUNCTION__));
1462 goto exit_proc;
1463 }
1464 str_ptr++;
1465 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
1466 WL_PNO(("%s: pno_freq_expo_max=%d\n", \
1467 __FUNCTION__, pno_freq_expo_max));
1468 }
1469 }
1470 }
1471 else {
1472 WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
1473 goto exit_proc;
1474 }
1475
1476 res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
1477
1478exit_proc:
1479 net_os_wake_unlock(dev);
1480 return res;
1481}
1482#endif
1483
1484static int
1485wl_iw_get_rssi(
1486 struct net_device *dev,
1487 struct iw_request_info *info,
1488 union iwreq_data *wrqu,
1489 char *extra
1490)
1491{
1492 static int rssi = 0;
1493 static wlc_ssid_t ssid = {0};
1494 int error = 0;
1495 char *p = extra;
1496 static char ssidbuf[SSID_FMT_BUF_LEN];
1497 scb_val_t scb_val;
1498
1499 net_os_wake_lock(dev);
1500
1501 bzero(&scb_val, sizeof(scb_val_t));
1502
1503 if (g_onoff == G_WLAN_SET_ON) {
1504 error = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
1505 if (error) {
1506 WL_ERROR(("%s: Fails %d\n", __FUNCTION__, error));
1507 } else {
1508 rssi = dtoh32(scb_val.val);
1509
1510 error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
1511 if (!error) {
1512 ssid.SSID_len = dtoh32(ssid.SSID_len);
1513 wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len));
1514 }
1515 }
1516 }
1517
1518 WL_ASSOC(("%s ssid_len:%d, rssi:%d\n", __FUNCTION__, ssid.SSID_len, rssi));
1519
1520 if (error || (ssid.SSID_len == 0)) {
1521 p += snprintf(p, MAX_WX_STRING, "FAIL");
1522 } else {
1523 p += snprintf(p, MAX_WX_STRING, "%s rssi %d ", ssidbuf, rssi);
1524 }
1525 wrqu->data.length = p - extra + 1;
1526
1527 net_os_wake_unlock(dev);
1528 return error;
1529}
1530
1531int
1532wl_iw_send_priv_event(
1533 struct net_device *dev,
1534 char *flag
1535)
1536{
1537 union iwreq_data wrqu;
1538 char extra[IW_CUSTOM_MAX + 1];
1539 int cmd;
1540
1541 cmd = IWEVCUSTOM;
1542 memset(&wrqu, 0, sizeof(wrqu));
1543 if (strlen(flag) > sizeof(extra))
1544 return -1;
1545
1546 strcpy(extra, flag);
1547 wrqu.data.length = strlen(extra);
1548 wireless_send_event(dev, cmd, &wrqu, extra);
1549 net_os_wake_lock_timeout_enable(dev);
1550 WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra));
1551
1552 return 0;
1553}
1554
1555
1556int
1557wl_control_wl_start(struct net_device *dev)
1558{
1559 int ret = 0;
1560 wl_iw_t *iw;
1561
1562 WL_TRACE(("Enter %s \n", __FUNCTION__));
1563
1564 if (!dev) {
1565 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
1566 return -1;
1567 }
1568
1569 iw = *(wl_iw_t **)netdev_priv(dev);
1570
1571 if (!iw) {
1572 WL_ERROR(("%s: wl is null\n", __FUNCTION__));
1573 return -1;
1574 }
1575 dhd_os_start_lock(iw->pub);
1576
1577 if (g_onoff == G_WLAN_SET_OFF) {
1578 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
1579
1580#if defined(BCMLXSDMMC)
1581 sdioh_start(NULL, 0);
1582#endif
1583
1584 ret = dhd_dev_reset(dev, 0);
1585
1586 if (ret == BCME_OK) {
1587#if defined(BCMLXSDMMC)
1588 sdioh_start(NULL, 1);
1589#endif
1590 dhd_dev_init_ioctl(dev);
1591 g_onoff = G_WLAN_SET_ON;
1592 }
1593 }
1594 WL_TRACE(("Exited %s \n", __FUNCTION__));
1595
1596 dhd_os_start_unlock(iw->pub);
1597 return ret;
1598}
1599
1600
1601static int
1602wl_iw_control_wl_off(
1603 struct net_device *dev,
1604 struct iw_request_info *info
1605)
1606{
1607 int ret = 0;
1608 wl_iw_t *iw;
1609
1610 WL_TRACE(("Enter %s\n", __FUNCTION__));
1611
1612 if (!dev) {
1613 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
1614 return -1;
1615 }
1616
1617 iw = *(wl_iw_t **)netdev_priv(dev);
1618 if (!iw) {
1619 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
1620 return -1;
1621 }
1622 dhd_os_start_lock(iw->pub);
1623
1624#ifdef SOFTAP
1625 ap_cfg_running = FALSE;
1626#endif
1627
1628 if (g_onoff == G_WLAN_SET_ON) {
1629 g_onoff = G_WLAN_SET_OFF;
1630#if defined(WL_IW_USE_ISCAN)
1631 g_iscan->iscan_state = ISCAN_STATE_IDLE;
1632#endif
1633
1634 dhd_dev_reset(dev, 1);
1635
1636#if defined(WL_IW_USE_ISCAN)
1637#if !defined(CSCAN)
1638 wl_iw_free_ss_cache();
1639 wl_iw_run_ss_cache_timer(0);
1640
1641 g_ss_cache_ctrl.m_link_down = 1;
1642#endif
1643 memset(g_scan, 0, G_SCAN_RESULTS);
1644 g_scan_specified_ssid = 0;
1645#if defined(CONFIG_FIRST_SCAN)
1646 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
1647 g_first_counter_scans = 0;
1648#endif
1649#endif
1650
1651#if defined(BCMLXSDMMC)
1652 sdioh_stop(NULL);
1653#endif
1654
1655 net_os_set_dtim_skip(dev, 0);
1656
1657 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
1658
1659 wl_iw_send_priv_event(dev, "STOP");
1660 }
1661
1662 dhd_os_start_unlock(iw->pub);
1663
1664 WL_TRACE(("Exited %s\n", __FUNCTION__));
1665
1666 return ret;
1667}
1668
1669static int
1670wl_iw_control_wl_on(
1671 struct net_device *dev,
1672 struct iw_request_info *info
1673)
1674{
1675 int ret = 0;
1676
1677 WL_TRACE(("Enter %s \n", __FUNCTION__));
1678
1679 if ((ret = wl_control_wl_start(dev)) != BCME_OK) {
1680 WL_ERROR(("%s failed first attemp\n", __FUNCTION__));
1681 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
1682 if ((ret = wl_control_wl_start(dev)) != BCME_OK) {
1683 WL_ERROR(("%s failed second attemp\n", __FUNCTION__));
1684 net_os_send_hang_message(dev);
1685 return ret;
1686 }
1687 }
1688
1689 wl_iw_send_priv_event(dev, "START");
1690
1691#ifdef SOFTAP
1692 if (!ap_fw_loaded) {
1693 wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
1694 }
1695#else
1696 wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
1697#endif
1698
1699 WL_TRACE(("Exited %s \n", __FUNCTION__));
1700
1701 return ret;
1702}
1703
1704#ifdef SOFTAP
1705static struct ap_profile my_ap;
1706static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap);
1707static int get_assoc_sta_list(struct net_device *dev, char *buf, int len);
1708static int set_ap_mac_list(struct net_device *dev, void *buf);
1709
1710#define PTYPE_STRING 0
1711#define PTYPE_INTDEC 1
1712#define PTYPE_INTHEX 2
1713#define PTYPE_STR_HEX 3
1714int get_parmeter_from_string(
1715 char **str_ptr, const char *token, int param_type, void *dst, int param_max_len);
1716
1717#endif
1718
1719int hex2num(char c)
1720{
1721 if (c >= '0' && c <= '9')
1722 return c - '0';
1723 if (c >= 'a' && c <= 'f')
1724 return c - 'a' + 10;
1725 if (c >= 'A' && c <= 'F')
1726 return c - 'A' + 10;
1727 return -1;
1728}
1729
1730int hex2byte(const char *hex)
1731{
1732 int a, b;
1733 a = hex2num(*hex++);
1734 if (a < 0)
1735 return -1;
1736 b = hex2num(*hex++);
1737 if (b < 0)
1738 return -1;
1739 return (a << 4) | b;
1740}
1741
1742
1743
1744int hstr_2_buf(const char *txt, u8 *buf, int len)
1745{
1746 int i;
1747
1748 for (i = 0; i < len; i++) {
1749 int a, b;
1750
1751 a = hex2num(*txt++);
1752 if (a < 0)
1753 return -1;
1754 b = hex2num(*txt++);
1755 if (b < 0)
1756 return -1;
1757 *buf++ = (a << 4) | b;
1758 }
1759
1760 return 0;
1761}
1762
1763#if defined(SOFTAP) && defined(SOFTAP_TLV_CFG)
1764
1765static int wl_iw_softap_cfg_tlv(
1766 struct net_device *dev,
1767 struct iw_request_info *info,
1768 union iwreq_data *wrqu,
1769 char *extra
1770)
1771{
1772 int res = -1;
1773 char *str_ptr;
1774 int tlv_size_left;
1775
1776
1777#define SOFTAP_TLV_DEBUG 1
1778#ifdef SOFTAP_TLV_DEBUG
1779char softap_cmd_example[] = {
1780
1781 'S', 'O', 'F', 'T', 'A', 'P', 'S', 'E', 'T', ' ',
1782
1783 SOFTAP_TLV_PREFIX, SOFTAP_TLV_VERSION,
1784 SOFTAP_TLV_SUBVERSION, SOFTAP_TLV_RESERVED,
1785
1786 TLV_TYPE_SSID, 9, 'B', 'R', 'C', 'M', ',', 'G', 'O', 'O', 'G',
1787
1788 TLV_TYPE_SECUR, 4, 'O', 'P', 'E', 'N',
1789
1790 TLV_TYPE_KEY, 4, 0x31, 0x32, 0x33, 0x34,
1791
1792 TLV_TYPE_CHANNEL, 4, 0x06, 0x00, 0x00, 0x00
1793};
1794#endif
1795
1796
1797#ifdef SOFTAP_TLV_DEBUG
1798 {
1799 int i;
1800 if (!(extra = kmalloc(sizeof(softap_cmd_example) +10, GFP_KERNEL)))
1801 return -ENOMEM;
1802 memcpy(extra, softap_cmd_example, sizeof(softap_cmd_example));
1803 wrqu->data.length = sizeof(softap_cmd_example);
1804 print_buf(extra, wrqu->data.length, 16);
1805 for (i = 0; i < wrqu->data.length; i++)
1806 printf("%c ", extra[i]);
1807 printf("\n");
1808 }
1809#endif
1810
1811 WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
1812 __FUNCTION__, info->cmd, info->flags,
1813 wrqu->data.pointer, wrqu->data.length));
1814
1815 if (g_onoff == G_WLAN_SET_OFF) {
1816 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
1817 return -1;
1818 }
1819
1820 if (wrqu->data.length < (strlen(SOFTAP_SET_CMD) + sizeof(cmd_tlv_t))) {
1821 WL_ERROR(("%s argument=%d less %d\n", __FUNCTION__,
1822 wrqu->data.length, strlen(SOFTAP_SET_CMD) + sizeof(cmd_tlv_t)));
1823 return -1;
1824 }
1825
1826 str_ptr = extra + strlen(SOFTAP_SET_CMD)+1;
1827 tlv_size_left = wrqu->data.length - (strlen(SOFTAP_SET_CMD)+1);
1828
1829 memset(&my_ap, 0, sizeof(my_ap));
1830
1831 return res;
1832}
1833#endif
1834
1835
1836#ifdef SOFTAP
1837int init_ap_profile_from_string(char *param_str, struct ap_profile *ap_cfg)
1838{
1839 char *str_ptr = param_str;
1840 char sub_cmd[16];
1841 int ret = 0;
1842
1843 memset(sub_cmd, 0, sizeof(sub_cmd));
1844 memset(ap_cfg, 0, sizeof(struct ap_profile));
1845
1846 if (get_parmeter_from_string(&str_ptr, "ASCII_CMD=",
1847 PTYPE_STRING, sub_cmd, SSID_LEN) != 0) {
1848 return -1;
1849 }
1850 if (strncmp(sub_cmd, "AP_CFG", 6)) {
1851 WL_ERROR(("ERROR: sub_cmd:%s != 'AP_CFG'!\n", sub_cmd));
1852 return -1;
1853 }
1854
1855 ret = get_parmeter_from_string(&str_ptr, "SSID=", PTYPE_STRING, ap_cfg->ssid, SSID_LEN);
1856
1857 ret |= get_parmeter_from_string(&str_ptr, "SEC=", PTYPE_STRING, ap_cfg->sec, SEC_LEN);
1858
1859 ret |= get_parmeter_from_string(&str_ptr, "KEY=", PTYPE_STRING, ap_cfg->key, KEY_LEN);
1860
1861 ret |= get_parmeter_from_string(&str_ptr, "CHANNEL=", PTYPE_INTDEC, &ap_cfg->channel, 5);
1862
1863 get_parmeter_from_string(&str_ptr, "PREAMBLE=", PTYPE_INTDEC, &ap_cfg->preamble, 5);
1864
1865 get_parmeter_from_string(&str_ptr, "MAX_SCB=", PTYPE_INTDEC, &ap_cfg->max_scb, 5);
1866
1867 get_parmeter_from_string(&str_ptr, "HIDDEN=", PTYPE_INTDEC, &ap_cfg->closednet, 5);
1868
1869 get_parmeter_from_string(&str_ptr, "COUNTRY=", PTYPE_STRING, &ap_cfg->country_code, 3);
1870
1871 return ret;
1872}
1873#endif
1874
1875
1876#ifdef SOFTAP
1877static int iwpriv_set_ap_config(struct net_device *dev,
1878 struct iw_request_info *info,
1879 union iwreq_data *wrqu,
1880 char *ext)
1881{
1882 int res = 0;
1883 char *extra = NULL;
1884 struct ap_profile *ap_cfg = &my_ap;
1885
1886 WL_TRACE(("%s: info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n",
1887 __FUNCTION__,
1888 info->cmd, info->flags,
1889 wrqu->data.pointer, wrqu->data.length));
1890
1891 if (wrqu->data.length != 0) {
1892
1893 char *str_ptr;
1894
1895 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
1896 return -ENOMEM;
1897
1898 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
1899 kfree(extra);
1900 return -EFAULT;
1901 }
1902
1903 extra[wrqu->data.length] = 0;
1904 WL_SOFTAP((" Got str param in iw_point:\n %s\n", extra));
1905
1906 memset(ap_cfg, 0, sizeof(struct ap_profile));
1907
1908 str_ptr = extra;
1909
1910 if ((res = init_ap_profile_from_string(extra, ap_cfg)) < 0) {
1911 WL_ERROR(("%s failed to parse %d\n", __FUNCTION__, res));
1912 kfree(extra);
1913 return -1;
1914 }
1915
1916 } else {
1917 WL_ERROR(("IWPRIV argument len = 0 \n"));
1918 return -1;
1919 }
1920
1921 if ((res = set_ap_cfg(dev, ap_cfg)) < 0)
1922 WL_ERROR(("%s failed to set_ap_cfg %d\n", __FUNCTION__, res));
1923
1924 kfree(extra);
1925
1926 return res;
1927}
1928#endif
1929
1930
1931#ifdef SOFTAP
1932static int iwpriv_get_assoc_list(struct net_device *dev,
1933 struct iw_request_info *info,
1934 union iwreq_data *p_iwrq,
1935 char *extra)
1936{
1937 int i, ret = 0;
1938 char mac_buf[256];
1939 struct maclist *sta_maclist = (struct maclist *)mac_buf;
1940
1941 char mac_lst[384];
1942 char *p_mac_str;
1943 char *p_mac_str_end;
1944
1945 if ((!dev) || (!extra)) {
1946 return -EINVAL;
1947 }
1948
1949 net_os_wake_lock(dev);
1950
1951 WL_TRACE(("\n %s: IWPRIV IOCTL: cmd:%hx, flags:%hx, extra:%p, iwp.len:%d, \
1952 iwp.len:%p, iwp.flags:%x \n", __FUNCTION__, info->cmd, info->flags, \
1953 extra, p_iwrq->data.length, p_iwrq->data.pointer, p_iwrq->data.flags));
1954
1955 memset(sta_maclist, 0, sizeof(mac_buf));
1956
1957 sta_maclist->count = 8;
1958
1959 WL_SOFTAP(("%s: net device:%s, buf_sz:%d\n",
1960 __FUNCTION__, dev->name, sizeof(mac_buf)));
1961
1962 if ((ret = get_assoc_sta_list(dev, mac_buf, sizeof(mac_buf))) < 0) {
1963 WL_ERROR(("%s: sta list ioctl error:%d\n",
1964 __FUNCTION__, ret));
1965 goto func_exit;
1966 }
1967
1968 WL_SOFTAP(("%s: got %d stations\n", __FUNCTION__,
1969 sta_maclist->count));
1970
1971 memset(mac_lst, 0, sizeof(mac_lst));
1972 p_mac_str = mac_lst;
1973 p_mac_str_end = &mac_lst[sizeof(mac_lst)-1];
1974
1975 for (i = 0; i < 8; i++) {
1976 struct ether_addr *id = &sta_maclist->ea[i];
1977 if (!ETHER_ISNULLADDR(id->octet)) {
1978 scb_val_t scb_val;
1979 int rssi = 0;
1980
1981 bzero(&scb_val, sizeof(scb_val_t));
1982
1983 if ((p_mac_str_end - p_mac_str) <= 36) {
1984 WL_ERROR(("%s: mac list buf is < 36 for item[%i] item\n",
1985 __FUNCTION__, i));
1986 break;
1987 }
1988
1989 p_mac_str += snprintf(p_mac_str, MAX_WX_STRING,
1990 "\nMac[%d]=%02X:%02X:%02X:%02X:%02X:%02X,", i,
1991 id->octet[0], id->octet[1], id->octet[2],
1992 id->octet[3], id->octet[4], id->octet[5]);
1993
1994 bcopy(id->octet, &scb_val.ea, 6);
1995 ret = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
1996 if (ret < 0) {
1997 snprintf(p_mac_str, MAX_WX_STRING, "RSSI:ERR");
1998 WL_ERROR(("%s: RSSI ioctl error:%d\n",
1999 __FUNCTION__, ret));
2000 break;
2001 }
2002
2003 rssi = dtoh32(scb_val.val);
2004 p_mac_str += snprintf(p_mac_str, MAX_WX_STRING,
2005 "RSSI:%d", rssi);
2006 }
2007 }
2008
2009 p_iwrq->data.length = strlen(mac_lst) + 1;
2010
2011 WL_SOFTAP(("%s: data to user:\n%s\n usr_ptr:%p\n", __FUNCTION__,
2012 mac_lst, p_iwrq->data.pointer));
2013
2014 if (p_iwrq->data.length) {
2015 bcopy(mac_lst, extra, p_iwrq->data.length);
2016 }
2017
2018func_exit:
2019 net_os_wake_unlock(dev);
2020
2021 WL_TRACE(("Exited %s \n", __FUNCTION__));
2022 return ret;
2023}
2024#endif
2025
2026
2027#ifdef SOFTAP
2028#define MAC_FILT_MAX 8
2029static int iwpriv_set_mac_filters(struct net_device *dev,
2030 struct iw_request_info *info,
2031 union iwreq_data *wrqu,
2032 char *ext)
2033{
2034 int i, ret = -1;
2035 char * extra = NULL;
2036 int mac_cnt = 0;
2037 int mac_mode = 0;
2038 struct ether_addr *p_ea;
2039 struct mac_list_set mflist_set;
2040
2041 WL_SOFTAP((">>> Got IWPRIV SET_MAC_FILTER IOCTL: info->cmd:%x, \
2042 info->flags:%x, u.data:%p, u.len:%d\n",
2043 info->cmd, info->flags,
2044 wrqu->data.pointer, wrqu->data.length));
2045
2046 if (wrqu->data.length != 0) {
2047
2048 char *str_ptr;
2049
2050 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
2051 return -ENOMEM;
2052
2053 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
2054 kfree(extra);
2055 return -EFAULT;
2056 }
2057
2058 extra[wrqu->data.length] = 0;
2059 WL_SOFTAP((" Got parameter string in iw_point:\n %s \n", extra));
2060
2061 memset(&mflist_set, 0, sizeof(mflist_set));
2062
2063 str_ptr = extra;
2064
2065 if (get_parmeter_from_string(&str_ptr, "MAC_MODE=",
2066 PTYPE_INTDEC, &mac_mode, 4) != 0) {
2067 WL_ERROR(("ERROR: 'MAC_MODE=' token is missing\n"));
2068 goto exit_proc;
2069 }
2070
2071 p_ea = &mflist_set.mac_list.ea[0];
2072
2073 if (get_parmeter_from_string(&str_ptr, "MAC_CNT=",
2074 PTYPE_INTDEC, &mac_cnt, 4) != 0) {
2075 WL_ERROR(("ERROR: 'MAC_CNT=' token param is missing \n"));
2076 goto exit_proc;
2077 }
2078
2079 if (mac_cnt > MAC_FILT_MAX) {
2080 WL_ERROR(("ERROR: number of MAC filters > MAX\n"));
2081 goto exit_proc;
2082 }
2083
2084 for (i=0; i < mac_cnt; i++)
2085 if (get_parmeter_from_string(&str_ptr, "MAC=",
2086 PTYPE_STR_HEX, &p_ea[i], 12) != 0) {
2087 WL_ERROR(("ERROR: MAC_filter[%d] is missing !\n", i));
2088 goto exit_proc;
2089 }
2090
2091 WL_SOFTAP(("MAC_MODE=:%d, MAC_CNT=%d, MACs:..\n", mac_mode, mac_cnt));
2092 for (i = 0; i < mac_cnt; i++) {
2093 WL_SOFTAP(("mac_filt[%d]:", i));
2094 print_buf(&p_ea[i], 6, 0);
2095 }
2096
2097 mflist_set.mode = mac_mode;
2098 mflist_set.mac_list.count = mac_cnt;
2099 set_ap_mac_list(dev, &mflist_set);
2100
2101 wrqu->data.pointer = NULL;
2102 wrqu->data.length = 0;
2103 ret = 0;
2104
2105 } else {
2106 WL_ERROR(("IWPRIV argument len is 0\n"));
2107 return -1;
2108 }
2109
2110 exit_proc:
2111 kfree(extra);
2112 return ret;
2113}
2114#endif
2115
2116
2117#ifdef SOFTAP
2118static int iwpriv_set_ap_sta_disassoc(struct net_device *dev,
2119 struct iw_request_info *info,
2120 union iwreq_data *wrqu,
2121 char *ext)
2122{
2123 int res = 0;
2124 char sta_mac[6] = {0, 0, 0, 0, 0, 0};
2125 char cmd_buf[256];
2126 char *str_ptr = cmd_buf;
2127
2128 WL_SOFTAP((">>%s called\n args: info->cmd:%x,"
2129 " info->flags:%x, u.data.p:%p, u.data.len:%d\n",
2130 __FUNCTION__, info->cmd, info->flags,
2131 wrqu->data.pointer, wrqu->data.length));
2132
2133 if (wrqu->data.length != 0) {
2134
2135 if (copy_from_user(cmd_buf, wrqu->data.pointer, wrqu->data.length)) {
2136 return -EFAULT;
2137 }
2138
2139 if (get_parmeter_from_string(&str_ptr,
2140 "MAC=", PTYPE_STR_HEX, sta_mac, 12) == 0) {
2141 res = wl_iw_softap_deassoc_stations(dev, sta_mac);
2142 } else {
2143 WL_ERROR(("ERROR: STA_MAC= token not found\n"));
2144 }
2145 }
2146
2147 return res;
2148}
2149#endif
2150
2151#endif
2152
2153
2154#if WIRELESS_EXT < 13
2155struct iw_request_info
2156{
2157 __u16 cmd;
2158 __u16 flags;
2159};
2160
2161typedef int (*iw_handler)(struct net_device *dev,
2162 struct iw_request_info *info,
2163 void *wrqu,
2164 char *extra);
2165#endif
2166
2167static int
2168wl_iw_config_commit(
2169 struct net_device *dev,
2170 struct iw_request_info *info,
2171 void *zwrq,
2172 char *extra
2173)
2174{
2175 wlc_ssid_t ssid;
2176 int error;
2177 struct sockaddr bssid;
2178
2179 WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name));
2180
2181 if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid))))
2182 return error;
2183
2184 ssid.SSID_len = dtoh32(ssid.SSID_len);
2185
2186 if (!ssid.SSID_len)
2187 return 0;
2188
2189 bzero(&bssid, sizeof(struct sockaddr));
2190 if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) {
2191 WL_ERROR(("%s: WLC_REASSOC to %s failed \n", __FUNCTION__, ssid.SSID));
2192 return error;
2193 }
2194
2195 return 0;
2196}
2197
2198static int
2199wl_iw_get_name(
2200 struct net_device *dev,
2201 struct iw_request_info *info,
2202 char *cwrq,
2203 char *extra
2204)
2205{
2206 WL_TRACE(("%s: SIOCGIWNAME\n", dev->name));
2207
2208 strcpy(cwrq, "IEEE 802.11-DS");
2209
2210 return 0;
2211}
2212
2213static int
2214wl_iw_set_freq(
2215 struct net_device *dev,
2216 struct iw_request_info *info,
2217 struct iw_freq *fwrq,
2218 char *extra
2219)
2220{
2221 int error, chan;
2222 uint sf = 0;
2223
2224 WL_TRACE(("%s %s: SIOCSIWFREQ\n", __FUNCTION__, dev->name));
2225
2226#if defined(SOFTAP)
2227 if (ap_cfg_running) {
2228 WL_TRACE(("%s:>> not executed, 'SOFT_AP is active' \n", __FUNCTION__));
2229 return 0;
2230 }
2231#endif
2232
2233
2234 if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
2235 chan = fwrq->m;
2236 }
2237
2238
2239 else {
2240
2241 if (fwrq->e >= 6) {
2242 fwrq->e -= 6;
2243 while (fwrq->e--)
2244 fwrq->m *= 10;
2245 } else if (fwrq->e < 6) {
2246 while (fwrq->e++ < 6)
2247 fwrq->m /= 10;
2248 }
2249
2250 if (fwrq->m > 4000 && fwrq->m < 5000)
2251 sf = WF_CHAN_FACTOR_4_G;
2252
2253 chan = wf_mhz2channel(fwrq->m, sf);
2254 }
2255 chan = htod32(chan);
2256 if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan))))
2257 return error;
2258
2259 g_wl_iw_params.target_channel = chan;
2260
2261 return -EINPROGRESS;
2262}
2263
2264static int
2265wl_iw_get_freq(
2266 struct net_device *dev,
2267 struct iw_request_info *info,
2268 struct iw_freq *fwrq,
2269 char *extra
2270)
2271{
2272 channel_info_t ci;
2273 int error;
2274
2275 WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name));
2276
2277 if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
2278 return error;
2279
2280 fwrq->m = dtoh32(ci.hw_channel);
2281 fwrq->e = dtoh32(0);
2282 return 0;
2283}
2284
2285static int
2286wl_iw_set_mode(
2287 struct net_device *dev,
2288 struct iw_request_info *info,
2289 __u32 *uwrq,
2290 char *extra
2291)
2292{
2293 int infra = 0, ap = 0, error = 0;
2294
2295 WL_TRACE(("%s: SIOCSIWMODE\n", dev->name));
2296
2297 switch (*uwrq) {
2298 case IW_MODE_MASTER:
2299 infra = ap = 1;
2300 break;
2301 case IW_MODE_ADHOC:
2302 case IW_MODE_AUTO:
2303 break;
2304 case IW_MODE_INFRA:
2305 infra = 1;
2306 break;
2307 default:
2308 return -EINVAL;
2309 }
2310 infra = htod32(infra);
2311 ap = htod32(ap);
2312
2313 if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) ||
2314 (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap))))
2315 return error;
2316
2317
2318 return -EINPROGRESS;
2319}
2320
2321static int
2322wl_iw_get_mode(
2323 struct net_device *dev,
2324 struct iw_request_info *info,
2325 __u32 *uwrq,
2326 char *extra
2327)
2328{
2329 int error, infra = 0, ap = 0;
2330
2331 WL_TRACE(("%s: SIOCGIWMODE\n", dev->name));
2332
2333 if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) ||
2334 (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap))))
2335 return error;
2336
2337 infra = dtoh32(infra);
2338 ap = dtoh32(ap);
2339 *uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
2340
2341 return 0;
2342}
2343
2344static int
2345wl_iw_get_range(
2346 struct net_device *dev,
2347 struct iw_request_info *info,
2348 struct iw_point *dwrq,
2349 char *extra
2350)
2351{
2352 struct iw_range *range = (struct iw_range *) extra;
2353 wl_uint32_list_t *list;
2354 wl_rateset_t rateset;
2355 int8 *channels;
2356 int error, i, k;
2357 uint sf, ch;
2358
2359 int phytype;
2360 int bw_cap = 0, sgi_tx = 0, nmode = 0;
2361 channel_info_t ci;
2362 uint8 nrate_list2copy = 0;
2363 uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130},
2364 {14, 29, 43, 58, 87, 116, 130, 144},
2365 {27, 54, 81, 108, 162, 216, 243, 270},
2366 {30, 60, 90, 120, 180, 240, 270, 300}};
2367
2368 WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name));
2369
2370 if (!extra)
2371 return -EINVAL;
2372
2373 channels = kmalloc((MAXCHANNEL+1)*4, GFP_KERNEL);
2374 if (!channels) {
2375 WL_ERROR(("Could not alloc channels\n"));
2376 return -ENOMEM;
2377 }
2378 list = (wl_uint32_list_t *)channels;
2379
2380 dwrq->length = sizeof(struct iw_range);
2381 memset(range, 0, sizeof(range));
2382
2383 range->min_nwid = range->max_nwid = 0;
2384
2385 list->count = htod32(MAXCHANNEL);
2386 if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, (MAXCHANNEL+1)*4))) {
2387 kfree(channels);
2388 return error;
2389 }
2390 for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) {
2391 range->freq[i].i = dtoh32(list->element[i]);
2392
2393 ch = dtoh32(list->element[i]);
2394 if (ch <= CH_MAX_2G_CHANNEL)
2395 sf = WF_CHAN_FACTOR_2_4_G;
2396 else
2397 sf = WF_CHAN_FACTOR_5_G;
2398
2399 range->freq[i].m = wf_channel2mhz(ch, sf);
2400 range->freq[i].e = 6;
2401 }
2402 range->num_frequency = range->num_channels = i;
2403
2404 range->max_qual.qual = 5;
2405
2406 range->max_qual.level = 0x100 - 200;
2407
2408 range->max_qual.noise = 0x100 - 200;
2409
2410 range->sensitivity = 65535;
2411
2412#if WIRELESS_EXT > 11
2413
2414 range->avg_qual.qual = 3;
2415
2416 range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD;
2417
2418 range->avg_qual.noise = 0x100 - 75;
2419#endif
2420
2421 if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) {
2422 kfree(channels);
2423 return error;
2424 }
2425 rateset.count = dtoh32(rateset.count);
2426 range->num_bitrates = rateset.count;
2427 for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
2428 range->bitrate[i] = (rateset.rates[i]& 0x7f) * 500000;
2429 dev_wlc_intvar_get(dev, "nmode", &nmode);
2430 dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
2431
2432 if (nmode == 1 && phytype == WLC_PHY_TYPE_SSN) {
2433 dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap);
2434 dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx);
2435 dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t));
2436 ci.hw_channel = dtoh32(ci.hw_channel);
2437
2438 if (bw_cap == 0 ||
2439 (bw_cap == 2 && ci.hw_channel <= 14)) {
2440 if (sgi_tx == 0)
2441 nrate_list2copy = 0;
2442 else
2443 nrate_list2copy = 1;
2444 }
2445 if (bw_cap == 1 ||
2446 (bw_cap == 2 && ci.hw_channel >= 36)) {
2447 if (sgi_tx == 0)
2448 nrate_list2copy = 2;
2449 else
2450 nrate_list2copy = 3;
2451 }
2452 range->num_bitrates += 8;
2453 for (k = 0; i < range->num_bitrates; k++, i++) {
2454
2455 range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000;
2456 }
2457 }
2458
2459 if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) {
2460 kfree(channels);
2461 return error;
2462 }
2463 i = dtoh32(i);
2464 if (i == WLC_PHY_TYPE_A)
2465 range->throughput = 24000000;
2466 else
2467 range->throughput = 1500000;
2468
2469 range->min_rts = 0;
2470 range->max_rts = 2347;
2471 range->min_frag = 256;
2472 range->max_frag = 2346;
2473
2474 range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS;
2475 range->num_encoding_sizes = 4;
2476 range->encoding_size[0] = WEP1_KEY_SIZE;
2477 range->encoding_size[1] = WEP128_KEY_SIZE;
2478#if WIRELESS_EXT > 17
2479 range->encoding_size[2] = TKIP_KEY_SIZE;
2480#else
2481 range->encoding_size[2] = 0;
2482#endif
2483 range->encoding_size[3] = AES_KEY_SIZE;
2484
2485 range->min_pmp = 0;
2486 range->max_pmp = 0;
2487 range->min_pmt = 0;
2488 range->max_pmt = 0;
2489 range->pmp_flags = 0;
2490 range->pm_capa = 0;
2491
2492 range->num_txpower = 2;
2493 range->txpower[0] = 1;
2494 range->txpower[1] = 255;
2495 range->txpower_capa = IW_TXPOW_MWATT;
2496
2497#if WIRELESS_EXT > 10
2498 range->we_version_compiled = WIRELESS_EXT;
2499 range->we_version_source = 19;
2500
2501 range->retry_capa = IW_RETRY_LIMIT;
2502 range->retry_flags = IW_RETRY_LIMIT;
2503 range->r_time_flags = 0;
2504
2505 range->min_retry = 1;
2506 range->max_retry = 255;
2507
2508 range->min_r_time = 0;
2509 range->max_r_time = 0;
2510#endif
2511
2512#if WIRELESS_EXT > 17
2513 range->enc_capa = IW_ENC_CAPA_WPA;
2514 range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
2515 range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
2516#ifdef BCMWPA2
2517 range->enc_capa |= IW_ENC_CAPA_WPA2;
2518#endif
2519
2520 IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
2521
2522 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
2523 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
2524 IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
2525 IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
2526#ifdef BCMWPA2
2527 IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND);
2528#endif
2529#endif
2530
2531 kfree(channels);
2532
2533 return 0;
2534}
2535
2536static int
2537rssi_to_qual(int rssi)
2538{
2539 if (rssi <= WL_IW_RSSI_NO_SIGNAL)
2540 return 0;
2541 else if (rssi <= WL_IW_RSSI_VERY_LOW)
2542 return 1;
2543 else if (rssi <= WL_IW_RSSI_LOW)
2544 return 2;
2545 else if (rssi <= WL_IW_RSSI_GOOD)
2546 return 3;
2547 else if (rssi <= WL_IW_RSSI_VERY_GOOD)
2548 return 4;
2549 else
2550 return 5;
2551}
2552
2553static int
2554wl_iw_set_spy(
2555 struct net_device *dev,
2556 struct iw_request_info *info,
2557 struct iw_point *dwrq,
2558 char *extra
2559)
2560{
2561 wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev);
2562 struct sockaddr *addr = (struct sockaddr *) extra;
2563 int i;
2564
2565 WL_TRACE(("%s: SIOCSIWSPY\n", dev->name));
2566
2567 if (!extra)
2568 return -EINVAL;
2569
2570 iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length);
2571 for (i = 0; i < iw->spy_num; i++)
2572 memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN);
2573 memset(iw->spy_qual, 0, sizeof(iw->spy_qual));
2574
2575 return 0;
2576}
2577
2578static int
2579wl_iw_get_spy(
2580 struct net_device *dev,
2581 struct iw_request_info *info,
2582 struct iw_point *dwrq,
2583 char *extra
2584)
2585{
2586 wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev);
2587 struct sockaddr *addr = (struct sockaddr *) extra;
2588 struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num];
2589 int i;
2590
2591 WL_TRACE(("%s: SIOCGIWSPY\n", dev->name));
2592
2593 if (!extra)
2594 return -EINVAL;
2595
2596 dwrq->length = iw->spy_num;
2597 for (i = 0; i < iw->spy_num; i++) {
2598 memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN);
2599 addr[i].sa_family = AF_UNIX;
2600 memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality));
2601 iw->spy_qual[i].updated = 0;
2602 }
2603
2604 return 0;
2605}
2606
2607
2608static int
2609wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params, int *join_params_size)
2610{
2611 chanspec_t chanspec = 0;
2612
2613 if (ch != 0) {
2614
2615 join_params->params.chanspec_num = 1;
2616 join_params->params.chanspec_list[0] = ch;
2617
2618 if (join_params->params.chanspec_list[0])
2619 chanspec |= WL_CHANSPEC_BAND_2G;
2620 else
2621 chanspec |= WL_CHANSPEC_BAND_5G;
2622
2623 chanspec |= WL_CHANSPEC_BW_20;
2624 chanspec |= WL_CHANSPEC_CTL_SB_NONE;
2625
2626 *join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
2627 join_params->params.chanspec_num * sizeof(chanspec_t);
2628
2629 join_params->params.chanspec_list[0] &= WL_CHANSPEC_CHAN_MASK;
2630 join_params->params.chanspec_list[0] |= chanspec;
2631 join_params->params.chanspec_list[0] =
2632 htodchanspec(join_params->params.chanspec_list[0]);
2633
2634 join_params->params.chanspec_num = htod32(join_params->params.chanspec_num);
2635
2636 WL_TRACE(("%s join_params->params.chanspec_list[0]= %X\n", \
2637 __FUNCTION__, join_params->params.chanspec_list[0]));
2638 }
2639 return 1;
2640}
2641
2642static int
2643wl_iw_set_wap(
2644 struct net_device *dev,
2645 struct iw_request_info *info,
2646 struct sockaddr *awrq,
2647 char *extra
2648)
2649{
2650 int error = -EINVAL;
2651 wl_join_params_t join_params;
2652 int join_params_size;
2653
2654 WL_TRACE(("%s: SIOCSIWAP\n", dev->name));
2655
2656 if (awrq->sa_family != ARPHRD_ETHER) {
2657 WL_ERROR(("Invalid Header...sa_family\n"));
2658 return -EINVAL;
2659 }
2660
2661
2662 if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) {
2663 scb_val_t scbval;
2664
2665 bzero(&scbval, sizeof(scb_val_t));
2666
2667 (void) dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
2668 return 0;
2669 }
2670
2671
2672
2673 memset(&join_params, 0, sizeof(join_params));
2674 join_params_size = sizeof(join_params.ssid);
2675
2676 memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
2677 join_params.ssid.SSID_len = htod32(g_ssid.SSID_len);
2678 memcpy(&join_params.params.bssid, awrq->sa_data, ETHER_ADDR_LEN);
2679
2680 WL_ASSOC(("%s target_channel=%d\n", __FUNCTION__, g_wl_iw_params.target_channel));
2681 wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size);
2682
2683 if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) {
2684 WL_ERROR(("%s Invalid ioctl data=%d\n", __FUNCTION__, error));
2685 return error;
2686 }
2687
2688 if (g_ssid.SSID_len) {
2689 WL_ASSOC(("%s: join SSID=%s BSSID="MACSTR" ch=%d\n", __FUNCTION__, \
2690 g_ssid.SSID, MAC2STR((u8 *)awrq->sa_data), \
2691 g_wl_iw_params.target_channel));
2692 }
2693
2694
2695 memset(&g_ssid, 0, sizeof(g_ssid));
2696 return 0;
2697}
2698
2699static int
2700wl_iw_get_wap(
2701 struct net_device *dev,
2702 struct iw_request_info *info,
2703 struct sockaddr *awrq,
2704 char *extra
2705)
2706{
2707 WL_TRACE(("%s: SIOCGIWAP\n", dev->name));
2708
2709 awrq->sa_family = ARPHRD_ETHER;
2710 memset(awrq->sa_data, 0, ETHER_ADDR_LEN);
2711
2712
2713 (void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN);
2714
2715 return 0;
2716}
2717
2718#if WIRELESS_EXT > 17
2719static int
2720wl_iw_mlme(
2721 struct net_device *dev,
2722 struct iw_request_info *info,
2723 struct sockaddr *awrq,
2724 char *extra
2725)
2726{
2727 struct iw_mlme *mlme;
2728 scb_val_t scbval;
2729 int error = -EINVAL;
2730
2731 WL_TRACE(("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name));
2732
2733 mlme = (struct iw_mlme *)extra;
2734 if (mlme == NULL) {
2735 WL_ERROR(("Invalid ioctl data.\n"));
2736 return error;
2737 }
2738
2739 scbval.val = mlme->reason_code;
2740 bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN);
2741
2742 if (mlme->cmd == IW_MLME_DISASSOC) {
2743 scbval.val = htod32(scbval.val);
2744 error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
2745 }
2746 else if (mlme->cmd == IW_MLME_DEAUTH) {
2747 scbval.val = htod32(scbval.val);
2748 error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
2749 sizeof(scb_val_t));
2750 }
2751 else {
2752 WL_ERROR(("Invalid ioctl data.\n"));
2753 return error;
2754 }
2755
2756 return error;
2757}
2758#endif
2759
2760#ifndef WL_IW_USE_ISCAN
2761static int
2762wl_iw_get_aplist(
2763 struct net_device *dev,
2764 struct iw_request_info *info,
2765 struct iw_point *dwrq,
2766 char *extra
2767)
2768{
2769 wl_scan_results_t *list;
2770 struct sockaddr *addr = (struct sockaddr *) extra;
2771 struct iw_quality qual[IW_MAX_AP];
2772 wl_bss_info_t *bi = NULL;
2773 int error, i;
2774 uint buflen = dwrq->length;
2775
2776 WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
2777
2778 if (!extra)
2779 return -EINVAL;
2780
2781 list = kmalloc(buflen, GFP_KERNEL);
2782 if (!list)
2783 return -ENOMEM;
2784 memset(list, 0, buflen);
2785 list->buflen = htod32(buflen);
2786 if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) {
2787 WL_ERROR(("%d: Scan results error %d\n", __LINE__, error));
2788 kfree(list);
2789 return error;
2790 }
2791 list->buflen = dtoh32(list->buflen);
2792 list->version = dtoh32(list->version);
2793 list->count = dtoh32(list->count);
2794 if (list->version != WL_BSS_INFO_VERSION) {
2795 WL_ERROR(("%s: list->version %d != WL_BSS_INFO_VERSION\n", \
2796 __FUNCTION__, list->version));
2797 kfree(list);
2798 return -EINVAL;
2799 }
2800
2801 for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
2802 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
2803
2804 if ((dtoh32(bi->length) > buflen) ||
2805 (((uintptr)bi + dtoh32(bi->length)) > ((uintptr)list + buflen))) {
2806 WL_ERROR(("%s: Scan results out of bounds: %u\n",__FUNCTION__,dtoh32(bi->length)));
2807 kfree(list);
2808 return -E2BIG;
2809 }
2810
2811 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
2812 continue;
2813
2814 memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
2815 addr[dwrq->length].sa_family = ARPHRD_ETHER;
2816 qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
2817 qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
2818 qual[dwrq->length].noise = 0x100 + bi->phy_noise;
2819
2820#if WIRELESS_EXT > 18
2821 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
2822#else
2823 qual[dwrq->length].updated = 7;
2824#endif
2825
2826 dwrq->length++;
2827 }
2828
2829 kfree(list);
2830
2831 if (dwrq->length) {
2832 memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
2833
2834 dwrq->flags = 1;
2835 }
2836 return 0;
2837}
2838#endif
2839
2840#ifdef WL_IW_USE_ISCAN
2841static int
2842wl_iw_iscan_get_aplist(
2843 struct net_device *dev,
2844 struct iw_request_info *info,
2845 struct iw_point *dwrq,
2846 char *extra
2847)
2848{
2849 wl_scan_results_t *list;
2850 iscan_buf_t * buf;
2851 iscan_info_t *iscan = g_iscan;
2852
2853 struct sockaddr *addr = (struct sockaddr *) extra;
2854 struct iw_quality qual[IW_MAX_AP];
2855 wl_bss_info_t *bi = NULL;
2856 int i;
2857
2858 WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
2859
2860 if (!extra)
2861 return -EINVAL;
2862
2863 if ((!iscan) || (iscan->sysioc_pid < 0)) {
2864 WL_ERROR(("%s error\n", __FUNCTION__));
2865 return 0;
2866 }
2867
2868 buf = iscan->list_hdr;
2869
2870 while (buf) {
2871 list = &((wl_iscan_results_t*)buf->iscan_buf)->results;
2872 if (list->version != WL_BSS_INFO_VERSION) {
2873 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \
2874 __FUNCTION__, list->version));
2875 return -EINVAL;
2876 }
2877
2878 bi = NULL;
2879 for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
2880 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length))
2881 : list->bss_info;
2882
2883 if ((dtoh32(bi->length) > WLC_IW_ISCAN_MAXLEN) ||
2884 (((uintptr)bi + dtoh32(bi->length)) > ((uintptr)list + WLC_IW_ISCAN_MAXLEN))) {
2885 WL_ERROR(("%s: Scan results out of bounds: %u\n",__FUNCTION__,dtoh32(bi->length)));
2886 return -E2BIG;
2887 }
2888
2889 if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
2890 continue;
2891
2892 memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
2893 addr[dwrq->length].sa_family = ARPHRD_ETHER;
2894 qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
2895 qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
2896 qual[dwrq->length].noise = 0x100 + bi->phy_noise;
2897
2898#if WIRELESS_EXT > 18
2899 qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
2900#else
2901 qual[dwrq->length].updated = 7;
2902#endif
2903
2904 dwrq->length++;
2905 }
2906 buf = buf->next;
2907 }
2908 if (dwrq->length) {
2909 memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
2910
2911 dwrq->flags = 1;
2912 }
2913 return 0;
2914}
2915
2916static int
2917wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
2918{
2919 int err = 0;
2920
2921 memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
2922 params->bss_type = DOT11_BSSTYPE_ANY;
2923 params->scan_type = 0;
2924 params->nprobes = -1;
2925 params->active_time = -1;
2926 params->passive_time = -1;
2927 params->home_time = -1;
2928 params->channel_num = 0;
2929#if defined(CONFIG_FIRST_SCAN)
2930 if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED)
2931 params->passive_time = 30;
2932#endif
2933 params->nprobes = htod32(params->nprobes);
2934 params->active_time = htod32(params->active_time);
2935 params->passive_time = htod32(params->passive_time);
2936 params->home_time = htod32(params->home_time);
2937 if (ssid && ssid->SSID_len)
2938 memcpy(&params->ssid, ssid, sizeof(wlc_ssid_t));
2939
2940 return err;
2941}
2942
2943static int
2944wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action)
2945{
2946 int err = 0;
2947
2948 iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
2949 iscan->iscan_ex_params_p->action = htod16(action);
2950 iscan->iscan_ex_params_p->scan_duration = htod16(0);
2951
2952 WL_SCAN(("%s : nprobes=%d\n", __FUNCTION__, iscan->iscan_ex_params_p->params.nprobes));
2953 WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
2954 WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
2955 WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
2956 WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
2957 WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type));
2958
2959 if ((err = dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p, \
2960 iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
2961 WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
2962 err = -1;
2963 }
2964
2965 return err;
2966}
2967
2968static void
2969wl_iw_timerfunc(ulong data)
2970{
2971 iscan_info_t *iscan = (iscan_info_t *)data;
2972 if (iscan) {
2973 iscan->timer_on = 0;
2974 if (iscan->iscan_state != ISCAN_STATE_IDLE) {
2975 WL_SCAN(("timer trigger\n"));
2976 up(&iscan->sysioc_sem);
2977 }
2978 }
2979}
2980static void wl_iw_set_event_mask(struct net_device *dev)
2981{
2982 char eventmask[WL_EVENTING_MASK_LEN];
2983 char iovbuf[WL_EVENTING_MASK_LEN + 12];
2984
2985 dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf));
2986 bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
2987 setbit(eventmask, WLC_E_SCAN_COMPLETE);
2988 dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN,
2989 iovbuf, sizeof(iovbuf));
2990}
2991
2992static uint32
2993wl_iw_iscan_get(iscan_info_t *iscan)
2994{
2995 iscan_buf_t * buf;
2996 iscan_buf_t * ptr;
2997 wl_iscan_results_t * list_buf;
2998 wl_iscan_results_t list;
2999 wl_scan_results_t *results;
3000 uint32 status;
3001 int res;
3002
3003 mutex_lock(&wl_cache_lock);
3004 if (iscan->list_cur) {
3005 buf = iscan->list_cur;
3006 iscan->list_cur = buf->next;
3007 }
3008 else {
3009 buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL);
3010 if (!buf) {
3011 WL_ERROR(("%s can't alloc iscan_buf_t : going to abort currect iscan\n", \
3012 __FUNCTION__));
3013 mutex_unlock(&wl_cache_lock);
3014 return WL_SCAN_RESULTS_NO_MEM;
3015 }
3016 buf->next = NULL;
3017 if (!iscan->list_hdr)
3018 iscan->list_hdr = buf;
3019 else {
3020 ptr = iscan->list_hdr;
3021 while (ptr->next) {
3022 ptr = ptr->next;
3023 }
3024 ptr->next = buf;
3025 }
3026 }
3027 memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
3028 list_buf = (wl_iscan_results_t*)buf->iscan_buf;
3029 results = &list_buf->results;
3030 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
3031 results->version = 0;
3032 results->count = 0;
3033
3034 memset(&list, 0, sizeof(list));
3035 list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
3036 res = dev_iw_iovar_getbuf(
3037 iscan->dev,
3038 "iscanresults",
3039 &list,
3040 WL_ISCAN_RESULTS_FIXED_SIZE,
3041 buf->iscan_buf,
3042 WLC_IW_ISCAN_MAXLEN);
3043 if (res == 0) {
3044 results->buflen = dtoh32(results->buflen);
3045 results->version = dtoh32(results->version);
3046 results->count = dtoh32(results->count);
3047 WL_SCAN(("results->count = %d\n", results->count));
3048
3049 WL_SCAN(("results->buflen = %d\n", results->buflen));
3050 status = dtoh32(list_buf->status);
3051 } else {
3052 WL_ERROR(("%s returns error %d\n", __FUNCTION__, res));
3053 status = WL_SCAN_RESULTS_NO_MEM;
3054 }
3055 mutex_unlock(&wl_cache_lock);
3056 return status;
3057}
3058
3059static void wl_iw_force_specific_scan(iscan_info_t *iscan)
3060{
3061 WL_SCAN(("%s force Specific SCAN for %s\n", __FUNCTION__, g_specific_ssid.SSID));
3062#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3063 rtnl_lock();
3064#endif
3065 (void) dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid));
3066#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3067 rtnl_unlock();
3068#endif
3069}
3070
3071static void wl_iw_send_scan_complete(iscan_info_t *iscan)
3072{
3073#ifndef SANDGATE2G
3074 union iwreq_data wrqu;
3075
3076 memset(&wrqu, 0, sizeof(wrqu));
3077
3078 wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL);
3079#if defined(CONFIG_FIRST_SCAN)
3080 if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED)
3081 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY;
3082#endif
3083 WL_SCAN(("Send Event ISCAN complete\n"));
3084#endif
3085}
3086
3087static int
3088_iscan_sysioc_thread(void *data)
3089{
3090 uint32 status;
3091 iscan_info_t *iscan = (iscan_info_t *)data;
3092 static bool iscan_pass_abort = FALSE;
3093
3094 DAEMONIZE("iscan_sysioc");
3095
3096 status = WL_SCAN_RESULTS_PARTIAL;
3097 while (down_interruptible(&iscan->sysioc_sem) == 0) {
3098
3099 net_os_wake_lock(iscan->dev);
3100
3101#if defined(SOFTAP)
3102 if (ap_cfg_running) {
3103 WL_SCAN(("%s skipping SCAN ops in AP mode !!!\n", __FUNCTION__));
3104 net_os_wake_unlock(iscan->dev);
3105 continue;
3106 }
3107#endif
3108
3109 if (iscan->timer_on) {
3110 iscan->timer_on = 0;
3111 del_timer_sync(&iscan->timer);
3112 }
3113
3114#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3115 rtnl_lock();
3116#endif
3117 status = wl_iw_iscan_get(iscan);
3118#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3119 rtnl_unlock();
3120#endif
3121
3122 if (g_scan_specified_ssid && (iscan_pass_abort == TRUE)) {
3123 WL_SCAN(("%s Get results from specific scan status=%d\n", __FUNCTION__, status));
3124 wl_iw_send_scan_complete(iscan);
3125 iscan_pass_abort = FALSE;
3126 status = -1;
3127 }
3128
3129 switch (status) {
3130 case WL_SCAN_RESULTS_PARTIAL:
3131 WL_SCAN(("iscanresults incomplete\n"));
3132#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3133 rtnl_lock();
3134#endif
3135
3136 wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
3137#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3138 rtnl_unlock();
3139#endif
3140
3141 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
3142 iscan->timer_on = 1;
3143 break;
3144 case WL_SCAN_RESULTS_SUCCESS:
3145 WL_SCAN(("iscanresults complete\n"));
3146 iscan->iscan_state = ISCAN_STATE_IDLE;
3147 wl_iw_send_scan_complete(iscan);
3148 break;
3149 case WL_SCAN_RESULTS_PENDING:
3150 WL_SCAN(("iscanresults pending\n"));
3151
3152 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
3153 iscan->timer_on = 1;
3154 break;
3155 case WL_SCAN_RESULTS_ABORTED:
3156 WL_SCAN(("iscanresults aborted\n"));
3157 iscan->iscan_state = ISCAN_STATE_IDLE;
3158 if (g_scan_specified_ssid == 0)
3159 wl_iw_send_scan_complete(iscan);
3160 else {
3161 iscan_pass_abort = TRUE;
3162 wl_iw_force_specific_scan(iscan);
3163 }
3164 break;
3165 case WL_SCAN_RESULTS_NO_MEM:
3166 WL_SCAN(("iscanresults can't alloc memory: skip\n"));
3167 iscan->iscan_state = ISCAN_STATE_IDLE;
3168 break;
3169 default:
3170 WL_SCAN(("iscanresults returned unknown status %d\n", status));
3171 break;
3172 }
3173
3174 net_os_wake_unlock(iscan->dev);
3175 }
3176
3177 if (iscan->timer_on) {
3178 iscan->timer_on = 0;
3179 del_timer_sync(&iscan->timer);
3180 }
3181
3182 complete_and_exit(&iscan->sysioc_exited, 0);
3183}
3184#endif
3185
3186#if !defined(CSCAN)
3187
3188static void
3189wl_iw_set_ss_cache_timer_flag(void)
3190{
3191 g_ss_cache_ctrl.m_timer_expired = 1;
3192 WL_TRACE(("%s called\n", __FUNCTION__));
3193}
3194
3195static int
3196wl_iw_init_ss_cache_ctrl(void)
3197{
3198 WL_TRACE(("%s :\n", __FUNCTION__));
3199 g_ss_cache_ctrl.m_prev_scan_mode = 0;
3200 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
3201 g_ss_cache_ctrl.m_cache_head = NULL;
3202 g_ss_cache_ctrl.m_link_down = 0;
3203 g_ss_cache_ctrl.m_timer_expired = 0;
3204 memset(g_ss_cache_ctrl.m_active_bssid, 0, ETHER_ADDR_LEN);
3205
3206 g_ss_cache_ctrl.m_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
3207 if (!g_ss_cache_ctrl.m_timer) {
3208 return -ENOMEM;
3209 }
3210 g_ss_cache_ctrl.m_timer->function = (void *)wl_iw_set_ss_cache_timer_flag;
3211 init_timer(g_ss_cache_ctrl.m_timer);
3212
3213 return 0;
3214}
3215
3216
3217
3218static void
3219wl_iw_free_ss_cache(void)
3220{
3221 wl_iw_ss_cache_t *node, *cur;
3222 wl_iw_ss_cache_t **spec_scan_head;
3223
3224 WL_TRACE(("%s called\n", __FUNCTION__));
3225
3226 mutex_lock(&wl_cache_lock);
3227 spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3228 node = *spec_scan_head;
3229
3230 for (;node;) {
3231 WL_TRACE(("%s : SSID - %s\n", __FUNCTION__, node->bss_info->SSID));
3232 cur = node;
3233 node = cur->next;
3234 kfree(cur);
3235 }
3236 *spec_scan_head = NULL;
3237 mutex_unlock(&wl_cache_lock);
3238}
3239
3240
3241
3242static int
3243wl_iw_run_ss_cache_timer(int kick_off)
3244{
3245 struct timer_list **timer;
3246
3247 timer = &g_ss_cache_ctrl.m_timer;
3248
3249 if (*timer) {
3250 if (kick_off) {
3251 (*timer)->expires = jiffies + 30000 * HZ / 1000;
3252 add_timer(*timer);
3253 WL_TRACE(("%s : timer starts \n", __FUNCTION__));
3254 } else {
3255 del_timer_sync(*timer);
3256 WL_TRACE(("%s : timer stops \n", __FUNCTION__));
3257 }
3258 }
3259
3260 return 0;
3261}
3262
3263
3264void
3265wl_iw_release_ss_cache_ctrl(void)
3266{
3267 WL_TRACE(("%s :\n", __FUNCTION__));
3268 wl_iw_free_ss_cache();
3269 wl_iw_run_ss_cache_timer(0);
3270 if (g_ss_cache_ctrl.m_timer) {
3271 kfree(g_ss_cache_ctrl.m_timer);
3272 }
3273}
3274
3275
3276
3277static void
3278wl_iw_reset_ss_cache(void)
3279{
3280 wl_iw_ss_cache_t *node, *prev, *cur;
3281 wl_iw_ss_cache_t **spec_scan_head;
3282
3283 mutex_lock(&wl_cache_lock);
3284 spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3285 node = *spec_scan_head;
3286 prev = node;
3287
3288 for (;node;) {
3289 WL_TRACE(("%s : node SSID %s \n", __FUNCTION__, node->bss_info->SSID));
3290 if (!node->dirty) {
3291 cur = node;
3292 if (cur == *spec_scan_head) {
3293 *spec_scan_head = cur->next;
3294 prev = *spec_scan_head;
3295 }
3296 else {
3297 prev->next = cur->next;
3298 }
3299 node = cur->next;
3300
3301 WL_TRACE(("%s : Del node : SSID %s\n", __FUNCTION__, cur->bss_info->SSID));
3302 kfree(cur);
3303 continue;
3304 }
3305
3306 node->dirty = 0;
3307 prev = node;
3308 node = node->next;
3309 }
3310 mutex_unlock(&wl_cache_lock);
3311}
3312
3313
3314static int
3315wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list)
3316{
3317
3318 wl_iw_ss_cache_t *node, *prev, *leaf;
3319 wl_iw_ss_cache_t **spec_scan_head;
3320 wl_bss_info_t *bi = NULL;
3321 int i;
3322
3323 if (!ss_list->count) {
3324 return 0;
3325 }
3326
3327 mutex_lock(&wl_cache_lock);
3328 spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3329
3330 for (i = 0; i < ss_list->count; i++) {
3331
3332 node = *spec_scan_head;
3333 prev = node;
3334
3335 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
3336
3337 WL_TRACE(("%s : find %d with specific SSID %s\n", __FUNCTION__, i, bi->SSID));
3338 for (;node;) {
3339 if (!memcmp(&node->bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
3340
3341 WL_TRACE(("dirty marked : SSID %s\n", bi->SSID));
3342 node->dirty = 1;
3343 break;
3344 }
3345 prev = node;
3346 node = node->next;
3347 }
3348
3349 if (node) {
3350 continue;
3351 }
3352 leaf = kmalloc(bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL);
3353 if (!leaf) {
3354 WL_ERROR(("Memory alloc failure %d\n", \
3355 bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN));
3356 mutex_unlock(&wl_cache_lock);
3357 return -ENOMEM;
3358 }
3359
3360 memcpy(leaf->bss_info, bi, bi->length);
3361 leaf->next = NULL;
3362 leaf->dirty = 1;
3363 leaf->count = 1;
3364 leaf->version = ss_list->version;
3365
3366 if (!prev) {
3367 *spec_scan_head = leaf;
3368 }
3369 else {
3370 prev->next = leaf;
3371 }
3372 }
3373 mutex_unlock(&wl_cache_lock);
3374 return 0;
3375}
3376
3377
3378static int
3379wl_iw_merge_scan_cache(struct iw_request_info *info, char *extra, uint buflen_from_user,
3380__u16 *merged_len)
3381{
3382 wl_iw_ss_cache_t *node;
3383 wl_scan_results_t *list_merge;
3384
3385 mutex_lock(&wl_cache_lock);
3386 node = g_ss_cache_ctrl.m_cache_head;
3387 for (;node;) {
3388 list_merge = (wl_scan_results_t *)&node->buflen;
3389 WL_TRACE(("%s: Cached Specific APs list=%d\n", __FUNCTION__, list_merge->count));
3390 if (buflen_from_user - *merged_len > 0) {
3391 *merged_len += (__u16) wl_iw_get_scan_prep(list_merge, info,
3392 extra + *merged_len, buflen_from_user - *merged_len);
3393 }
3394 else {
3395 WL_TRACE(("%s: exit with break\n", __FUNCTION__));
3396 break;
3397 }
3398 node = node->next;
3399 }
3400 mutex_unlock(&wl_cache_lock);
3401 return 0;
3402}
3403
3404
3405static int
3406wl_iw_delete_bss_from_ss_cache(void *addr)
3407{
3408
3409 wl_iw_ss_cache_t *node, *prev;
3410 wl_iw_ss_cache_t **spec_scan_head;
3411
3412 mutex_lock(&wl_cache_lock);
3413 spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
3414 node = *spec_scan_head;
3415 prev = node;
3416 for (;node;) {
3417 if (!memcmp(&node->bss_info->BSSID, addr, ETHER_ADDR_LEN)) {
3418 if (node == *spec_scan_head) {
3419 *spec_scan_head = node->next;
3420 }
3421 else {
3422 prev->next = node->next;
3423 }
3424
3425 WL_TRACE(("%s : Del node : %s\n", __FUNCTION__, node->bss_info->SSID));
3426 kfree(node);
3427 break;
3428 }
3429
3430 prev = node;
3431 node = node->next;
3432 }
3433
3434 memset(addr, 0, ETHER_ADDR_LEN);
3435 mutex_unlock(&wl_cache_lock);
3436 return 0;
3437}
3438
3439#endif
3440
3441
3442static int
3443wl_iw_set_scan(
3444 struct net_device *dev,
3445 struct iw_request_info *info,
3446 union iwreq_data *wrqu,
3447 char *extra
3448)
3449{
3450 int error;
3451 WL_TRACE(("%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name));
3452
3453#if defined(CSCAN)
3454 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__));
3455 return -EINVAL;
3456#endif
3457
3458#if defined(SOFTAP)
3459 if (ap_cfg_running) {
3460 WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
3461 return 0;
3462 }
3463#endif
3464
3465 if (g_onoff == G_WLAN_SET_OFF)
3466 return 0;
3467
3468 memset(&g_specific_ssid, 0, sizeof(g_specific_ssid));
3469#ifndef WL_IW_USE_ISCAN
3470 g_scan_specified_ssid = 0;
3471#endif
3472
3473#if WIRELESS_EXT > 17
3474
3475 if (wrqu->data.length == sizeof(struct iw_scan_req)) {
3476 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
3477 struct iw_scan_req *req = (struct iw_scan_req *)extra;
3478#if defined(CONFIG_FIRST_SCAN)
3479 if (g_first_broadcast_scan != BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
3480 WL_ERROR(("%s Ignoring SC %s first BC is not done = %d\n", \
3481 __FUNCTION__, req->essid, \
3482 g_first_broadcast_scan));
3483 return -EBUSY;
3484 }
3485#endif
3486 if (g_scan_specified_ssid) {
3487 WL_SCAN(("%s Specific SCAN is not done ignore scan for = %s \n", \
3488 __FUNCTION__, req->essid));
3489 return -EBUSY;
3490 }
3491 else {
3492 g_specific_ssid.SSID_len = MIN(sizeof(g_specific_ssid.SSID), \
3493 req->essid_len);
3494 memcpy(g_specific_ssid.SSID, req->essid, g_specific_ssid.SSID_len);
3495 g_specific_ssid.SSID_len = htod32(g_specific_ssid.SSID_len);
3496 g_scan_specified_ssid = 1;
3497 WL_TRACE(("### Specific scan ssid=%s len=%d\n", \
3498 g_specific_ssid.SSID, g_specific_ssid.SSID_len));
3499 }
3500 }
3501 }
3502#endif
3503
3504 if ((error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)))) {
3505 WL_SCAN(("Set SCAN for %s failed with %d\n", g_specific_ssid.SSID, error));
3506 g_scan_specified_ssid = 0;
3507 return -EBUSY;
3508 }
3509
3510 return 0;
3511}
3512
3513#ifdef WL_IW_USE_ISCAN
3514int
3515wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
3516{
3517 wlc_ssid_t ssid;
3518 iscan_info_t *iscan = g_iscan;
3519
3520#if defined(CONFIG_FIRST_SCAN)
3521 if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_IDLE) {
3522 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_STARTED;
3523 WL_SCAN(("%s: First Brodcast scan was forced\n", __FUNCTION__));
3524 }
3525 else if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) {
3526 WL_SCAN(("%s: ignore ISCAN request first BS is not done yet\n", __FUNCTION__));
3527 return 0;
3528 }
3529#endif
3530
3531#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3532 if (flag)
3533 rtnl_lock();
3534#endif
3535
3536 dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &iscan->scan_flag, sizeof(iscan->scan_flag));
3537 wl_iw_set_event_mask(dev);
3538
3539 WL_SCAN(("+++: Set Broadcast ISCAN\n"));
3540
3541 memset(&ssid, 0, sizeof(ssid));
3542
3543 iscan->list_cur = iscan->list_hdr;
3544 iscan->iscan_state = ISCAN_STATE_SCANING;
3545
3546 memset(&iscan->iscan_ex_params_p->params, 0, iscan->iscan_ex_param_size);
3547 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, &ssid);
3548 wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
3549
3550#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
3551 if (flag)
3552 rtnl_unlock();
3553#endif
3554
3555 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
3556
3557 iscan->timer_on = 1;
3558
3559 return 0;
3560}
3561
3562static int
3563wl_iw_iscan_set_scan(
3564 struct net_device *dev,
3565 struct iw_request_info *info,
3566 union iwreq_data *wrqu,
3567 char *extra
3568)
3569{
3570 wlc_ssid_t ssid;
3571 iscan_info_t *iscan = g_iscan;
3572 int ret = 0;
3573
3574 WL_SCAN(("%s: SIOCSIWSCAN : ISCAN\n", dev->name));
3575
3576#if defined(CSCAN)
3577 WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__));
3578 return -EINVAL;
3579#endif
3580
3581 net_os_wake_lock(dev);
3582
3583#if defined(SOFTAP)
3584 if (ap_cfg_running) {
3585 WL_SCAN(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
3586 goto set_scan_end;
3587 }
3588#endif
3589
3590 if (g_onoff == G_WLAN_SET_OFF) {
3591 WL_SCAN(("%s: driver is not up yet after START\n", __FUNCTION__));
3592 goto set_scan_end;
3593 }
3594
3595#ifdef PNO_SUPPORT
3596 if (dhd_dev_get_pno_status(dev)) {
3597 WL_SCAN(("%s: Scan called when PNO is active\n", __FUNCTION__));
3598 }
3599#endif
3600
3601 if ((!iscan) || (iscan->sysioc_pid < 0)) {
3602 WL_ERROR(("%s error\n", __FUNCTION__));
3603 goto set_scan_end;
3604 }
3605
3606 if (g_scan_specified_ssid) {
3607 WL_SCAN(("%s Specific SCAN already running ignoring BC scan\n", \
3608 __FUNCTION__));
3609 ret = EBUSY;
3610 goto set_scan_end;
3611 }
3612
3613 memset(&ssid, 0, sizeof(ssid));
3614
3615#if WIRELESS_EXT > 17
3616
3617 if (wrqu->data.length == sizeof(struct iw_scan_req)) {
3618 if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
3619 int as = 0;
3620 struct iw_scan_req *req = (struct iw_scan_req *)extra;
3621 ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len);
3622 memcpy(ssid.SSID, req->essid, ssid.SSID_len);
3623 ssid.SSID_len = htod32(ssid.SSID_len);
3624 dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as));
3625 wl_iw_set_event_mask(dev);
3626 ret = wl_iw_set_scan(dev, info, wrqu, extra);
3627 goto set_scan_end;
3628 }
3629 else {
3630 g_scan_specified_ssid = 0;
3631
3632 if (iscan->iscan_state == ISCAN_STATE_SCANING) {
3633 WL_SCAN(("%s ISCAN already in progress \n", __FUNCTION__));
3634 goto set_scan_end;
3635 }
3636 }
3637 }
3638#endif
3639
3640#if defined(CONFIG_FIRST_SCAN) && !defined(CSCAN)
3641 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
3642 if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) {
3643
3644 WL_ERROR(("%s Clean up First scan flag which is %d\n", \
3645 __FUNCTION__, g_first_broadcast_scan));
3646 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
3647 }
3648 else {
3649 WL_ERROR(("%s Ignoring Broadcast Scan:First Scan is not done yet %d\n", \
3650 __FUNCTION__, g_first_counter_scans));
3651 ret = -EBUSY;
3652 goto set_scan_end;
3653 }
3654 }
3655#endif
3656
3657 wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
3658
3659set_scan_end:
3660 net_os_wake_unlock(dev);
3661 return ret;
3662}
3663#endif
3664
3665#if WIRELESS_EXT > 17
3666static bool
3667ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len)
3668{
3669 uint8 *ie = *wpaie;
3670
3671 if ((ie[1] >= 6) &&
3672 !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
3673 return TRUE;
3674 }
3675
3676 ie += ie[1] + 2;
3677
3678 *tlvs_len -= (int)(ie - *tlvs);
3679
3680 *tlvs = ie;
3681 return FALSE;
3682}
3683
3684static bool
3685ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len)
3686{
3687 uint8 *ie = *wpsie;
3688
3689 if ((ie[1] >= 4) &&
3690 !bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
3691 return TRUE;
3692 }
3693
3694 ie += ie[1] + 2;
3695
3696 *tlvs_len -= (int)(ie - *tlvs);
3697
3698 *tlvs = ie;
3699 return FALSE;
3700}
3701#endif
3702
3703static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
3704 size_t len, int uppercase)
3705{
3706 size_t i;
3707 char *pos = buf, *end = buf + buf_size;
3708 int ret;
3709 if (buf_size == 0)
3710 return 0;
3711 for (i = 0; i < len; i++) {
3712 ret = snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
3713 data[i]);
3714 if (ret < 0 || ret >= end - pos) {
3715 end[-1] = '\0';
3716 return pos - buf;
3717 }
3718 pos += ret;
3719 }
3720 end[-1] = '\0';
3721 return pos - buf;
3722}
3723
3724
3725int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
3726{
3727 return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
3728}
3729
3730static int
3731wl_iw_handle_scanresults_ies(char **event_p, char *end,
3732 struct iw_request_info *info, wl_bss_info_t *bi)
3733{
3734#if WIRELESS_EXT > 17
3735 struct iw_event iwe;
3736 char *event;
3737 char *buf;
3738 int custom_event_len;
3739
3740 event = *event_p;
3741 if (bi->ie_length) {
3742
3743 bcm_tlv_t *ie;
3744 uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3745 int ptr_len = bi->ie_length;
3746
3747#ifdef BCMWPA2
3748 if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) {
3749 iwe.cmd = IWEVGENIE;
3750 iwe.u.data.length = ie->len + 2;
3751 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3752 }
3753 ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3754#endif
3755
3756 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
3757
3758 if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
3759 iwe.cmd = IWEVGENIE;
3760 iwe.u.data.length = ie->len + 2;
3761 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3762 break;
3763 }
3764 }
3765
3766 ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3767 ptr_len = bi->ie_length;
3768 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
3769 if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
3770 iwe.cmd = IWEVGENIE;
3771 iwe.u.data.length = ie->len + 2;
3772 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3773 break;
3774 }
3775 }
3776
3777 ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
3778 ptr_len = bi->ie_length;
3779
3780 while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WAPI_ID))) {
3781 WL_TRACE(("%s: found a WAPI IE...\n", __FUNCTION__));
3782#ifdef WAPI_IE_USE_GENIE
3783 iwe.cmd = IWEVGENIE;
3784 iwe.u.data.length = ie->len + 2;
3785 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
3786#else
3787 iwe.cmd = IWEVCUSTOM;
3788 custom_event_len = strlen("wapi_ie=") + 2*(ie->len + 2);
3789 iwe.u.data.length = custom_event_len;
3790
3791 buf = kmalloc(custom_event_len+1, GFP_KERNEL);
3792 if (buf == NULL)
3793 {
3794 WL_ERROR(("malloc(%d) returned NULL...\n", custom_event_len));
3795 break;
3796 }
3797
3798 memcpy(buf, "wapi_ie=", 8);
3799 wpa_snprintf_hex(buf + 8, 2+1, &(ie->id), 1);
3800 wpa_snprintf_hex(buf + 10, 2+1, &(ie->len), 1);
3801 wpa_snprintf_hex(buf + 12, 2*ie->len+1, ie->data, ie->len);
3802 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, buf);
3803 kfree(buf);
3804#endif
3805 break;
3806 }
3807 *event_p = event;
3808 }
3809#endif
3810
3811 return 0;
3812}
3813
3814#ifndef CSCAN
3815static uint
3816wl_iw_get_scan_prep(
3817 wl_scan_results_t *list,
3818 struct iw_request_info *info,
3819 char *extra,
3820 short max_size)
3821{
3822 int i, j;
3823 struct iw_event iwe;
3824 wl_bss_info_t *bi = NULL;
3825 char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value;
3826 int ret = 0;
3827 int channel;
3828
3829 if (!list) {
3830 WL_ERROR(("%s: Null list pointer",__FUNCTION__));
3831 return ret;
3832 }
3833
3834 for (i = 0; i < list->count && i < IW_MAX_AP; i++)
3835 {
3836 if (list->version != WL_BSS_INFO_VERSION) {
3837 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \
3838 __FUNCTION__, list->version));
3839 return ret;
3840 }
3841
3842 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
3843
3844 WL_TRACE(("%s : %s\n", __FUNCTION__, bi->SSID));
3845
3846 iwe.cmd = SIOCGIWAP;
3847 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
3848 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
3849 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
3850
3851 iwe.u.data.length = dtoh32(bi->SSID_len);
3852 iwe.cmd = SIOCGIWESSID;
3853 iwe.u.data.flags = 1;
3854 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
3855
3856 if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
3857 iwe.cmd = SIOCGIWMODE;
3858 if (dtoh16(bi->capability) & DOT11_CAP_ESS)
3859 iwe.u.mode = IW_MODE_INFRA;
3860 else
3861 iwe.u.mode = IW_MODE_ADHOC;
3862 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
3863 }
3864
3865 iwe.cmd = SIOCGIWFREQ;
3866 channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
3867 iwe.u.freq.m = wf_channel2mhz(channel,
3868 channel <= CH_MAX_2G_CHANNEL ?
3869 WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
3870 iwe.u.freq.e = 6;
3871 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
3872
3873 iwe.cmd = IWEVQUAL;
3874 iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
3875 iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
3876 iwe.u.qual.noise = 0x100 + bi->phy_noise;
3877 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
3878
3879 wl_iw_handle_scanresults_ies(&event, end, info, bi);
3880
3881 iwe.cmd = SIOCGIWENCODE;
3882 if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
3883 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
3884 else
3885 iwe.u.data.flags = IW_ENCODE_DISABLED;
3886 iwe.u.data.length = 0;
3887 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
3888
3889 if (bi->rateset.count) {
3890 if (((event -extra) + IW_EV_LCP_LEN) <= (uintptr)end) {
3891 value = event + IW_EV_LCP_LEN;
3892 iwe.cmd = SIOCGIWRATE;
3893
3894 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
3895 for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
3896 iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000;
3897 value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
3898 IW_EV_PARAM_LEN);
3899 }
3900 event = value;
3901 }
3902 }
3903 }
3904
3905 if ((ret = (event - extra)) < 0) {
3906 WL_ERROR(("==> Wrong size\n"));
3907 ret = 0;
3908 }
3909 WL_TRACE(("%s: size=%d bytes prepared \n", __FUNCTION__, (unsigned int)(event - extra)));
3910 return (uint)ret;
3911}
3912
3913static int
3914wl_iw_get_scan(
3915 struct net_device *dev,
3916 struct iw_request_info *info,
3917 struct iw_point *dwrq,
3918 char *extra
3919)
3920{
3921 channel_info_t ci;
3922 wl_scan_results_t *list_merge;
3923 wl_scan_results_t *list = (wl_scan_results_t *) g_scan;
3924 int error;
3925 uint buflen_from_user = dwrq->length;
3926 uint len = G_SCAN_RESULTS;
3927 __u16 len_ret = 0;
3928#if !defined(CSCAN)
3929 __u16 merged_len = 0;
3930#endif
3931#if defined(WL_IW_USE_ISCAN)
3932 iscan_info_t *iscan = g_iscan;
3933 iscan_buf_t * p_buf;
3934#if !defined(CSCAN)
3935 uint32 counter = 0;
3936#endif
3937#endif
3938 WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user));
3939
3940 if (!extra) {
3941 WL_TRACE(("%s: wl_iw_get_scan return -EINVAL\n", dev->name));
3942 return -EINVAL;
3943 }
3944
3945 if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
3946 return error;
3947 ci.scan_channel = dtoh32(ci.scan_channel);
3948 if (ci.scan_channel)
3949 return -EAGAIN;
3950
3951#if !defined(CSCAN)
3952 if (g_ss_cache_ctrl.m_timer_expired) {
3953 wl_iw_free_ss_cache();
3954 g_ss_cache_ctrl.m_timer_expired ^= 1;
3955 }
3956 if ((!g_scan_specified_ssid && g_ss_cache_ctrl.m_prev_scan_mode) ||
3957 g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) {
3958 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
3959
3960 wl_iw_reset_ss_cache();
3961 }
3962 g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
3963 if (g_scan_specified_ssid) {
3964 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
3965 }
3966 else {
3967 g_ss_cache_ctrl.m_cons_br_scan_cnt++;
3968 }
3969#endif
3970
3971 if (g_scan_specified_ssid) {
3972
3973 list = kmalloc(len, GFP_KERNEL);
3974 if (!list) {
3975 WL_TRACE(("%s: wl_iw_get_scan return -ENOMEM\n", dev->name));
3976 g_scan_specified_ssid = 0;
3977 return -ENOMEM;
3978 }
3979 }
3980
3981 memset(list, 0, len);
3982 list->buflen = htod32(len);
3983 if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len))) {
3984 WL_ERROR(("%s: %s : Scan_results ERROR %d\n", dev->name, __FUNCTION__, error));
3985 dwrq->length = len;
3986 if (g_scan_specified_ssid) {
3987 g_scan_specified_ssid = 0;
3988 kfree(list);
3989 }
3990 return 0;
3991 }
3992 list->buflen = dtoh32(list->buflen);
3993 list->version = dtoh32(list->version);
3994 list->count = dtoh32(list->count);
3995
3996 if (list->version != WL_BSS_INFO_VERSION) {
3997 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
3998 __FUNCTION__, list->version));
3999 if (g_scan_specified_ssid) {
4000 g_scan_specified_ssid = 0;
4001 kfree(list);
4002 }
4003 return -EINVAL;
4004 }
4005
4006#if !defined(CSCAN)
4007 if (g_scan_specified_ssid) {
4008
4009 wl_iw_add_bss_to_ss_cache(list);
4010 kfree(list);
4011 }
4012
4013 mutex_lock(&wl_cache_lock);
4014#if defined(WL_IW_USE_ISCAN)
4015 if (g_scan_specified_ssid)
4016 WL_TRACE(("%s: Specified scan APs from scan=%d\n", __FUNCTION__, list->count));
4017 p_buf = iscan->list_hdr;
4018
4019 while (p_buf != iscan->list_cur) {
4020 list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
4021 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
4022 counter += list_merge->count;
4023 if (list_merge->count > 0)
4024 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info,
4025 extra+len_ret, buflen_from_user -len_ret);
4026 p_buf = p_buf->next;
4027 }
4028 WL_TRACE(("%s merged with total Bcast APs=%d\n", __FUNCTION__, counter));
4029#else
4030 list_merge = (wl_scan_results_t *) g_scan;
4031 len_ret = (__u16) wl_iw_get_scan_prep(list_merge, info, extra, buflen_from_user);
4032#endif
4033 mutex_unlock(&wl_cache_lock);
4034 if (g_ss_cache_ctrl.m_link_down) {
4035 wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid);
4036 }
4037
4038 wl_iw_merge_scan_cache(info, extra+len_ret, buflen_from_user-len_ret, &merged_len);
4039 len_ret += merged_len;
4040 wl_iw_run_ss_cache_timer(0);
4041 wl_iw_run_ss_cache_timer(1);
4042#else
4043
4044 if (g_scan_specified_ssid) {
4045 WL_TRACE(("%s: Specified scan APs in the list =%d\n", __FUNCTION__, list->count));
4046 len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
4047 kfree(list);
4048
4049#if defined(WL_IW_USE_ISCAN)
4050 p_buf = iscan->list_hdr;
4051
4052 while (p_buf != iscan->list_cur) {
4053 list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
4054 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
4055 if (list_merge->count > 0)
4056 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info,
4057 extra+len_ret, buflen_from_user -len_ret);
4058 p_buf = p_buf->next;
4059 }
4060#else
4061 list_merge = (wl_scan_results_t *) g_scan;
4062 WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
4063 if (list_merge->count > 0)
4064 len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, extra+len_ret,
4065 buflen_from_user -len_ret);
4066#endif
4067 }
4068 else {
4069 list = (wl_scan_results_t *) g_scan;
4070 len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
4071 }
4072#endif
4073
4074#if defined(WL_IW_USE_ISCAN)
4075
4076 g_scan_specified_ssid = 0;
4077#endif
4078
4079 if ((len_ret + WE_ADD_EVENT_FIX) < buflen_from_user)
4080 len = len_ret;
4081
4082 dwrq->length = len;
4083 dwrq->flags = 0;
4084
4085 WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, list->count));
4086 return 0;
4087}
4088#endif
4089
4090#if defined(WL_IW_USE_ISCAN)
4091static int
4092wl_iw_iscan_get_scan(
4093 struct net_device *dev,
4094 struct iw_request_info *info,
4095 struct iw_point *dwrq,
4096 char *extra
4097)
4098{
4099 wl_scan_results_t *list;
4100 struct iw_event iwe;
4101 wl_bss_info_t *bi = NULL;
4102 int ii, j;
4103 int apcnt;
4104 char *event = extra, *end = extra + dwrq->length, *value;
4105 iscan_info_t *iscan = g_iscan;
4106 iscan_buf_t * p_buf;
4107 uint32 counter = 0;
4108 uint8 channel;
4109#if !defined(CSCAN)
4110 __u16 merged_len = 0;
4111 uint buflen_from_user = dwrq->length;
4112#endif
4113
4114 WL_SCAN(("%s %s buflen_from_user %d:\n", dev->name, __FUNCTION__, dwrq->length));
4115
4116#if defined(SOFTAP)
4117 if (ap_cfg_running) {
4118 WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
4119 return -EINVAL;
4120 }
4121#endif
4122
4123 if (!extra) {
4124 WL_TRACE(("%s: INVALID SIOCGIWSCAN GET bad parameter\n", dev->name));
4125 return -EINVAL;
4126 }
4127
4128#if defined(CONFIG_FIRST_SCAN)
4129 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_READY) {
4130 WL_TRACE(("%s %s: first ISCAN results are NOT ready yet \n", \
4131 dev->name, __FUNCTION__));
4132 return -EAGAIN;
4133 }
4134#endif
4135
4136 if ((!iscan) || (iscan->sysioc_pid < 0)) {
4137 WL_ERROR(("%ssysioc_pid\n", __FUNCTION__));
4138 return -EAGAIN;
4139 }
4140
4141#if !defined(CSCAN)
4142 if (g_ss_cache_ctrl.m_timer_expired) {
4143 wl_iw_free_ss_cache();
4144 g_ss_cache_ctrl.m_timer_expired ^= 1;
4145 }
4146 if (g_scan_specified_ssid) {
4147 return wl_iw_get_scan(dev, info, dwrq, extra);
4148 }
4149 else {
4150 if (g_ss_cache_ctrl.m_link_down) {
4151 wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid);
4152 }
4153 if (g_ss_cache_ctrl.m_prev_scan_mode || g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) {
4154 g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
4155
4156 wl_iw_reset_ss_cache();
4157 }
4158 g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
4159 g_ss_cache_ctrl.m_cons_br_scan_cnt++;
4160 }
4161#endif
4162
4163 WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name));
4164 apcnt = 0;
4165 p_buf = iscan->list_hdr;
4166
4167 while (p_buf != iscan->list_cur) {
4168 list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
4169
4170 counter += list->count;
4171
4172 if (list->version != WL_BSS_INFO_VERSION) {
4173 WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
4174 __FUNCTION__, list->version));
4175 return -EINVAL;
4176 }
4177
4178 bi = NULL;
4179 for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) {
4180 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
4181
4182 if ((dtoh32(bi->length) > WLC_IW_ISCAN_MAXLEN) ||
4183 (((uintptr)bi + dtoh32(bi->length)) > ((uintptr)list + WLC_IW_ISCAN_MAXLEN))) {
4184 WL_ERROR(("%s: Scan results out of bounds: %u\n",__FUNCTION__,dtoh32(bi->length)));
4185 return -E2BIG;
4186 }
4187
4188 if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN +
4189 IW_EV_QUAL_LEN >= end)
4190 return -E2BIG;
4191
4192 iwe.cmd = SIOCGIWAP;
4193 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
4194 memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
4195 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
4196
4197 iwe.u.data.length = dtoh32(bi->SSID_len);
4198 iwe.cmd = SIOCGIWESSID;
4199 iwe.u.data.flags = 1;
4200 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
4201
4202 if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
4203 iwe.cmd = SIOCGIWMODE;
4204 if (dtoh16(bi->capability) & DOT11_CAP_ESS)
4205 iwe.u.mode = IW_MODE_INFRA;
4206 else
4207 iwe.u.mode = IW_MODE_ADHOC;
4208 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
4209 }
4210
4211 iwe.cmd = SIOCGIWFREQ;
4212 channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
4213 iwe.u.freq.m = wf_channel2mhz(channel,
4214 channel <= CH_MAX_2G_CHANNEL ?
4215 WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
4216 iwe.u.freq.e = 6;
4217 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
4218
4219 iwe.cmd = IWEVQUAL;
4220 iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
4221 iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
4222 iwe.u.qual.noise = 0x100 + bi->phy_noise;
4223 event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
4224
4225 wl_iw_handle_scanresults_ies(&event, end, info, bi);
4226
4227 iwe.cmd = SIOCGIWENCODE;
4228 if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
4229 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
4230 else
4231 iwe.u.data.flags = IW_ENCODE_DISABLED;
4232 iwe.u.data.length = 0;
4233 event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
4234
4235 if (bi->rateset.count) {
4236 if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end)
4237 return -E2BIG;
4238
4239 value = event + IW_EV_LCP_LEN;
4240 iwe.cmd = SIOCGIWRATE;
4241
4242 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
4243 for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
4244 iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000;
4245 value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
4246 IW_EV_PARAM_LEN);
4247 }
4248 event = value;
4249 }
4250 }
4251 p_buf = p_buf->next;
4252 }
4253
4254 dwrq->length = event - extra;
4255 dwrq->flags = 0;
4256
4257#if !defined(CSCAN)
4258 wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len);
4259 dwrq->length += merged_len;
4260 wl_iw_run_ss_cache_timer(0);
4261 wl_iw_run_ss_cache_timer(1);
4262#endif /* CSCAN */
4263#if defined(CONFIG_FIRST_SCAN)
4264 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
4265#endif
4266
4267 WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter));
4268
4269 return 0;
4270}
4271#endif
4272
4273static int
4274wl_iw_set_essid(
4275 struct net_device *dev,
4276 struct iw_request_info *info,
4277 struct iw_point *dwrq,
4278 char *extra
4279)
4280{
4281 int error;
4282 wl_join_params_t join_params;
4283 int join_params_size;
4284
4285 WL_TRACE(("%s: SIOCSIWESSID\n", dev->name));
4286
4287
4288 memset(&g_ssid, 0, sizeof(g_ssid));
4289
4290 CHECK_EXTRA_FOR_NULL(extra);
4291
4292 if (dwrq->length && extra) {
4293#if WIRELESS_EXT > 20
4294 g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length);
4295#else
4296 g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length-1);
4297#endif
4298 memcpy(g_ssid.SSID, extra, g_ssid.SSID_len);
4299 } else {
4300
4301 g_ssid.SSID_len = 0;
4302 }
4303 g_ssid.SSID_len = htod32(g_ssid.SSID_len);
4304
4305 memset(&join_params, 0, sizeof(join_params));
4306 join_params_size = sizeof(join_params.ssid);
4307
4308 memcpy(&join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
4309 join_params.ssid.SSID_len = htod32(g_ssid.SSID_len);
4310 memcpy(&join_params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
4311
4312 wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size);
4313
4314 if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) {
4315 WL_ERROR(("Invalid ioctl data=%d\n", error));
4316 return error;
4317 }
4318
4319 if (g_ssid.SSID_len) {
4320 WL_TRACE(("%s: join SSID=%s ch=%d\n", __FUNCTION__, \
4321 g_ssid.SSID, g_wl_iw_params.target_channel));
4322 }
4323 return 0;
4324}
4325
4326static int
4327wl_iw_get_essid(
4328 struct net_device *dev,
4329 struct iw_request_info *info,
4330 struct iw_point *dwrq,
4331 char *extra
4332)
4333{
4334 wlc_ssid_t ssid;
4335 int error;
4336
4337 WL_TRACE(("%s: SIOCGIWESSID\n", dev->name));
4338
4339 if (!extra)
4340 return -EINVAL;
4341
4342 if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) {
4343 WL_ERROR(("Error getting the SSID\n"));
4344 return error;
4345 }
4346
4347 ssid.SSID_len = dtoh32(ssid.SSID_len);
4348
4349 memcpy(extra, ssid.SSID, ssid.SSID_len);
4350
4351 dwrq->length = ssid.SSID_len;
4352
4353 dwrq->flags = 1;
4354
4355 return 0;
4356}
4357
4358static int
4359wl_iw_set_nick(
4360 struct net_device *dev,
4361 struct iw_request_info *info,
4362 struct iw_point *dwrq,
4363 char *extra
4364)
4365{
4366 wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev);
4367
4368 WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name));
4369
4370 if (!extra)
4371 return -EINVAL;
4372
4373 if (dwrq->length > sizeof(iw->nickname))
4374 return -E2BIG;
4375
4376 memcpy(iw->nickname, extra, dwrq->length);
4377 iw->nickname[dwrq->length - 1] = '\0';
4378
4379 return 0;
4380}
4381
4382static int
4383wl_iw_get_nick(
4384 struct net_device *dev,
4385 struct iw_request_info *info,
4386 struct iw_point *dwrq,
4387 char *extra
4388)
4389{
4390 wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev);
4391
4392 WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name));
4393
4394 if (!extra)
4395 return -EINVAL;
4396
4397 strcpy(extra, iw->nickname);
4398 dwrq->length = strlen(extra) + 1;
4399
4400 return 0;
4401}
4402
4403static int wl_iw_set_rate(
4404 struct net_device *dev,
4405 struct iw_request_info *info,
4406 struct iw_param *vwrq,
4407 char *extra
4408)
4409{
4410 wl_rateset_t rateset;
4411 int error, rate, i, error_bg, error_a;
4412
4413 WL_TRACE(("%s: SIOCSIWRATE\n", dev->name));
4414
4415
4416 if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
4417 return error;
4418
4419 rateset.count = dtoh32(rateset.count);
4420
4421 if (vwrq->value < 0) {
4422
4423 rate = rateset.rates[rateset.count - 1] & 0x7f;
4424 } else if (vwrq->value < rateset.count) {
4425
4426 rate = rateset.rates[vwrq->value] & 0x7f;
4427 } else {
4428
4429 rate = vwrq->value / 500000;
4430 }
4431
4432 if (vwrq->fixed) {
4433
4434 error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate);
4435 error_a = dev_wlc_intvar_set(dev, "a_rate", rate);
4436
4437 if (error_bg && error_a)
4438 return (error_bg | error_a);
4439 } else {
4440
4441
4442 error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0);
4443
4444 error_a = dev_wlc_intvar_set(dev, "a_rate", 0);
4445
4446 if (error_bg && error_a)
4447 return (error_bg | error_a);
4448
4449
4450 for (i = 0; i < rateset.count; i++)
4451 if ((rateset.rates[i] & 0x7f) > rate)
4452 break;
4453 rateset.count = htod32(i);
4454
4455
4456 if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset))))
4457 return error;
4458 }
4459
4460 return 0;
4461}
4462
4463static int wl_iw_get_rate(
4464 struct net_device *dev,
4465 struct iw_request_info *info,
4466 struct iw_param *vwrq,
4467 char *extra
4468)
4469{
4470 int error, rate;
4471
4472 WL_TRACE(("%s: SIOCGIWRATE\n", dev->name));
4473
4474
4475 if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate))))
4476 return error;
4477 rate = dtoh32(rate);
4478 vwrq->value = rate * 500000;
4479
4480 return 0;
4481}
4482
4483static int
4484wl_iw_set_rts(
4485 struct net_device *dev,
4486 struct iw_request_info *info,
4487 struct iw_param *vwrq,
4488 char *extra
4489)
4490{
4491 int error, rts;
4492
4493 WL_TRACE(("%s: SIOCSIWRTS\n", dev->name));
4494
4495 if (vwrq->disabled)
4496 rts = DOT11_DEFAULT_RTS_LEN;
4497 else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN)
4498 return -EINVAL;
4499 else
4500 rts = vwrq->value;
4501
4502 if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts)))
4503 return error;
4504
4505 return 0;
4506}
4507
4508static int
4509wl_iw_get_rts(
4510 struct net_device *dev,
4511 struct iw_request_info *info,
4512 struct iw_param *vwrq,
4513 char *extra
4514)
4515{
4516 int error, rts;
4517
4518 WL_TRACE(("%s: SIOCGIWRTS\n", dev->name));
4519
4520 if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts)))
4521 return error;
4522
4523 vwrq->value = rts;
4524 vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN);
4525 vwrq->fixed = 1;
4526
4527 return 0;
4528}
4529
4530static int
4531wl_iw_set_frag(
4532 struct net_device *dev,
4533 struct iw_request_info *info,
4534 struct iw_param *vwrq,
4535 char *extra
4536)
4537{
4538 int error, frag;
4539
4540 WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name));
4541
4542 if (vwrq->disabled)
4543 frag = DOT11_DEFAULT_FRAG_LEN;
4544 else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN)
4545 return -EINVAL;
4546 else
4547 frag = vwrq->value;
4548
4549 if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag)))
4550 return error;
4551
4552 return 0;
4553}
4554
4555static int
4556wl_iw_get_frag(
4557 struct net_device *dev,
4558 struct iw_request_info *info,
4559 struct iw_param *vwrq,
4560 char *extra
4561)
4562{
4563 int error, fragthreshold;
4564
4565 WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name));
4566
4567 if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold)))
4568 return error;
4569
4570 vwrq->value = fragthreshold;
4571 vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN);
4572 vwrq->fixed = 1;
4573
4574 return 0;
4575}
4576
4577static int
4578wl_iw_set_txpow(
4579 struct net_device *dev,
4580 struct iw_request_info *info,
4581 struct iw_param *vwrq,
4582 char *extra
4583)
4584{
4585 int error, disable;
4586 uint16 txpwrmw;
4587 WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name));
4588
4589
4590 disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
4591 disable += WL_RADIO_SW_DISABLE << 16;
4592
4593 disable = htod32(disable);
4594 if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable))))
4595 return error;
4596
4597
4598 if (disable & WL_RADIO_SW_DISABLE)
4599 return 0;
4600
4601
4602 if (!(vwrq->flags & IW_TXPOW_MWATT))
4603 return -EINVAL;
4604
4605
4606 if (vwrq->value < 0)
4607 return 0;
4608
4609 if (vwrq->value > 0xffff) txpwrmw = 0xffff;
4610 else txpwrmw = (uint16)vwrq->value;
4611
4612
4613 error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw)));
4614 return error;
4615}
4616
4617static int
4618wl_iw_get_txpow(
4619 struct net_device *dev,
4620 struct iw_request_info *info,
4621 struct iw_param *vwrq,
4622 char *extra
4623)
4624{
4625 int error, disable, txpwrdbm;
4626 uint8 result;
4627
4628 WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name));
4629
4630 if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) ||
4631 (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm)))
4632 return error;
4633
4634 disable = dtoh32(disable);
4635 result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE);
4636 vwrq->value = (int32)bcm_qdbm_to_mw(result);
4637 vwrq->fixed = 0;
4638 vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0;
4639 vwrq->flags = IW_TXPOW_MWATT;
4640
4641 return 0;
4642}
4643
4644#if WIRELESS_EXT > 10
4645static int
4646wl_iw_set_retry(
4647 struct net_device *dev,
4648 struct iw_request_info *info,
4649 struct iw_param *vwrq,
4650 char *extra
4651)
4652{
4653 int error, lrl, srl;
4654
4655 WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name));
4656
4657
4658 if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
4659 return -EINVAL;
4660
4661
4662 if (vwrq->flags & IW_RETRY_LIMIT) {
4663
4664
4665#if WIRELESS_EXT > 20
4666 if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) ||
4667 !((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) {
4668#else
4669 if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) {
4670#endif
4671 lrl = htod32(vwrq->value);
4672 if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl))))
4673 return error;
4674 }
4675
4676
4677#if WIRELESS_EXT > 20
4678 if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) ||
4679 !((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) {
4680#else
4681 if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) {
4682#endif
4683 srl = htod32(vwrq->value);
4684 if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl))))
4685 return error;
4686 }
4687 }
4688 return 0;
4689}
4690
4691static int
4692wl_iw_get_retry(
4693 struct net_device *dev,
4694 struct iw_request_info *info,
4695 struct iw_param *vwrq,
4696 char *extra
4697)
4698{
4699 int error, lrl, srl;
4700
4701 WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name));
4702
4703 vwrq->disabled = 0;
4704
4705
4706 if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
4707 return -EINVAL;
4708
4709
4710 if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) ||
4711 (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl))))
4712 return error;
4713
4714 lrl = dtoh32(lrl);
4715 srl = dtoh32(srl);
4716
4717
4718 if (vwrq->flags & IW_RETRY_MAX) {
4719 vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
4720 vwrq->value = lrl;
4721 } else {
4722 vwrq->flags = IW_RETRY_LIMIT;
4723 vwrq->value = srl;
4724 if (srl != lrl)
4725 vwrq->flags |= IW_RETRY_MIN;
4726 }
4727
4728 return 0;
4729}
4730#endif
4731
4732static int
4733wl_iw_set_encode(
4734 struct net_device *dev,
4735 struct iw_request_info *info,
4736 struct iw_point *dwrq,
4737 char *extra
4738)
4739{
4740 wl_wsec_key_t key;
4741 int error, val, wsec;
4742
4743 WL_TRACE(("%s: SIOCSIWENCODE\n", dev->name));
4744
4745 memset(&key, 0, sizeof(key));
4746
4747 if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
4748
4749 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
4750 val = htod32(key.index);
4751 if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
4752 return error;
4753 val = dtoh32(val);
4754 if (val)
4755 break;
4756 }
4757
4758 if (key.index == DOT11_MAX_DEFAULT_KEYS)
4759 key.index = 0;
4760 } else {
4761 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
4762 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
4763 return -EINVAL;
4764 }
4765
4766
4767 if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) {
4768
4769 val = htod32(key.index);
4770 if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val))))
4771 return error;
4772 } else {
4773 key.len = dwrq->length;
4774
4775 if (dwrq->length > sizeof(key.data))
4776 return -EINVAL;
4777
4778 memcpy(key.data, extra, dwrq->length);
4779
4780 key.flags = WL_PRIMARY_KEY;
4781 switch (key.len) {
4782 case WEP1_KEY_SIZE:
4783 key.algo = CRYPTO_ALGO_WEP1;
4784 break;
4785 case WEP128_KEY_SIZE:
4786 key.algo = CRYPTO_ALGO_WEP128;
4787 break;
4788#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
4789 case TKIP_KEY_SIZE:
4790 key.algo = CRYPTO_ALGO_TKIP;
4791 break;
4792#endif
4793 case AES_KEY_SIZE:
4794 key.algo = CRYPTO_ALGO_AES_CCM;
4795 break;
4796 default:
4797 return -EINVAL;
4798 }
4799
4800
4801 swap_key_from_BE(&key);
4802 if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))
4803 return error;
4804 }
4805
4806
4807 val = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED;
4808
4809 if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec)))
4810 return error;
4811
4812 wsec &= ~(WEP_ENABLED);
4813 wsec |= val;
4814
4815 if ((error = dev_wlc_intvar_set(dev, "wsec", wsec)))
4816 return error;
4817
4818
4819 val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0;
4820 val = htod32(val);
4821 if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val))))
4822 return error;
4823
4824 return 0;
4825}
4826
4827static int
4828wl_iw_get_encode(
4829 struct net_device *dev,
4830 struct iw_request_info *info,
4831 struct iw_point *dwrq,
4832 char *extra
4833)
4834{
4835 wl_wsec_key_t key;
4836 int error, val, wsec, auth;
4837
4838 WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name));
4839
4840
4841 bzero(&key, sizeof(wl_wsec_key_t));
4842
4843 if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
4844
4845 for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
4846 val = key.index;
4847 if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
4848 return error;
4849 val = dtoh32(val);
4850 if (val)
4851 break;
4852 }
4853 } else
4854 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
4855
4856 if (key.index >= DOT11_MAX_DEFAULT_KEYS)
4857 key.index = 0;
4858
4859
4860
4861 if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) ||
4862 (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth))))
4863 return error;
4864
4865 swap_key_to_BE(&key);
4866
4867 wsec = dtoh32(wsec);
4868 auth = dtoh32(auth);
4869
4870 dwrq->length = MIN(DOT11_MAX_KEY_SIZE, key.len);
4871
4872
4873 dwrq->flags = key.index + 1;
4874 if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) {
4875
4876 dwrq->flags |= IW_ENCODE_DISABLED;
4877 }
4878 if (auth) {
4879
4880 dwrq->flags |= IW_ENCODE_RESTRICTED;
4881 }
4882
4883
4884 if (dwrq->length && extra)
4885 memcpy(extra, key.data, dwrq->length);
4886
4887 return 0;
4888}
4889
4890static int
4891wl_iw_set_power(
4892 struct net_device *dev,
4893 struct iw_request_info *info,
4894 struct iw_param *vwrq,
4895 char *extra
4896)
4897{
4898 int error, pm;
4899
4900 WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name));
4901
4902 pm = vwrq->disabled ? PM_OFF : PM_MAX;
4903
4904 pm = htod32(pm);
4905 if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm))))
4906 return error;
4907
4908 return 0;
4909}
4910
4911static int
4912wl_iw_get_power(
4913 struct net_device *dev,
4914 struct iw_request_info *info,
4915 struct iw_param *vwrq,
4916 char *extra
4917)
4918{
4919 int error, pm;
4920
4921 WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name));
4922
4923 if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))))
4924 return error;
4925
4926 pm = dtoh32(pm);
4927 vwrq->disabled = pm ? 0 : 1;
4928 vwrq->flags = IW_POWER_ALL_R;
4929
4930 return 0;
4931}
4932
4933#if WIRELESS_EXT > 17
4934static int
4935wl_iw_set_wpaie(
4936 struct net_device *dev,
4937 struct iw_request_info *info,
4938 struct iw_point *iwp,
4939 char *extra
4940)
4941{
4942 uchar buf[WLC_IOCTL_SMLEN] = {0};
4943 uchar *p = buf;
4944 int wapi_ie_size;
4945
4946 WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name));
4947
4948 CHECK_EXTRA_FOR_NULL(extra);
4949
4950 if (extra[0] == DOT11_MNG_WAPI_ID)
4951 {
4952 wapi_ie_size = iwp->length;
4953 memcpy(p, extra, iwp->length);
4954 dev_wlc_bufvar_set(dev, "wapiie", buf, wapi_ie_size);
4955 }
4956 else
4957 dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
4958
4959 return 0;
4960}
4961
4962static int
4963wl_iw_get_wpaie(
4964 struct net_device *dev,
4965 struct iw_request_info *info,
4966 struct iw_point *iwp,
4967 char *extra
4968)
4969{
4970 WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name));
4971 iwp->length = 64;
4972 dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
4973 return 0;
4974}
4975
4976static int
4977wl_iw_set_encodeext(
4978 struct net_device *dev,
4979 struct iw_request_info *info,
4980 struct iw_point *dwrq,
4981 char *extra
4982)
4983{
4984 wl_wsec_key_t key;
4985 int error;
4986 struct iw_encode_ext *iwe;
4987
4988 WL_WSEC(("%s: SIOCSIWENCODEEXT\n", dev->name));
4989
4990 CHECK_EXTRA_FOR_NULL(extra);
4991
4992 memset(&key, 0, sizeof(key));
4993 iwe = (struct iw_encode_ext *)extra;
4994
4995
4996 if (dwrq->flags & IW_ENCODE_DISABLED) {
4997
4998 }
4999
5000
5001 key.index = 0;
5002 if (dwrq->flags & IW_ENCODE_INDEX)
5003 key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
5004
5005 key.len = iwe->key_len;
5006
5007
5008 if (!ETHER_ISMULTI(iwe->addr.sa_data))
5009 bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN);
5010
5011
5012 if (key.len == 0) {
5013 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
5014 WL_WSEC(("Changing the the primary Key to %d\n", key.index));
5015
5016 key.index = htod32(key.index);
5017 error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
5018 &key.index, sizeof(key.index));
5019 if (error)
5020 return error;
5021 }
5022
5023 else {
5024 swap_key_from_BE(&key);
5025 dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
5026 }
5027 }
5028 else {
5029 if (iwe->key_len > sizeof(key.data))
5030 return -EINVAL;
5031
5032 WL_WSEC(("Setting the key index %d\n", key.index));
5033 if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
5034 WL_WSEC(("key is a Primary Key\n"));
5035 key.flags = WL_PRIMARY_KEY;
5036 }
5037
5038 bcopy((void *)iwe->key, key.data, iwe->key_len);
5039
5040 if (iwe->alg == IW_ENCODE_ALG_TKIP) {
5041 uint8 keybuf[8];
5042 bcopy(&key.data[24], keybuf, sizeof(keybuf));
5043 bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
5044 bcopy(keybuf, &key.data[16], sizeof(keybuf));
5045 }
5046
5047
5048 if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
5049 uchar *ivptr;
5050 ivptr = (uchar *)iwe->rx_seq;
5051 key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
5052 (ivptr[3] << 8) | ivptr[2];
5053 key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
5054 key.iv_initialized = TRUE;
5055 }
5056
5057 switch (iwe->alg) {
5058 case IW_ENCODE_ALG_NONE:
5059 key.algo = CRYPTO_ALGO_OFF;
5060 break;
5061 case IW_ENCODE_ALG_WEP:
5062 if (iwe->key_len == WEP1_KEY_SIZE)
5063 key.algo = CRYPTO_ALGO_WEP1;
5064 else
5065 key.algo = CRYPTO_ALGO_WEP128;
5066 break;
5067 case IW_ENCODE_ALG_TKIP:
5068 key.algo = CRYPTO_ALGO_TKIP;
5069 break;
5070 case IW_ENCODE_ALG_CCMP:
5071 key.algo = CRYPTO_ALGO_AES_CCM;
5072 break;
5073 case IW_ENCODE_ALG_SM4:
5074 key.algo = CRYPTO_ALGO_SMS4;
5075 if (iwe->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
5076 key.flags &= ~WL_PRIMARY_KEY;
5077 }
5078 break;
5079 default:
5080 break;
5081 }
5082 swap_key_from_BE(&key);
5083
5084 dhd_wait_pend8021x(dev);
5085
5086 error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
5087 if (error)
5088 return error;
5089 }
5090 return 0;
5091}
5092
5093#if WIRELESS_EXT > 17
5094#ifdef BCMWPA2
5095struct {
5096 pmkid_list_t pmkids;
5097 pmkid_t foo[MAXPMKID-1];
5098} pmkid_list;
5099
5100static int
5101wl_iw_set_pmksa(
5102 struct net_device *dev,
5103 struct iw_request_info *info,
5104 struct iw_param *vwrq,
5105 char *extra
5106)
5107{
5108 struct iw_pmksa *iwpmksa;
5109 uint i;
5110 int ret = 0;
5111 char eabuf[ETHER_ADDR_STR_LEN];
5112
5113 WL_WSEC(("%s: SIOCSIWPMKSA\n", dev->name));
5114 CHECK_EXTRA_FOR_NULL(extra);
5115
5116 iwpmksa = (struct iw_pmksa *)extra;
5117 bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
5118
5119 if (iwpmksa->cmd == IW_PMKSA_FLUSH) {
5120 WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"));
5121 bzero((char *)&pmkid_list, sizeof(pmkid_list));
5122 }
5123
5124 else if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
5125 {
5126 pmkid_list_t pmkid, *pmkidptr;
5127 uint j;
5128 pmkidptr = &pmkid;
5129
5130 bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN);
5131 bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN);
5132
5133 WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ",
5134 bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID,
5135 eabuf)));
5136 for (j = 0; j < WPA2_PMKID_LEN; j++)
5137 WL_WSEC(("%02x ", pmkidptr->pmkid[0].PMKID[j]));
5138 WL_WSEC(("\n"));
5139 }
5140
5141 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
5142 if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID,
5143 ETHER_ADDR_LEN))
5144 break;
5145
5146 if ((pmkid_list.pmkids.npmkid > 0) && (i < pmkid_list.pmkids.npmkid)) {
5147 bzero(&pmkid_list.pmkids.pmkid[i], sizeof(pmkid_t));
5148 for (; i < (pmkid_list.pmkids.npmkid - 1); i++) {
5149 bcopy(&pmkid_list.pmkids.pmkid[i+1].BSSID,
5150 &pmkid_list.pmkids.pmkid[i].BSSID,
5151 ETHER_ADDR_LEN);
5152 bcopy(&pmkid_list.pmkids.pmkid[i+1].PMKID,
5153 &pmkid_list.pmkids.pmkid[i].PMKID,
5154 WPA2_PMKID_LEN);
5155 }
5156 pmkid_list.pmkids.npmkid--;
5157 }
5158 else
5159 ret = -EINVAL;
5160 }
5161
5162 else if (iwpmksa->cmd == IW_PMKSA_ADD) {
5163 for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
5164 if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID,
5165 ETHER_ADDR_LEN))
5166 break;
5167 if (i < MAXPMKID) {
5168 bcopy(&iwpmksa->bssid.sa_data[0],
5169 &pmkid_list.pmkids.pmkid[i].BSSID,
5170 ETHER_ADDR_LEN);
5171 bcopy(&iwpmksa->pmkid[0], &pmkid_list.pmkids.pmkid[i].PMKID,
5172 WPA2_PMKID_LEN);
5173 if (i == pmkid_list.pmkids.npmkid)
5174 pmkid_list.pmkids.npmkid++;
5175 }
5176 else
5177 ret = -EINVAL;
5178
5179 {
5180 uint j;
5181 uint k;
5182 k = pmkid_list.pmkids.npmkid;
5183 WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ",
5184 bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[k].BSSID,
5185 eabuf)));
5186 for (j = 0; j < WPA2_PMKID_LEN; j++)
5187 WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[k].PMKID[j]));
5188 WL_WSEC(("\n"));
5189 }
5190 }
5191 WL_WSEC(("PRINTING pmkid LIST - No of elements %d, ret = %d\n", pmkid_list.pmkids.npmkid, ret));
5192 for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
5193 uint j;
5194 WL_WSEC(("PMKID[%d]: %s = ", i,
5195 bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[i].BSSID,
5196 eabuf)));
5197 for (j = 0; j < WPA2_PMKID_LEN; j++)
5198 WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]));
5199 WL_WSEC(("\n"));
5200 }
5201 WL_WSEC(("\n"));
5202
5203 if (!ret)
5204 ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list));
5205 return ret;
5206}
5207#endif
5208#endif
5209
5210static int
5211wl_iw_get_encodeext(
5212 struct net_device *dev,
5213 struct iw_request_info *info,
5214 struct iw_param *vwrq,
5215 char *extra
5216)
5217{
5218 WL_WSEC(("%s: SIOCGIWENCODEEXT\n", dev->name));
5219 return 0;
5220}
5221
5222static int
5223wl_iw_set_wpaauth(
5224 struct net_device *dev,
5225 struct iw_request_info *info,
5226 struct iw_param *vwrq,
5227 char *extra
5228)
5229{
5230 int error = 0;
5231 int paramid;
5232 int paramval;
5233 int val = 0;
5234 wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev);
5235
5236 WL_WSEC(("%s: SIOCSIWAUTH\n", dev->name));
5237
5238#if defined(SOFTAP)
5239 if (ap_cfg_running) {
5240 WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
5241 return 0;
5242 }
5243#endif
5244
5245 paramid = vwrq->flags & IW_AUTH_INDEX;
5246 paramval = vwrq->value;
5247
5248 WL_WSEC(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n",
5249 dev->name, paramid, paramval));
5250
5251 switch (paramid) {
5252 case IW_AUTH_WPA_VERSION:
5253
5254 if (paramval & IW_AUTH_WPA_VERSION_DISABLED)
5255 val = WPA_AUTH_DISABLED;
5256 else if (paramval & (IW_AUTH_WPA_VERSION_WPA))
5257 val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
5258#ifdef BCMWPA2
5259 else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
5260 val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
5261#endif
5262 else if (paramval & IW_AUTH_WAPI_VERSION_1)
5263 val = WPA_AUTH_WAPI;
5264 WL_WSEC(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val));
5265 if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
5266 return error;
5267 break;
5268 case IW_AUTH_CIPHER_PAIRWISE:
5269 case IW_AUTH_CIPHER_GROUP:
5270
5271
5272 if (paramval & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
5273 val = WEP_ENABLED;
5274 if (paramval & IW_AUTH_CIPHER_TKIP)
5275 val = TKIP_ENABLED;
5276 if (paramval & IW_AUTH_CIPHER_CCMP)
5277 val = AES_ENABLED;
5278 if (paramval & IW_AUTH_CIPHER_SMS4)
5279 val = SMS4_ENABLED;
5280
5281 if (paramid == IW_AUTH_CIPHER_PAIRWISE) {
5282 iw->pwsec = val;
5283 val |= iw->gwsec;
5284 }
5285 else {
5286 iw->gwsec = val;
5287 val |= iw->pwsec;
5288 }
5289
5290 if (iw->privacy_invoked && !val) {
5291 WL_WSEC(("%s: %s: 'Privacy invoked' TRUE but clearing wsec, assuming "
5292 "we're a WPS enrollee\n", dev->name, __FUNCTION__));
5293 if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) {
5294 WL_ERROR(("Failed to set iovar is_WPS_enrollee\n"));
5295 return error;
5296 }
5297 } else if (val) {
5298 if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) {
5299 WL_ERROR(("Failed to clear iovar is_WPS_enrollee\n"));
5300 return error;
5301 }
5302 }
5303
5304 if ((error = dev_wlc_intvar_set(dev, "wsec", val))) {
5305 WL_ERROR(("Failed to set 'wsec'iovar\n"));
5306 return error;
5307 }
5308
5309 break;
5310
5311 case IW_AUTH_KEY_MGMT:
5312 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) {
5313 WL_ERROR(("Failed to get 'wpa_auth'iovar\n"));
5314 return error;
5315 }
5316
5317 if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
5318 if (paramval & IW_AUTH_KEY_MGMT_PSK)
5319 val = WPA_AUTH_PSK;
5320 else
5321 val = WPA_AUTH_UNSPECIFIED;
5322 }
5323#ifdef BCMWPA2
5324 else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
5325 if (paramval & IW_AUTH_KEY_MGMT_PSK)
5326 val = WPA2_AUTH_PSK;
5327 else
5328 val = WPA2_AUTH_UNSPECIFIED;
5329 }
5330#endif
5331 if (paramval & (IW_AUTH_KEY_MGMT_WAPI_PSK | IW_AUTH_KEY_MGMT_WAPI_CERT))
5332 val = WPA_AUTH_WAPI;
5333 WL_WSEC(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
5334 if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) {
5335 WL_ERROR(("Failed to set 'wpa_auth'iovar\n"));
5336 return error;
5337 }
5338
5339 break;
5340 case IW_AUTH_TKIP_COUNTERMEASURES:
5341 if ((error = dev_wlc_bufvar_set(dev, "tkip_countermeasures", \
5342 (char *)&paramval, sizeof(paramval))))
5343 WL_WSEC(("%s: tkip_countermeasures failed %d\n", __FUNCTION__, error));
5344 break;
5345
5346 case IW_AUTH_80211_AUTH_ALG:
5347
5348 WL_WSEC(("Setting the D11auth %d\n", paramval));
5349 if (paramval == IW_AUTH_ALG_OPEN_SYSTEM)
5350 val = 0;
5351 else if (paramval == IW_AUTH_ALG_SHARED_KEY)
5352 val = 1;
5353 else if (paramval == (IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY))
5354 val = 2;
5355 else
5356 error = 1;
5357 if (!error && (error = dev_wlc_intvar_set(dev, "auth", val)))
5358 return error;
5359 break;
5360
5361 case IW_AUTH_WPA_ENABLED:
5362 if (paramval == 0) {
5363 iw->pwsec = 0;
5364 iw->gwsec = 0;
5365 if ((error = dev_wlc_intvar_get(dev, "wsec", &val))) {
5366 WL_ERROR(("Failed to get 'wsec'iovar\n"));
5367 return error;
5368 }
5369 if (val & (TKIP_ENABLED | AES_ENABLED)) {
5370 val &= ~(TKIP_ENABLED | AES_ENABLED);
5371 dev_wlc_intvar_set(dev, "wsec", val);
5372 }
5373 val = 0;
5374
5375 WL_INFORM(("%s: %d: setting wpa_auth to %d\n",
5376 __FUNCTION__, __LINE__, val));
5377 error = dev_wlc_intvar_set(dev, "wpa_auth", 0);
5378 if (error)
5379 WL_ERROR(("Failed to set 'wpa_auth'iovar\n"));
5380 return error;
5381 }
5382
5383
5384 break;
5385
5386 case IW_AUTH_DROP_UNENCRYPTED:
5387 error = dev_wlc_bufvar_set(dev, "wsec_restrict", \
5388 (char *)&paramval, sizeof(paramval));
5389 if (error)
5390 WL_ERROR(("%s: wsec_restrict %d\n", __FUNCTION__, error));
5391 break;
5392
5393 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
5394 error = dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", \
5395 (char *)&paramval, sizeof(paramval));
5396 if (error)
5397 WL_WSEC(("%s: rx_unencrypted_eapol %d\n", __FUNCTION__, error));
5398 break;
5399
5400#if WIRELESS_EXT > 17
5401 case IW_AUTH_ROAMING_CONTROL:
5402 WL_INFORM(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
5403
5404 break;
5405 case IW_AUTH_PRIVACY_INVOKED: {
5406 int wsec;
5407
5408 if (paramval == 0) {
5409 iw->privacy_invoked = FALSE;
5410 if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) {
5411 WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n"));
5412 return error;
5413 }
5414 } else {
5415 iw->privacy_invoked = TRUE;
5416 if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec)))
5417 return error;
5418
5419 if (!(IW_WSEC_ENABLED(wsec))) {
5420
5421 if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) {
5422 WL_WSEC(("Failed to set iovar is_WPS_enrollee\n"));
5423 return error;
5424 }
5425 } else {
5426 if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) {
5427 WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n"));
5428 return error;
5429 }
5430 }
5431 }
5432 break;
5433 }
5434#endif
5435 case IW_AUTH_WAPI_ENABLED:
5436 if ((error = dev_wlc_intvar_get(dev, "wsec", &val)))
5437 return error;
5438 if (paramval) {
5439 val |= SMS4_ENABLED;
5440 if ((error = dev_wlc_intvar_set(dev, "wsec", val))) {
5441 WL_ERROR(("%s: setting wsec to 0x%0x returned error %d\n",
5442 __FUNCTION__, val, error));
5443 return error;
5444 }
5445 if ((error = dev_wlc_intvar_set(dev, "wpa_auth", WPA_AUTH_WAPI))) {
5446 WL_ERROR(("%s: setting wpa_auth(WPA_AUTH_WAPI) returned %d\n",
5447 __FUNCTION__, error));
5448 return error;
5449 }
5450 }
5451
5452 break;
5453 default:
5454 break;
5455 }
5456 return 0;
5457}
5458#ifdef BCMWPA2
5459#define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
5460#else
5461#define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK))
5462#endif
5463
5464static int
5465wl_iw_get_wpaauth(
5466 struct net_device *dev,
5467 struct iw_request_info *info,
5468 struct iw_param *vwrq,
5469 char *extra
5470)
5471{
5472 int error;
5473 int paramid;
5474 int paramval = 0;
5475 int val;
5476 wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev);
5477
5478 WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name));
5479
5480 paramid = vwrq->flags & IW_AUTH_INDEX;
5481
5482 switch (paramid) {
5483 case IW_AUTH_WPA_VERSION:
5484
5485 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
5486 return error;
5487 if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED))
5488 paramval = IW_AUTH_WPA_VERSION_DISABLED;
5489 else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED))
5490 paramval = IW_AUTH_WPA_VERSION_WPA;
5491#ifdef BCMWPA2
5492 else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED))
5493 paramval = IW_AUTH_WPA_VERSION_WPA2;
5494#endif
5495 break;
5496 case IW_AUTH_CIPHER_PAIRWISE:
5497 case IW_AUTH_CIPHER_GROUP:
5498 if (paramid == IW_AUTH_CIPHER_PAIRWISE)
5499 val = iw->pwsec;
5500 else
5501 val = iw->gwsec;
5502
5503 paramval = 0;
5504 if (val) {
5505 if (val & WEP_ENABLED)
5506 paramval |= (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104);
5507 if (val & TKIP_ENABLED)
5508 paramval |= (IW_AUTH_CIPHER_TKIP);
5509 if (val & AES_ENABLED)
5510 paramval |= (IW_AUTH_CIPHER_CCMP);
5511 }
5512 else
5513 paramval = IW_AUTH_CIPHER_NONE;
5514 break;
5515 case IW_AUTH_KEY_MGMT:
5516
5517 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
5518 return error;
5519 if (VAL_PSK(val))
5520 paramval = IW_AUTH_KEY_MGMT_PSK;
5521 else
5522 paramval = IW_AUTH_KEY_MGMT_802_1X;
5523
5524 break;
5525 case IW_AUTH_TKIP_COUNTERMEASURES:
5526 error = dev_wlc_bufvar_get(dev, "tkip_countermeasures", \
5527 (char *)&paramval, sizeof(paramval));
5528 if (error)
5529 WL_ERROR(("%s get tkip_countermeasures %d\n", __FUNCTION__, error));
5530 break;
5531
5532 case IW_AUTH_DROP_UNENCRYPTED:
5533 error = dev_wlc_bufvar_get(dev, "wsec_restrict", \
5534 (char *)&paramval, sizeof(paramval));
5535 if (error)
5536 WL_ERROR(("%s get wsec_restrict %d\n", __FUNCTION__, error));
5537 break;
5538
5539 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
5540 error = dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", \
5541 (char *)&paramval, sizeof(paramval));
5542 if (error)
5543 WL_ERROR(("%s get rx_unencrypted_eapol %d\n", __FUNCTION__, error));
5544 break;
5545
5546 case IW_AUTH_80211_AUTH_ALG:
5547
5548 if ((error = dev_wlc_intvar_get(dev, "auth", &val)))
5549 return error;
5550 if (!val)
5551 paramval = IW_AUTH_ALG_OPEN_SYSTEM;
5552 else
5553 paramval = IW_AUTH_ALG_SHARED_KEY;
5554 break;
5555 case IW_AUTH_WPA_ENABLED:
5556 if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
5557 return error;
5558 if (val)
5559 paramval = TRUE;
5560 else
5561 paramval = FALSE;
5562 break;
5563#if WIRELESS_EXT > 17
5564 case IW_AUTH_ROAMING_CONTROL:
5565 WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
5566
5567 break;
5568 case IW_AUTH_PRIVACY_INVOKED:
5569 paramval = iw->privacy_invoked;
5570 break;
5571#endif
5572 }
5573 vwrq->value = paramval;
5574 return 0;
5575}
5576#endif
5577
5578
5579#ifdef SOFTAP
5580
5581static int ap_macmode = MACLIST_MODE_DISABLED;
5582static struct mflist ap_black_list;
5583static int
5584wl_iw_parse_wep(char *keystr, wl_wsec_key_t *key)
5585{
5586 char hex[] = "XX";
5587 unsigned char *data = key->data;
5588
5589 switch (strlen(keystr)) {
5590 case 5:
5591 case 13:
5592 case 16:
5593 key->len = strlen(keystr);
5594 memcpy(data, keystr, key->len + 1);
5595 break;
5596 case 12:
5597 case 28:
5598 case 34:
5599 case 66:
5600 if (!strnicmp(keystr, "0x", 2))
5601 keystr += 2;
5602 else
5603 return -1;
5604 case 10:
5605 case 26:
5606 case 32:
5607 case 64:
5608 key->len = strlen(keystr) / 2;
5609 while (*keystr) {
5610 strncpy(hex, keystr, 2);
5611 *data++ = (char) bcm_strtoul(hex, NULL, 16);
5612 keystr += 2;
5613 }
5614 break;
5615 default:
5616 return -1;
5617 }
5618
5619 switch (key->len) {
5620 case 5:
5621 key->algo = CRYPTO_ALGO_WEP1;
5622 break;
5623 case 13:
5624 key->algo = CRYPTO_ALGO_WEP128;
5625 break;
5626 case 16:
5627 key->algo = CRYPTO_ALGO_AES_CCM;
5628 break;
5629 case 32:
5630 key->algo = CRYPTO_ALGO_TKIP;
5631 break;
5632 default:
5633 return -1;
5634 }
5635
5636 key->flags |= WL_PRIMARY_KEY;
5637
5638 return 0;
5639}
5640
5641#ifdef EXT_WPA_CRYPTO
5642#define SHA1HashSize 20
5643extern void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
5644 int iterations, u8 *buf, size_t buflen);
5645
5646#else
5647
5648#define SHA1HashSize 20
5649int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
5650 int iterations, u8 *buf, size_t buflen)
5651{
5652 WL_ERROR(("WARNING: %s is not implemented !!!\n", __FUNCTION__));
5653 return -1;
5654}
5655
5656#endif
5657
5658
5659int dev_iw_write_cfg1_bss_var(struct net_device *dev, int val)
5660{
5661 struct {
5662 int cfg;
5663 int val;
5664 } bss_setbuf;
5665
5666 int bss_set_res;
5667 char smbuf[WLC_IOCTL_SMLEN];
5668 memset(smbuf, 0, sizeof(smbuf));
5669
5670 bss_setbuf.cfg = 1;
5671 bss_setbuf.val = val;
5672
5673 bss_set_res = dev_iw_iovar_setbuf(dev, "bss",
5674 &bss_setbuf, sizeof(bss_setbuf), smbuf, sizeof(smbuf));
5675 WL_TRACE(("%s: bss_set_result:%d set with %d\n", __FUNCTION__, bss_set_res, val));
5676
5677 return bss_set_res;
5678}
5679
5680
5681int dev_iw_read_cfg1_bss_var(struct net_device *dev, int *val)
5682{
5683 int bsscfg_idx = 1;
5684 int bss_set_res;
5685 char smbuf[WLC_IOCTL_SMLEN];
5686 memset(smbuf, 0, sizeof(smbuf));
5687
5688 bss_set_res = dev_iw_iovar_getbuf(dev, "bss", \
5689 &bsscfg_idx, sizeof(bsscfg_idx), smbuf, sizeof(smbuf));
5690 *val = *(int*)smbuf;
5691 *val = dtoh32(*val);
5692 WL_TRACE(("%s: status=%d bss_get_result=%d\n", __FUNCTION__, bss_set_res, *val));
5693 return bss_set_res;
5694}
5695
5696
5697#ifndef AP_ONLY
5698static int wl_bssiovar_mkbuf(
5699 const char *iovar,
5700 int bssidx,
5701 void *param,
5702 int paramlen,
5703 void *bufptr,
5704 int buflen,
5705 int *perr)
5706{
5707 const char *prefix = "bsscfg:";
5708 int8 *p;
5709 uint prefixlen;
5710 uint namelen;
5711 uint iolen;
5712
5713 prefixlen = strlen(prefix);
5714 namelen = strlen(iovar) + 1;
5715 iolen = prefixlen + namelen + sizeof(int) + paramlen;
5716
5717 if (buflen < 0 || iolen > (uint)buflen) {
5718 *perr = BCME_BUFTOOSHORT;
5719 return 0;
5720 }
5721
5722 p = (int8 *)bufptr;
5723
5724 memcpy(p, prefix, prefixlen);
5725 p += prefixlen;
5726
5727 memcpy(p, iovar, namelen);
5728 p += namelen;
5729
5730 bssidx = htod32(bssidx);
5731 memcpy(p, &bssidx, sizeof(int32));
5732 p += sizeof(int32);
5733
5734 if (paramlen)
5735 memcpy(p, param, paramlen);
5736
5737 *perr = 0;
5738 return iolen;
5739}
5740#endif
5741
5742
5743int get_user_params(char *user_params, struct iw_point *dwrq)
5744{
5745 int ret = 0;
5746
5747 if (copy_from_user(user_params, dwrq->pointer, dwrq->length)) {
5748 WL_ERROR(("\n%s: no user params: uptr:%p, ulen:%d\n",
5749 __FUNCTION__, dwrq->pointer, dwrq->length));
5750 return -EFAULT;
5751 }
5752
5753 WL_TRACE(("\n%s: iwpriv user params:%s\n", __FUNCTION__, user_params));
5754
5755 return ret;
5756}
5757
5758
5759#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
5760
5761#if defined(CSCAN)
5762
5763static int
5764wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan)
5765{
5766 int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
5767 int err = 0;
5768 char *p;
5769 int i;
5770 iscan_info_t *iscan = g_iscan;
5771
5772 WL_SCAN(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan));
5773
5774 if ((!dev) && (!g_iscan) && (!iscan->iscan_ex_params_p)) {
5775 WL_ERROR(("%s error exit\n", __FUNCTION__));
5776 err = -1;
5777 goto exit;
5778 }
5779
5780#ifdef PNO_SUPPORT
5781 if (dhd_dev_get_pno_status(dev)) {
5782 WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__));
5783 }
5784#endif
5785
5786 params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
5787
5788 if (nssid > 0) {
5789 i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16);
5790 i = ROUNDUP(i, sizeof(uint32));
5791 if (i + nssid * sizeof(wlc_ssid_t) > params_size) {
5792 printf("additional ssids exceed params_size\n");
5793 err = -1;
5794 goto exit;
5795 }
5796
5797 p = ((char*)&iscan->iscan_ex_params_p->params) + i;
5798 memcpy(p, ssids_local, nssid * sizeof(wlc_ssid_t));
5799 p += nssid * sizeof(wlc_ssid_t);
5800 } else {
5801 p = (char*)iscan->iscan_ex_params_p->params.channel_list + nchan * sizeof(uint16);
5802 }
5803
5804 iscan->iscan_ex_params_p->params.channel_num = \
5805 htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) | \
5806 (nchan & WL_SCAN_PARAMS_COUNT_MASK));
5807
5808 nssid = \
5809 (uint)((iscan->iscan_ex_params_p->params.channel_num >> WL_SCAN_PARAMS_NSSID_SHIFT) & \
5810 WL_SCAN_PARAMS_COUNT_MASK);
5811
5812 params_size = (int) (p - (char*)iscan->iscan_ex_params_p + nssid * sizeof(wlc_ssid_t));
5813 iscan->iscan_ex_param_size = params_size;
5814
5815 iscan->list_cur = iscan->list_hdr;
5816 iscan->iscan_state = ISCAN_STATE_SCANING;
5817 wl_iw_set_event_mask(dev);
5818 mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
5819
5820 iscan->timer_on = 1;
5821
5822#ifdef SCAN_DUMP
5823 {
5824 int i;
5825 WL_SCAN(("\n### List of SSIDs to scan ###\n"));
5826 for (i = 0; i < nssid; i++) {
5827 if (!ssids_local[i].SSID_len)
5828 WL_SCAN(("%d: Broadcast scan\n", i));
5829 else
5830 WL_SCAN(("%d: scan for %s size =%d\n", i, \
5831 ssids_local[i].SSID, ssids_local[i].SSID_len));
5832 }
5833 WL_SCAN(("### List of channels to scan ###\n"));
5834 for (i = 0; i < nchan; i++)
5835 {
5836 WL_SCAN(("%d ", iscan->iscan_ex_params_p->params.channel_list[i]));
5837 }
5838 WL_SCAN(("\nnprobes=%d\n", iscan->iscan_ex_params_p->params.nprobes));
5839 WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
5840 WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
5841 WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
5842 WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
5843 WL_SCAN(("\n###################\n"));
5844 }
5845#endif
5846
5847 if (params_size > WLC_IOCTL_MEDLEN) {
5848 WL_ERROR(("Set ISCAN for %s due to params_size=%d \n", \
5849 __FUNCTION__, params_size));
5850 err = -1;
5851 }
5852
5853 if ((err = dev_iw_iovar_setbuf(dev, "iscan", iscan->iscan_ex_params_p, \
5854 iscan->iscan_ex_param_size, \
5855 iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
5856 WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
5857 err = -1;
5858 }
5859
5860exit:
5861
5862 return err;
5863}
5864
5865
5866static int iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info, \
5867 union iwreq_data *wrqu, char *ext)
5868{
5869 int res = 0;
5870 char *extra = NULL;
5871 iscan_info_t *iscan = g_iscan;
5872 wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
5873 int nssid = 0;
5874 int nchan = 0;
5875
5876 WL_TRACE(("\%s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
5877 __FUNCTION__, info->cmd, info->flags,
5878 wrqu->data.pointer, wrqu->data.length));
5879
5880 if (g_onoff == G_WLAN_SET_OFF) {
5881 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
5882 return -1;
5883 }
5884
5885#ifdef PNO_SET_DEBUG
5886 wl_iw_set_pno_set(dev, info, wrqu, extra);
5887 return 0;
5888#endif
5889
5890 if (wrqu->data.length != 0) {
5891
5892 char *str_ptr;
5893
5894 if (!iscan->iscan_ex_params_p) {
5895 return -EFAULT;
5896 }
5897
5898 if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
5899 return -ENOMEM;
5900
5901 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
5902 kfree(extra);
5903 return -EFAULT;
5904 }
5905
5906 extra[wrqu->data.length] = 0;
5907 WL_ERROR(("Got str param in iw_point:\n %s\n", extra));
5908
5909 str_ptr = extra;
5910
5911 if (strncmp(str_ptr, GET_SSID, strlen(GET_SSID))) {
5912 WL_ERROR(("%s Error: extracting SSID='' string\n", __FUNCTION__));
5913 goto exit_proc;
5914 }
5915 str_ptr += strlen(GET_SSID);
5916 nssid = wl_iw_parse_ssid_list(&str_ptr, ssids_local, nssid, \
5917 WL_SCAN_PARAMS_SSID_MAX);
5918 if (nssid == -1) {
5919 WL_ERROR(("%s wrong ssid list", __FUNCTION__));
5920 return -1;
5921 }
5922
5923 if (iscan->iscan_ex_param_size > WLC_IOCTL_MAXLEN) {
5924 WL_ERROR(("%s wrong ex_param_size %d", \
5925 __FUNCTION__, iscan->iscan_ex_param_size));
5926 return -1;
5927 }
5928 memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
5929
5930
5931 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
5932 iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
5933 iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
5934 iscan->iscan_ex_params_p->scan_duration = htod16(0);
5935
5936
5937 if ((nchan = wl_iw_parse_channel_list(&str_ptr, \
5938 &iscan->iscan_ex_params_p->params.channel_list[0], \
5939 WL_NUMCHANNELS)) == -1) {
5940 WL_ERROR(("%s missing channel list\n", __FUNCTION__));
5941 return -1;
5942 }
5943
5944
5945 get_parmeter_from_string(&str_ptr, \
5946 GET_NPROBE, PTYPE_INTDEC, \
5947 &iscan->iscan_ex_params_p->params.nprobes, 2);
5948
5949 get_parmeter_from_string(&str_ptr, GET_ACTIVE_ASSOC_DWELL, PTYPE_INTDEC, \
5950 &iscan->iscan_ex_params_p->params.active_time, 4);
5951
5952 get_parmeter_from_string(&str_ptr, GET_PASSIVE_ASSOC_DWELL, PTYPE_INTDEC, \
5953 &iscan->iscan_ex_params_p->params.passive_time, 4);
5954
5955 get_parmeter_from_string(&str_ptr, GET_HOME_DWELL, PTYPE_INTDEC, \
5956 &iscan->iscan_ex_params_p->params.home_time, 4);
5957
5958 get_parmeter_from_string(&str_ptr, GET_SCAN_TYPE, PTYPE_INTDEC, \
5959 &iscan->iscan_ex_params_p->params.scan_type, 1);
5960
5961 res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
5962
5963 } else {
5964 WL_ERROR(("IWPRIV argument len = 0 \n"));
5965 return -1;
5966 }
5967
5968exit_proc:
5969
5970 kfree(extra);
5971
5972 return res;
5973}
5974
5975
5976static int
5977wl_iw_set_cscan(
5978 struct net_device *dev,
5979 struct iw_request_info *info,
5980 union iwreq_data *wrqu,
5981 char *extra
5982)
5983{
5984 int res = -1;
5985 iscan_info_t *iscan = g_iscan;
5986 wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
5987 int nssid = 0;
5988 int nchan = 0;
5989 cscan_tlv_t *cscan_tlv_temp;
5990 char type;
5991 char *str_ptr;
5992 int tlv_size_left;
5993#ifdef TLV_DEBUG
5994 int i;
5995 char tlv_in_example[] = { 'C', 'S', 'C', 'A', 'N', ' ', \
5996 0x53, 0x01, 0x00, 0x00,
5997 'S',
5998 0x00,
5999 'S',
6000 0x04,
6001 'B', 'R', 'C', 'M',
6002 'C',
6003 0x06,
6004 'P',
6005 0x94,
6006 0x11,
6007 'T',
6008 0x01
6009 };
6010#endif
6011
6012 WL_TRACE(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
6013 __FUNCTION__, info->cmd, info->flags,
6014 wrqu->data.pointer, wrqu->data.length));
6015
6016 net_os_wake_lock(dev);
6017
6018 if (g_onoff == G_WLAN_SET_OFF) {
6019 WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
6020 goto exit_proc;
6021 }
6022
6023
6024 if (wrqu->data.length < (strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))) {
6025 WL_ERROR(("%s aggument=%d less %d\n", __FUNCTION__, \
6026 wrqu->data.length, strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t)));
6027 goto exit_proc;
6028 }
6029
6030#ifdef TLV_DEBUG
6031 memcpy(extra, tlv_in_example, sizeof(tlv_in_example));
6032 wrqu->data.length = sizeof(tlv_in_example);
6033 for (i = 0; i < wrqu->data.length; i++)
6034 printf("%02X ", extra[i]);
6035 printf("\n");
6036#endif
6037
6038 str_ptr = extra;
6039 str_ptr += strlen(CSCAN_COMMAND);
6040 tlv_size_left = wrqu->data.length - strlen(CSCAN_COMMAND);
6041
6042 cscan_tlv_temp = (cscan_tlv_t *)str_ptr;
6043 memset(ssids_local, 0, sizeof(ssids_local));
6044
6045 if ((cscan_tlv_temp->prefix == CSCAN_TLV_PREFIX) && \
6046 (cscan_tlv_temp->version == CSCAN_TLV_VERSION) && \
6047 (cscan_tlv_temp->subver == CSCAN_TLV_SUBVERSION))
6048 {
6049 str_ptr += sizeof(cscan_tlv_t);
6050 tlv_size_left -= sizeof(cscan_tlv_t);
6051
6052
6053 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \
6054 WL_SCAN_PARAMS_SSID_MAX, &tlv_size_left)) <= 0) {
6055 WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
6056 goto exit_proc;
6057 }
6058 else {
6059
6060 memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
6061
6062
6063 wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
6064 iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
6065 iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
6066 iscan->iscan_ex_params_p->scan_duration = htod16(0);
6067
6068
6069 while (tlv_size_left > 0)
6070 {
6071 type = str_ptr[0];
6072 switch (type) {
6073 case CSCAN_TLV_TYPE_CHANNEL_IE:
6074
6075 if ((nchan = wl_iw_parse_channel_list_tlv(&str_ptr, \
6076 &iscan->iscan_ex_params_p->params.channel_list[0], \
6077 WL_NUMCHANNELS, &tlv_size_left)) == -1) {
6078 WL_ERROR(("%s missing channel list\n", \
6079 __FUNCTION__));
6080 goto exit_proc;
6081 }
6082 break;
6083 case CSCAN_TLV_TYPE_NPROBE_IE:
6084 if ((res = wl_iw_parse_data_tlv(&str_ptr, \
6085 &iscan->iscan_ex_params_p->params.nprobes, \
6086 sizeof(iscan->iscan_ex_params_p->params.nprobes), \
6087 type, sizeof(char), &tlv_size_left)) == -1) {
6088 WL_ERROR(("%s return %d\n", \
6089 __FUNCTION__, res));
6090 goto exit_proc;
6091 }
6092 break;
6093 case CSCAN_TLV_TYPE_ACTIVE_IE:
6094 if ((res = wl_iw_parse_data_tlv(&str_ptr, \
6095 &iscan->iscan_ex_params_p->params.active_time, \
6096 sizeof(iscan->iscan_ex_params_p->params.active_time), \
6097 type, sizeof(short), &tlv_size_left)) == -1) {
6098 WL_ERROR(("%s return %d\n", \
6099 __FUNCTION__, res));
6100 goto exit_proc;
6101 }
6102 break;
6103 case CSCAN_TLV_TYPE_PASSIVE_IE:
6104 if ((res = wl_iw_parse_data_tlv(&str_ptr, \
6105 &iscan->iscan_ex_params_p->params.passive_time, \
6106 sizeof(iscan->iscan_ex_params_p->params.passive_time), \
6107 type, sizeof(short), &tlv_size_left)) == -1) {
6108 WL_ERROR(("%s return %d\n", \
6109 __FUNCTION__, res));
6110 goto exit_proc;
6111 }
6112 break;
6113 case CSCAN_TLV_TYPE_HOME_IE:
6114 if ((res = wl_iw_parse_data_tlv(&str_ptr, \
6115 &iscan->iscan_ex_params_p->params.home_time, \
6116 sizeof(iscan->iscan_ex_params_p->params.home_time), \
6117 type, sizeof(short), &tlv_size_left)) == -1) {
6118 WL_ERROR(("%s return %d\n", \
6119 __FUNCTION__, res));
6120 goto exit_proc;
6121 }
6122 break;
6123 case CSCAN_TLV_TYPE_STYPE_IE:
6124 if ((res = wl_iw_parse_data_tlv(&str_ptr, \
6125 &iscan->iscan_ex_params_p->params.scan_type, \
6126 sizeof(iscan->iscan_ex_params_p->params.scan_type), \
6127 type, sizeof(char), &tlv_size_left)) == -1) {
6128 WL_ERROR(("%s return %d\n", \
6129 __FUNCTION__, res));
6130 goto exit_proc;
6131 }
6132 break;
6133
6134 default :
6135 WL_ERROR(("%s get unkwown type %X\n", \
6136 __FUNCTION__, type));
6137 goto exit_proc;
6138 break;
6139 }
6140 }
6141 }
6142 }
6143 else {
6144 WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
6145 goto exit_proc;
6146 }
6147
6148#if defined(CONFIG_FIRST_SCAN)
6149 if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
6150 if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) {
6151
6152 WL_ERROR(("%s Clean up First scan flag which is %d\n", \
6153 __FUNCTION__, g_first_broadcast_scan));
6154 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
6155 }
6156 else {
6157 WL_ERROR(("%s Ignoring CSCAN : First Scan is not done yet %d\n", \
6158 __FUNCTION__, g_first_counter_scans));
6159 res = -EBUSY;
6160 goto exit_proc;
6161 }
6162 }
6163#endif
6164
6165 res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
6166
6167exit_proc:
6168 net_os_wake_unlock(dev);
6169 return res;
6170}
6171
6172#endif
6173
6174#ifdef SOFTAP
6175#ifndef AP_ONLY
6176
6177static int thr_wait_for_2nd_eth_dev(void *data)
6178{
6179 struct net_device *dev = (struct net_device *)data;
6180 wl_iw_t *iw;
6181 int ret = 0;
6182 unsigned long flags;
6183
6184 net_os_wake_lock(dev);
6185
6186 DAEMONIZE("wl0_eth_wthread");
6187
6188 WL_TRACE(("\n>%s thread started:, PID:%x\n", __FUNCTION__, current->pid));
6189 iw = *(wl_iw_t **)netdev_priv(dev);
6190 if (!iw) {
6191 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
6192 ret = -1;
6193 goto fail;
6194 }
6195
6196#ifndef BCMSDIOH_STD
6197 if (down_timeout(&ap_eth_sema, msecs_to_jiffies(5000)) != 0) {
6198 WL_ERROR(("\n%s: sap_eth_sema timeout \n", __FUNCTION__));
6199 ret = -1;
6200 goto fail;
6201 }
6202#endif
6203
6204 flags = dhd_os_spin_lock(iw->pub);
6205 if (!ap_net_dev) {
6206 WL_ERROR((" ap_net_dev is null !!!"));
6207 ret = -1;
6208 dhd_os_spin_unlock(iw->pub, flags);
6209 goto fail;
6210 }
6211
6212 WL_TRACE(("\n>%s: Thread:'softap ethdev IF:%s is detected !!!'\n\n",
6213 __FUNCTION__, ap_net_dev->name));
6214
6215 ap_cfg_running = TRUE;
6216
6217 dhd_os_spin_unlock(iw->pub, flags);
6218
6219 bcm_mdelay(500);
6220
6221 wl_iw_send_priv_event(priv_dev, "AP_SET_CFG_OK");
6222
6223fail:
6224 WL_TRACE(("\n>%s, thread completed\n", __FUNCTION__));
6225
6226 net_os_wake_unlock(dev);
6227
6228 complete_and_exit(&ap_cfg_exited, 0);
6229 return ret;
6230}
6231#endif
6232#ifndef AP_ONLY
6233static int last_auto_channel = 6;
6234#endif
6235static int get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap)
6236{
6237 int chosen = 0;
6238 wl_uint32_list_t request;
6239 int rescan = 0;
6240 int retry = 0;
6241 int updown = 0;
6242 int ret = 0;
6243 wlc_ssid_t null_ssid;
6244 int res = 0;
6245#ifndef AP_ONLY
6246 int iolen = 0;
6247 int mkvar_err = 0;
6248 int bsscfg_index = 1;
6249 char buf[WLC_IOCTL_SMLEN];
6250#endif
6251 WL_SOFTAP(("Enter %s\n", __FUNCTION__));
6252
6253#ifndef AP_ONLY
6254 if (ap_cfg_running) {
6255 ap->channel = last_auto_channel;
6256 return res;
6257 }
6258#endif
6259 memset(&null_ssid, 0, sizeof(wlc_ssid_t));
6260 res |= dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown));
6261#ifdef AP_ONLY
6262 res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid));
6263#else
6264 iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&null_ssid), \
6265 null_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err);
6266 ASSERT(iolen);
6267 res |= dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen);
6268#endif
6269 auto_channel_retry:
6270 request.count = htod32(0);
6271 ret = dev_wlc_ioctl(dev, WLC_START_CHANNEL_SEL, &request, sizeof(request));
6272 if (ret < 0) {
6273 WL_ERROR(("can't start auto channel scan\n"));
6274 goto fail;
6275 }
6276
6277 get_channel_retry:
6278 bcm_mdelay(500);
6279
6280 ret = dev_wlc_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
6281 if (ret < 0 || dtoh32(chosen) == 0) {
6282 if (retry++ < 3)
6283 goto get_channel_retry;
6284 else {
6285 WL_ERROR(("can't get auto channel sel, err = %d, \
6286 chosen = %d\n", ret, chosen));
6287 goto fail;
6288 }
6289 }
6290 if ((chosen == 1) && (!rescan++))
6291 goto auto_channel_retry;
6292 WL_SOFTAP(("Set auto channel = %d\n", chosen));
6293 ap->channel = chosen;
6294 if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown))) < 0) {
6295 WL_ERROR(("%s fail to set up err =%d\n", __FUNCTION__, res));
6296 goto fail;
6297 }
6298#ifndef AP_ONLY
6299 if (!res)
6300 last_auto_channel = ap->channel;
6301#endif
6302
6303fail :
6304 return res;
6305}
6306
6307
6308static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap)
6309{
6310 int updown = 0;
6311 int channel = 0;
6312
6313 wlc_ssid_t ap_ssid;
6314 int max_assoc = 8;
6315
6316 int res = 0;
6317 int apsta_var = 0;
6318#ifndef AP_ONLY
6319 int mpc = 0;
6320 int iolen = 0;
6321 int mkvar_err = 0;
6322 int bsscfg_index = 1;
6323 char buf[WLC_IOCTL_SMLEN];
6324#endif
6325
6326 if (!dev) {
6327 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
6328 return -1;
6329 }
6330
6331 net_os_wake_lock(dev);
6332
6333 WL_SOFTAP(("wl_iw: set ap profile:\n"));
6334 WL_SOFTAP((" ssid = '%s'\n", ap->ssid));
6335 WL_SOFTAP((" security = '%s'\n", ap->sec));
6336 if (ap->key[0] != '\0')
6337 WL_SOFTAP((" key = '%s'\n", ap->key));
6338 WL_SOFTAP((" channel = %d\n", ap->channel));
6339 WL_SOFTAP((" max scb = %d\n", ap->max_scb));
6340
6341#ifdef AP_ONLY
6342 if (ap_cfg_running) {
6343 wl_iw_softap_deassoc_stations(dev, NULL);
6344 ap_cfg_running = FALSE;
6345 }
6346#endif
6347
6348 if (ap_cfg_running == FALSE) {
6349
6350#ifndef AP_ONLY
6351 sema_init(&ap_eth_sema, 0);
6352
6353 mpc = 0;
6354 if ((res = dev_wlc_intvar_set(dev, "mpc", mpc))) {
6355 WL_ERROR(("%s fail to set mpc\n", __FUNCTION__));
6356 goto fail;
6357 }
6358#endif
6359
6360 updown = 0;
6361 if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown)))) {
6362 WL_ERROR(("%s fail to set updown\n", __FUNCTION__));
6363 goto fail;
6364 }
6365
6366#ifdef AP_ONLY
6367 apsta_var = 0;
6368 if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) {
6369 WL_ERROR(("%s fail to set apsta_var 0\n", __FUNCTION__));
6370 goto fail;
6371 }
6372 apsta_var = 1;
6373 if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) {
6374 WL_ERROR(("%s fail to set apsta_var 1\n", __FUNCTION__));
6375 goto fail;
6376 }
6377 res = dev_wlc_ioctl(dev, WLC_GET_AP, &apsta_var, sizeof(apsta_var));
6378#else
6379 apsta_var = 1;
6380 iolen = wl_bssiovar_mkbuf("apsta",
6381 bsscfg_index, &apsta_var, sizeof(apsta_var)+4,
6382 buf, sizeof(buf), &mkvar_err);
6383
6384 if (iolen <= 0)
6385 goto fail;
6386
6387 if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) < 0) {
6388 WL_ERROR(("%s fail to set apsta \n", __FUNCTION__));
6389 goto fail;
6390 }
6391 WL_TRACE(("\n>in %s: apsta set result: %d \n", __FUNCTION__, res));
6392#endif
6393
6394 updown = 1;
6395 if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown))) < 0) {
6396 WL_ERROR(("%s fail to set apsta \n", __FUNCTION__));
6397 goto fail;
6398 }
6399
6400 } else {
6401
6402 if (!ap_net_dev) {
6403 WL_ERROR(("%s: ap_net_dev is null\n", __FUNCTION__));
6404 goto fail;
6405 }
6406
6407 res = wl_iw_softap_deassoc_stations(ap_net_dev, NULL);
6408
6409
6410 if ((res = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) {
6411 WL_ERROR(("%s fail to set bss down\n", __FUNCTION__));
6412 goto fail;
6413 }
6414 }
6415
6416 if (strlen(ap->country_code)) {
6417 WL_ERROR(("%s: Igonored: Country MUST be specified \
6418 COUNTRY command with \n", __FUNCTION__));
6419 } else {
6420 WL_SOFTAP(("%s: Country code is not specified,"
6421 " will use Radio's default\n",
6422 __FUNCTION__));
6423 }
6424
6425 iolen = wl_bssiovar_mkbuf("closednet",
6426 bsscfg_index, &ap->closednet, sizeof(ap->closednet)+4,
6427 buf, sizeof(buf), &mkvar_err);
6428 ASSERT(iolen);
6429 if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) < 0) {
6430 WL_ERROR(("%s failed to set 'closednet'for apsta \n", __FUNCTION__));
6431 goto fail;
6432 }
6433
6434
6435 if ((ap->channel == 0) && (get_softap_auto_channel(dev, ap) < 0)) {
6436 ap->channel = 1;
6437 WL_ERROR(("%s auto channel failed, pick up channel=%d\n", \
6438 __FUNCTION__, ap->channel));
6439 }
6440
6441 channel = ap->channel;
6442 if ((res = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel)))) {
6443 WL_ERROR(("%s fail to set channel\n", __FUNCTION__));
6444 goto fail;
6445 }
6446
6447 if (ap_cfg_running == FALSE) {
6448 updown = 0;
6449 if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)))) {
6450 WL_ERROR(("%s fail to set up\n", __FUNCTION__));
6451 goto fail;
6452 }
6453 }
6454
6455 max_assoc = ap->max_scb;
6456 if ((res = dev_wlc_intvar_set(dev, "maxassoc", max_assoc))) {
6457 WL_ERROR(("%s fail to set maxassoc\n", __FUNCTION__));
6458 goto fail;
6459 }
6460
6461 ap_ssid.SSID_len = strlen(ap->ssid);
6462 strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len);
6463
6464#ifdef AP_ONLY
6465 if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) {
6466 WL_ERROR(("ERROR:%d in:%s, wl_iw_set_ap_security is skipped\n", \
6467 res, __FUNCTION__));
6468 goto fail;
6469 }
6470 wl_iw_send_priv_event(dev, "ASCII_CMD=AP_BSS_START");
6471 ap_cfg_running = TRUE;
6472#else
6473 iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&ap_ssid),
6474 ap_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err);
6475 ASSERT(iolen);
6476 if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) != 0) {
6477 WL_ERROR(("ERROR:%d in:%s, Security & BSS reconfiguration is skipped\n", \
6478 res, __FUNCTION__));
6479 goto fail;
6480 }
6481 if (ap_cfg_running == FALSE) {
6482 init_completion(&ap_cfg_exited);
6483 ap_cfg_pid = kernel_thread(thr_wait_for_2nd_eth_dev, dev, 0);
6484 } else {
6485 ap_cfg_pid = -1;
6486 if (ap_net_dev == NULL) {
6487 WL_ERROR(("%s ERROR: ap_net_dev is NULL !!!\n", __FUNCTION__));
6488 goto fail;
6489 }
6490
6491 WL_ERROR(("%s: %s Configure security & restart AP bss \n", \
6492 __FUNCTION__, ap_net_dev->name));
6493
6494 if ((res = wl_iw_set_ap_security(ap_net_dev, &my_ap)) < 0) {
6495 WL_ERROR(("%s fail to set security : %d\n", __FUNCTION__, res));
6496 goto fail;
6497 }
6498
6499 if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0) {
6500 WL_ERROR(("%s fail to set bss up\n", __FUNCTION__));
6501 goto fail;
6502 }
6503 }
6504#endif
6505fail:
6506 WL_SOFTAP(("%s exit with %d\n", __FUNCTION__, res));
6507
6508 net_os_wake_unlock(dev);
6509
6510 return res;
6511}
6512
6513
6514static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap)
6515{
6516 int wsec = 0;
6517 int wpa_auth = 0;
6518 int res = 0;
6519 int i;
6520 char *ptr;
6521#ifdef AP_ONLY
6522 int mpc = 0;
6523 wlc_ssid_t ap_ssid;
6524#endif
6525 wl_wsec_key_t key;
6526
6527 WL_SOFTAP(("\nsetting SOFTAP security mode:\n"));
6528 WL_SOFTAP(("wl_iw: set ap profile:\n"));
6529 WL_SOFTAP((" ssid = '%s'\n", ap->ssid));
6530 WL_SOFTAP((" security = '%s'\n", ap->sec));
6531 if (ap->key[0] != '\0') {
6532 WL_SOFTAP((" key = '%s'\n", ap->key));
6533 }
6534 WL_SOFTAP((" channel = %d\n", ap->channel));
6535 WL_SOFTAP((" max scb = %d\n", ap->max_scb));
6536
6537 if (strnicmp(ap->sec, "open", strlen("open")) == 0) {
6538 wsec = 0;
6539 res = dev_wlc_intvar_set(dev, "wsec", wsec);
6540 wpa_auth = WPA_AUTH_DISABLED;
6541 res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
6542
6543 WL_SOFTAP(("=====================\n"));
6544 WL_SOFTAP((" wsec & wpa_auth set 'OPEN', result:&d %d\n", res));
6545 WL_SOFTAP(("=====================\n"));
6546
6547 } else if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) {
6548
6549 memset(&key, 0, sizeof(key));
6550
6551 wsec = WEP_ENABLED;
6552 res = dev_wlc_intvar_set(dev, "wsec", wsec);
6553
6554 key.index = 0;
6555 if (wl_iw_parse_wep(ap->key, &key)) {
6556 WL_SOFTAP(("wep key parse err!\n"));
6557 return -1;
6558 }
6559
6560 key.index = htod32(key.index);
6561 key.len = htod32(key.len);
6562 key.algo = htod32(key.algo);
6563 key.flags = htod32(key.flags);
6564
6565 res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
6566
6567 wpa_auth = WPA_AUTH_DISABLED;
6568 res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
6569
6570 WL_SOFTAP(("=====================\n"));
6571 WL_SOFTAP((" wsec & auth set 'WEP', result:&d %d\n", res));
6572 WL_SOFTAP(("=====================\n"));
6573
6574 } else if (strnicmp(ap->sec, "wpa2-psk", strlen("wpa2-psk")) == 0) {
6575 wsec_pmk_t psk;
6576 size_t key_len;
6577
6578 wsec = AES_ENABLED;
6579 dev_wlc_intvar_set(dev, "wsec", wsec);
6580
6581 key_len = strlen(ap->key);
6582 if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) {
6583 WL_SOFTAP(("passphrase must be between %d and %d characters long\n",
6584 WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN));
6585 return -1;
6586 }
6587
6588 if (key_len < WSEC_MAX_PSK_LEN) {
6589 unsigned char output[2*SHA1HashSize];
6590 char key_str_buf[WSEC_MAX_PSK_LEN+1];
6591
6592 memset(output, 0, sizeof(output));
6593 pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32);
6594
6595 ptr = key_str_buf;
6596 for (i = 0; i < (WSEC_MAX_PSK_LEN/8); i++) {
6597 sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4], \
6598 (uint)output[i*4+1], (uint)output[i*4+2], \
6599 (uint)output[i*4+3]);
6600 ptr += 8;
6601 }
6602 WL_SOFTAP(("%s: passphase = %s\n", __FUNCTION__, key_str_buf));
6603
6604 psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN);
6605 memcpy(psk.key, key_str_buf, psk.key_len);
6606 } else {
6607 psk.key_len = htod16((ushort) key_len);
6608 memcpy(psk.key, ap->key, key_len);
6609 }
6610 psk.flags = htod16(WSEC_PASSPHRASE);
6611 dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk));
6612
6613 wpa_auth = WPA2_AUTH_PSK;
6614 dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
6615
6616 } else if (strnicmp(ap->sec, "wpa-psk", strlen("wpa-psk")) == 0) {
6617
6618 wsec_pmk_t psk;
6619 size_t key_len;
6620
6621 wsec = TKIP_ENABLED;
6622 res = dev_wlc_intvar_set(dev, "wsec", wsec);
6623
6624 key_len = strlen(ap->key);
6625 if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) {
6626 WL_SOFTAP(("passphrase must be between %d and %d characters long\n",
6627 WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN));
6628 return -1;
6629 }
6630
6631 if (key_len < WSEC_MAX_PSK_LEN) {
6632 unsigned char output[2*SHA1HashSize];
6633 char key_str_buf[WSEC_MAX_PSK_LEN+1];
6634 bzero(output, 2*SHA1HashSize);
6635
6636 WL_SOFTAP(("%s: do passhash...\n", __FUNCTION__));
6637
6638 pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32);
6639
6640 ptr = key_str_buf;
6641 for (i = 0; i < (WSEC_MAX_PSK_LEN/8); i++) {
6642 WL_SOFTAP(("[%02d]: %08x\n", i, *((unsigned int *)&output[i*4])));
6643
6644 sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4],
6645 (uint)output[i*4+1], (uint)output[i*4+2],
6646 (uint)output[i*4+3]);
6647 ptr += 8;
6648 }
6649 WL_SOFTAP(("%s: passphase = %s\n", __FUNCTION__, key_str_buf));
6650
6651 psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN);
6652 memcpy(psk.key, key_str_buf, psk.key_len);
6653 } else {
6654 psk.key_len = htod16((ushort) key_len);
6655 memcpy(psk.key, ap->key, key_len);
6656 }
6657
6658 psk.flags = htod16(WSEC_PASSPHRASE);
6659 res |= dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk));
6660
6661 wpa_auth = WPA_AUTH_PSK;
6662 res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
6663
6664 WL_SOFTAP((" wsec & auth set 'wpa-psk' (TKIP), result:&d %d\n", res));
6665 }
6666
6667#ifdef AP_ONLY
6668 ap_ssid.SSID_len = strlen(ap->ssid);
6669 strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len);
6670 res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &ap_ssid, sizeof(ap_ssid));
6671 mpc = 0;
6672 res |= dev_wlc_intvar_set(dev, "mpc", mpc);
6673 if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) {
6674 res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
6675 }
6676#endif
6677 return res;
6678}
6679
6680
6681
6682int get_parmeter_from_string(
6683 char **str_ptr, const char *token,
6684 int param_type, void *dst, int param_max_len)
6685{
6686 char int_str[7] = "0";
6687 int parm_str_len;
6688 char *param_str_begin;
6689 char *param_str_end;
6690
6691 if ((*str_ptr) && !strncmp(*str_ptr, token, strlen(token))) {
6692
6693 strsep(str_ptr, "=,");
6694 param_str_begin = *str_ptr;
6695 strsep(str_ptr, "=,");
6696
6697 if (*str_ptr == NULL) {
6698 parm_str_len = strlen(param_str_begin);
6699 } else {
6700 param_str_end = *str_ptr-1;
6701 parm_str_len = param_str_end - param_str_begin;
6702 }
6703
6704 WL_TRACE((" 'token:%s', len:%d, ", token, parm_str_len));
6705
6706 if (parm_str_len > param_max_len) {
6707 WL_TRACE((" WARNING: extracted param len:%d is > MAX:%d\n",
6708 parm_str_len, param_max_len));
6709
6710 parm_str_len = param_max_len;
6711 }
6712
6713 switch (param_type) {
6714
6715 case PTYPE_INTDEC: {
6716 int *pdst_int = dst;
6717 char *eptr;
6718
6719 if (parm_str_len > sizeof(int_str))
6720 parm_str_len = sizeof(int_str);
6721
6722 memcpy(int_str, param_str_begin, parm_str_len);
6723
6724 *pdst_int = simple_strtoul(int_str, &eptr, 10);
6725
6726 WL_TRACE((" written as integer:%d\n", *pdst_int));
6727 }
6728 break;
6729 case PTYPE_STR_HEX: {
6730 u8 *buf = dst;
6731
6732 param_max_len = param_max_len >> 1;
6733 hstr_2_buf(param_str_begin, buf, param_max_len);
6734 print_buf(buf, param_max_len, 0);
6735 }
6736 break;
6737 default:
6738 memcpy(dst, param_str_begin, parm_str_len);
6739 *((char *)dst + parm_str_len) = 0;
6740 WL_TRACE((" written as a string:%s\n", (char *)dst));
6741 break;
6742 }
6743
6744 return 0;
6745 } else {
6746 WL_ERROR(("\n %s: No token:%s in str:%s\n",
6747 __FUNCTION__, token, *str_ptr));
6748
6749 return -1;
6750 }
6751}
6752
6753static int wl_iw_softap_deassoc_stations(struct net_device *dev, u8 *mac)
6754{
6755 int i;
6756 int res = 0;
6757 char mac_buf[128] = {0};
6758 char z_mac[6] = {0, 0, 0, 0, 0, 0};
6759 char *sta_mac;
6760 struct maclist *assoc_maclist = (struct maclist *) mac_buf;
6761 bool deauth_all = false;
6762
6763 if (mac == NULL) {
6764 deauth_all = true;
6765 sta_mac = z_mac;
6766 } else {
6767 sta_mac = mac;
6768 }
6769
6770 memset(assoc_maclist, 0, sizeof(mac_buf));
6771 assoc_maclist->count = 8;
6772
6773 res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 128);
6774 if (res != 0) {
6775 WL_SOFTAP(("%s: Error:%d Couldn't get ASSOC List\n", __FUNCTION__, res));
6776 return res;
6777 }
6778
6779 if (assoc_maclist->count) {
6780 for (i = 0; i < assoc_maclist->count; i++) {
6781 scb_val_t scbval;
6782
6783 scbval.val = htod32(1);
6784 bcopy(&assoc_maclist->ea[i], &scbval.ea, ETHER_ADDR_LEN);
6785
6786 if (deauth_all || (memcmp(&scbval.ea, sta_mac, ETHER_ADDR_LEN) == 0)) {
6787 WL_SOFTAP(("%s, deauth STA:%d \n", __FUNCTION__, i));
6788 res |= dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
6789 &scbval, sizeof(scb_val_t));
6790 }
6791 }
6792 } else {
6793 WL_SOFTAP((" STA ASSOC list is empty\n"));
6794 }
6795
6796 if (res != 0) {
6797 WL_ERROR(("%s: Error:%d\n", __FUNCTION__, res));
6798 } else if (assoc_maclist->count) {
6799 bcm_mdelay(200);
6800 }
6801 return res;
6802}
6803
6804
6805static int iwpriv_softap_stop(struct net_device *dev,
6806 struct iw_request_info *info,
6807 union iwreq_data *wrqu,
6808 char *ext)
6809{
6810 int res = 0;
6811
6812 WL_SOFTAP(("got iwpriv AP_BSS_STOP\n"));
6813
6814 if ((!dev) && (!ap_net_dev)) {
6815 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
6816 return res;
6817 }
6818
6819 net_os_wake_lock(dev);
6820
6821 if ((ap_cfg_running == TRUE)) {
6822#ifdef AP_ONLY
6823 wl_iw_softap_deassoc_stations(dev, NULL);
6824#else
6825 wl_iw_softap_deassoc_stations(ap_net_dev, NULL);
6826
6827 if ((res = dev_iw_write_cfg1_bss_var(dev, 2)) < 0)
6828 WL_ERROR(("%s failed to del BSS err = %d", __FUNCTION__, res));
6829#endif
6830
6831 bcm_mdelay(100);
6832
6833 wrqu->data.length = 0;
6834 ap_cfg_running = FALSE;
6835 }
6836 else
6837 WL_ERROR(("%s: was called when SoftAP is OFF : move on\n", __FUNCTION__));
6838
6839 WL_SOFTAP(("%s Done with %d\n", __FUNCTION__, res));
6840
6841 net_os_wake_unlock(dev);
6842
6843 return res;
6844}
6845
6846
6847static int iwpriv_fw_reload(struct net_device *dev,
6848 struct iw_request_info *info,
6849 union iwreq_data *wrqu,
6850 char *ext)
6851{
6852 int ret = -1;
6853 char extra[256];
6854 char *fwstr = fw_path;
6855
6856 WL_SOFTAP(("current firmware_path[]=%s\n", fwstr));
6857
6858 WL_TRACE((">Got FW_RELOAD cmd:"
6859 "info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d, \
6860 fw_path:%p, len:%d \n",
6861 info->cmd, info->flags,
6862 wrqu->data.pointer, wrqu->data.length, fwstr, strlen(fwstr)));
6863
6864 if ((wrqu->data.length > 4) && (wrqu->data.length < sizeof(extra))) {
6865
6866 char *str_ptr;
6867
6868 if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
6869 ret = -EFAULT;
6870 goto exit_proc;
6871 }
6872
6873 extra[wrqu->data.length] = 8;
6874 str_ptr = extra;
6875
6876 if (get_parmeter_from_string(&str_ptr, "FW_PATH=", PTYPE_STRING, fwstr, 255) != 0) {
6877 WL_ERROR(("Error: extracting FW_PATH='' string\n"));
6878 goto exit_proc;
6879 }
6880
6881 if (strstr(fwstr, "apsta") != NULL) {
6882 WL_SOFTAP(("GOT APSTA FIRMWARE\n"));
6883 ap_fw_loaded = TRUE;
6884 } else {
6885 WL_SOFTAP(("GOT STA FIRMWARE\n"));
6886 ap_fw_loaded = FALSE;
6887 }
6888
6889 WL_SOFTAP(("SET firmware_path[]=%s , str_p:%p\n", fwstr, fwstr));
6890 ret = 0;
6891 } else {
6892 WL_ERROR(("Error: ivalid param len:%d\n", wrqu->data.length));
6893 }
6894
6895exit_proc:
6896 return ret;
6897}
6898#endif
6899
6900#ifdef SOFTAP
6901static int iwpriv_wpasupp_loop_tst(struct net_device *dev,
6902 struct iw_request_info *info,
6903 union iwreq_data *wrqu,
6904 char *ext)
6905{
6906 int res = 0;
6907 char *params = NULL;
6908
6909 WL_TRACE((">Got IWPRIV wp_supp loopback cmd test:"
6910 "info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n",
6911 info->cmd, info->flags,
6912 wrqu->data.pointer, wrqu->data.length));
6913
6914 if (wrqu->data.length != 0) {
6915
6916 if (!(params = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
6917 return -ENOMEM;
6918
6919 if (copy_from_user(params, wrqu->data.pointer, wrqu->data.length)) {
6920 kfree(params);
6921 return -EFAULT;
6922 }
6923
6924 params[wrqu->data.length] = 0;
6925 WL_SOFTAP(("\n>> copied from user:\n %s\n", params));
6926 } else {
6927 WL_ERROR(("ERROR param length is 0\n"));
6928 return -EFAULT;
6929 }
6930
6931 res = wl_iw_send_priv_event(dev, params);
6932 kfree(params);
6933
6934 return res;
6935}
6936#endif
6937
6938
6939static int
6940iwpriv_en_ap_bss(
6941 struct net_device *dev,
6942 struct iw_request_info *info,
6943 void *wrqu,
6944 char *extra)
6945{
6946 int res = 0;
6947
6948 if (!dev) {
6949 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
6950 return -1;
6951 }
6952
6953 net_os_wake_lock(dev);
6954
6955 WL_SOFTAP(("%s: rcvd IWPRIV IOCTL: for dev:%s\n", __FUNCTION__, dev->name));
6956
6957#ifndef AP_ONLY
6958 if (ap_cfg_pid >= 0) {
6959 wait_for_completion(&ap_cfg_exited);
6960 ap_cfg_pid = -1;
6961 }
6962
6963 if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) {
6964 WL_ERROR((" %s ERROR setting SOFTAP security in :%d\n", __FUNCTION__, res));
6965 }
6966 else {
6967 if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0)
6968 WL_ERROR(("%s fail to set bss up err=%d\n", __FUNCTION__, res));
6969 else
6970 bcm_mdelay(100);
6971 }
6972
6973#endif
6974 WL_SOFTAP(("%s done with res %d \n", __FUNCTION__, res));
6975
6976 net_os_wake_unlock(dev);
6977
6978 return res;
6979}
6980
6981static int
6982get_assoc_sta_list(struct net_device *dev, char *buf, int len)
6983{
6984 WL_TRACE(("%s: dev_wlc_ioctl(dev:%p, cmd:%d, buf:%p, len:%d)\n",
6985 __FUNCTION__, dev, WLC_GET_ASSOCLIST, buf, len));
6986
6987 return dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, buf, len);
6988
6989}
6990
6991
6992void check_error(int res, const char *msg, const char *func, int line)
6993{
6994 if (res != 0)
6995 WL_ERROR(("%s, %d function:%s, line:%d\n", msg, res, func, line));
6996}
6997
6998static int
6999set_ap_mac_list(struct net_device *dev, void *buf)
7000{
7001 struct mac_list_set *mac_list_set = (struct mac_list_set *)buf;
7002 struct maclist *maclist = (struct maclist *)&mac_list_set->mac_list;
7003 int length;
7004 int i;
7005 int mac_mode = mac_list_set->mode;
7006 int ioc_res = 0;
7007 ap_macmode = mac_list_set->mode;
7008
7009 bzero(&ap_black_list, sizeof(struct mflist));
7010
7011 if (mac_mode == MACLIST_MODE_DISABLED) {
7012
7013 ioc_res = dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode));
7014 check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__);
7015 WL_SOFTAP(("%s: MAC filtering disabled\n", __FUNCTION__));
7016 } else {
7017
7018 scb_val_t scbval;
7019 char mac_buf[256] = {0};
7020 struct maclist *assoc_maclist = (struct maclist *) mac_buf;
7021
7022 bcopy(maclist, &ap_black_list, sizeof(ap_black_list));
7023
7024 ioc_res = dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode));
7025 check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__);
7026
7027 length = sizeof(maclist->count) + maclist->count*ETHER_ADDR_LEN;
7028 dev_wlc_ioctl(dev, WLC_SET_MACLIST, maclist, length);
7029
7030 WL_SOFTAP(("%s: applied MAC List, mode:%d, length %d:\n",
7031 __FUNCTION__, mac_mode, length));
7032 for (i = 0; i < maclist->count; i++)
7033 WL_SOFTAP(("mac %d: %02X:%02X:%02X:%02X:%02X:%02X\n",
7034 i, maclist->ea[i].octet[0], maclist->ea[i].octet[1], \
7035 maclist->ea[i].octet[2], \
7036 maclist->ea[i].octet[3], maclist->ea[i].octet[4], \
7037 maclist->ea[i].octet[5]));
7038
7039 assoc_maclist->count = 8;
7040 ioc_res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 256);
7041 check_error(ioc_res, "ioctl ERROR:", __FUNCTION__, __LINE__);
7042 WL_SOFTAP((" Cur assoc clients:%d\n", assoc_maclist->count));
7043
7044 if (assoc_maclist->count)
7045 for (i = 0; i < assoc_maclist->count; i++) {
7046 int j;
7047 bool assoc_mac_matched = false;
7048
7049 WL_SOFTAP(("\n Cheking assoc STA: "));
7050 print_buf(&assoc_maclist->ea[i], 6, 7);
7051 WL_SOFTAP(("with the b/w list:"));
7052
7053 for (j = 0; j < maclist->count; j++)
7054 if (!bcmp(&assoc_maclist->ea[i], &maclist->ea[j],
7055 ETHER_ADDR_LEN)) {
7056
7057 assoc_mac_matched = true;
7058 break;
7059 }
7060
7061 if (((mac_mode == MACLIST_MODE_ALLOW) && !assoc_mac_matched) ||
7062 ((mac_mode == MACLIST_MODE_DENY) && assoc_mac_matched)) {
7063
7064 WL_SOFTAP(("b-match or w-mismatch,"
7065 " do deauth/disassoc \n"));
7066 scbval.val = htod32(1);
7067 bcopy(&assoc_maclist->ea[i], &scbval.ea, \
7068 ETHER_ADDR_LEN);
7069 ioc_res = dev_wlc_ioctl(dev,
7070 WLC_SCB_DEAUTHENTICATE_FOR_REASON,
7071 &scbval, sizeof(scb_val_t));
7072 check_error(ioc_res,
7073 "ioctl ERROR:",
7074 __FUNCTION__, __LINE__);
7075
7076 } else {
7077 WL_SOFTAP((" no b/w list hits, let it be\n"));
7078 }
7079 } else {
7080 WL_SOFTAP(("No ASSOC CLIENTS\n"));
7081 }
7082 }
7083
7084 WL_SOFTAP(("%s iocres:%d\n", __FUNCTION__, ioc_res));
7085 return ioc_res;
7086}
7087#endif
7088
7089
7090#ifdef SOFTAP
7091int set_macfilt_from_string(struct mflist *pmflist, char **param_str)
7092{
7093 return 0;
7094}
7095#endif
7096
7097
7098#ifdef SOFTAP
7099#define PARAM_OFFSET PROFILE_OFFSET
7100
7101int wl_iw_process_private_ascii_cmd(
7102 struct net_device *dev,
7103 struct iw_request_info *info,
7104 union iwreq_data *dwrq,
7105 char *cmd_str)
7106{
7107 int ret = 0;
7108 char *sub_cmd = cmd_str + PROFILE_OFFSET + strlen("ASCII_CMD=");
7109
7110 WL_SOFTAP(("\n %s: ASCII_CMD: offs_0:%s, offset_32:\n'%s'\n",
7111 __FUNCTION__, cmd_str, cmd_str + PROFILE_OFFSET));
7112
7113 if (strnicmp(sub_cmd, "AP_CFG", strlen("AP_CFG")) == 0) {
7114
7115 WL_SOFTAP((" AP_CFG \n"));
7116
7117
7118 if (init_ap_profile_from_string(cmd_str+PROFILE_OFFSET, &my_ap) != 0) {
7119 WL_ERROR(("ERROR: SoftAP CFG prams !\n"));
7120 ret = -1;
7121 } else {
7122 ret = set_ap_cfg(dev, &my_ap);
7123 }
7124
7125 } else if (strnicmp(sub_cmd, "AP_BSS_START", strlen("AP_BSS_START")) == 0) {
7126
7127 WL_SOFTAP(("\n SOFTAP - ENABLE BSS \n"));
7128
7129 WL_SOFTAP(("\n!!! got 'WL_AP_EN_BSS' from WPA supplicant, dev:%s\n", dev->name));
7130
7131#ifndef AP_ONLY
7132 if (ap_net_dev == NULL) {
7133 printf("\n ERROR: SOFTAP net_dev* is NULL !!!\n");
7134 } else {
7135 if ((ret = iwpriv_en_ap_bss(ap_net_dev, info, dwrq, cmd_str)) < 0)
7136 WL_ERROR(("%s line %d fail to set bss up\n", \
7137 __FUNCTION__, __LINE__));
7138 }
7139#else
7140 if ((ret = iwpriv_en_ap_bss(dev, info, dwrq, cmd_str)) < 0)
7141 WL_ERROR(("%s line %d fail to set bss up\n", \
7142 __FUNCTION__, __LINE__));
7143#endif
7144 } else if (strnicmp(sub_cmd, "ASSOC_LST", strlen("ASSOC_LST")) == 0) {
7145 /* no code yet */
7146 } else if (strnicmp(sub_cmd, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) {
7147 WL_SOFTAP((" \n temp DOWN SOFTAP\n"));
7148#ifndef AP_ONLY
7149 if ((ret = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) {
7150 WL_ERROR(("%s line %d fail to set bss down\n", \
7151 __FUNCTION__, __LINE__));
7152 }
7153#endif
7154 }
7155
7156 return ret;
7157}
7158#endif
7159
7160static int wl_iw_set_priv(
7161 struct net_device *dev,
7162 struct iw_request_info *info,
7163 struct iw_point *dwrq,
7164 char *ext
7165)
7166{
7167 int ret = 0;
7168 char * extra;
7169
7170 if (!(extra = kmalloc(dwrq->length, GFP_KERNEL)))
7171 return -ENOMEM;
7172
7173 if (copy_from_user(extra, dwrq->pointer, dwrq->length)) {
7174 kfree(extra);
7175 return -EFAULT;
7176 }
7177
7178 WL_TRACE(("%s: SIOCSIWPRIV request %s, info->cmd:%x, info->flags:%d\n dwrq->length:%d",
7179 dev->name, extra, info->cmd, info->flags, dwrq->length));
7180
7181 net_os_wake_lock(dev);
7182
7183 if (dwrq->length && extra) {
7184 if (strnicmp(extra, "START", strlen("START")) == 0) {
7185 wl_iw_control_wl_on(dev, info);
7186 WL_TRACE(("%s, Received regular START command\n", __FUNCTION__));
7187 }
7188
7189 if (g_onoff == G_WLAN_SET_OFF) {
7190 WL_TRACE(("%s, missing START, Fail\n", __FUNCTION__));
7191 kfree(extra);
7192 net_os_wake_unlock(dev);
7193 return -EFAULT;
7194 }
7195
7196 if (strnicmp(extra, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
7197#ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS
7198 WL_TRACE(("%s: active scan setting suppressed\n", dev->name));
7199#else
7200 ret = wl_iw_set_active_scan(dev, info, (union iwreq_data *)dwrq, extra);
7201#endif
7202 } else if (strnicmp(extra, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0)
7203#ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS
7204 WL_TRACE(("%s: passive scan setting suppressed\n", dev->name));
7205#else
7206 ret = wl_iw_set_passive_scan(dev, info, (union iwreq_data *)dwrq, extra);
7207#endif
7208 else if (strnicmp(extra, "RSSI", strlen("RSSI")) == 0)
7209 ret = wl_iw_get_rssi(dev, info, (union iwreq_data *)dwrq, extra);
7210 else if (strnicmp(extra, "LINKSPEED", strlen("LINKSPEED")) == 0)
7211 ret = wl_iw_get_link_speed(dev, info, (union iwreq_data *)dwrq, extra);
7212 else if (strnicmp(extra, "MACADDR", strlen("MACADDR")) == 0)
7213 ret = wl_iw_get_macaddr(dev, info, (union iwreq_data *)dwrq, extra);
7214 else if (strnicmp(extra, "COUNTRY", strlen("COUNTRY")) == 0)
7215 ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra);
7216 else if (strnicmp(extra, "STOP", strlen("STOP")) == 0)
7217 ret = wl_iw_control_wl_off(dev, info);
7218 else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0)
7219 ret = wl_iw_get_band(dev, info, (union iwreq_data *)dwrq, extra);
7220 else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0)
7221 ret = wl_iw_set_band(dev, info, (union iwreq_data *)dwrq, extra);
7222 else if (strnicmp(extra, DTIM_SKIP_GET_CMD, strlen(DTIM_SKIP_GET_CMD)) == 0)
7223 ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
7224 else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0)
7225 ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
7226 else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0)
7227 ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra);
7228 else if (strnicmp(extra, TXPOWER_SET_CMD, strlen(TXPOWER_SET_CMD)) == 0)
7229 ret = wl_iw_set_txpower(dev, info, (union iwreq_data *)dwrq, extra);
7230#if defined(PNO_SUPPORT)
7231 else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0)
7232 ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra);
7233 else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0)
7234 ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra);
7235 else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0)
7236 ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra);
7237#endif
7238#if defined(CSCAN)
7239 else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0)
7240 ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra);
7241#endif
7242#ifdef CUSTOMER_HW2
7243 else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
7244 ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
7245 else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) {
7246 WL_TRACE_COEX(("%s:got Framwrork cmd: 'BTCOEXMODE'\n", __FUNCTION__));
7247 ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra);
7248 }
7249#else
7250 else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
7251 ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra);
7252#endif
7253 else if (strnicmp(extra, "GETPOWER", strlen("GETPOWER")) == 0)
7254 ret = wl_iw_get_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
7255 else if (strnicmp(extra, RXFILTER_START_CMD, strlen(RXFILTER_START_CMD)) == 0)
7256 ret = net_os_set_packet_filter(dev, 1);
7257 else if (strnicmp(extra, RXFILTER_STOP_CMD, strlen(RXFILTER_STOP_CMD)) == 0)
7258 ret = net_os_set_packet_filter(dev, 0);
7259 else if (strnicmp(extra, RXFILTER_ADD_CMD, strlen(RXFILTER_ADD_CMD)) == 0) {
7260 int filter_num = *(extra + strlen(RXFILTER_ADD_CMD) + 1) - '0';
7261 ret = net_os_rxfilter_add_remove(dev, TRUE, filter_num);
7262 }
7263 else if (strnicmp(extra, RXFILTER_REMOVE_CMD, strlen(RXFILTER_REMOVE_CMD)) == 0) {
7264 int filter_num = *(extra + strlen(RXFILTER_REMOVE_CMD) + 1) - '0';
7265 ret = net_os_rxfilter_add_remove(dev, FALSE, filter_num);
7266 }
7267#ifdef SOFTAP
7268#ifdef SOFTAP_TLV_CFG
7269 else if (strnicmp(extra, SOFTAP_SET_CMD, strlen(SOFTAP_SET_CMD)) == 0) {
7270 wl_iw_softap_cfg_tlv(dev, info, (union iwreq_data *)dwrq, extra);
7271 }
7272#endif
7273 else if (strnicmp(extra, "ASCII_CMD", strlen("ASCII_CMD")) == 0) {
7274 wl_iw_process_private_ascii_cmd(dev, info, (union iwreq_data *)dwrq, extra);
7275 } else if (strnicmp(extra, "AP_MAC_LIST_SET", strlen("AP_MAC_LIST_SET")) == 0) {
7276 WL_SOFTAP(("penguin, set AP_MAC_LIST_SET\n"));
7277 set_ap_mac_list(dev, (extra + PROFILE_OFFSET));
7278 }
7279#endif
7280 else {
7281 WL_TRACE(("Unknown PRIVATE command: %s: ignored\n", extra));
7282 snprintf(extra, MAX_WX_STRING, "OK");
7283 dwrq->length = strlen("OK") + 1;
7284 }
7285 }
7286
7287 net_os_wake_unlock(dev);
7288
7289 if (extra) {
7290 if (copy_to_user(dwrq->pointer, extra, dwrq->length)) {
7291 kfree(extra);
7292 return -EFAULT;
7293 }
7294
7295 kfree(extra);
7296 }
7297
7298 return ret;
7299}
7300
7301static const iw_handler wl_iw_handler[] =
7302{
7303 (iw_handler) wl_iw_config_commit,
7304 (iw_handler) wl_iw_get_name,
7305 (iw_handler) NULL,
7306 (iw_handler) NULL,
7307 (iw_handler) wl_iw_set_freq,
7308 (iw_handler) wl_iw_get_freq,
7309 (iw_handler) wl_iw_set_mode,
7310 (iw_handler) wl_iw_get_mode,
7311 (iw_handler) NULL,
7312 (iw_handler) NULL,
7313 (iw_handler) NULL,
7314 (iw_handler) wl_iw_get_range,
7315 (iw_handler) wl_iw_set_priv,
7316 (iw_handler) NULL,
7317 (iw_handler) NULL,
7318 (iw_handler) NULL,
7319 (iw_handler) wl_iw_set_spy,
7320 (iw_handler) wl_iw_get_spy,
7321 (iw_handler) NULL,
7322 (iw_handler) NULL,
7323 (iw_handler) wl_iw_set_wap,
7324 (iw_handler) wl_iw_get_wap,
7325#if WIRELESS_EXT > 17
7326 (iw_handler) wl_iw_mlme,
7327#else
7328 (iw_handler) NULL,
7329#endif
7330#if defined(WL_IW_USE_ISCAN)
7331 (iw_handler) wl_iw_iscan_get_aplist,
7332#else
7333 (iw_handler) wl_iw_get_aplist,
7334#endif
7335#if WIRELESS_EXT > 13
7336#if defined(WL_IW_USE_ISCAN)
7337 (iw_handler) wl_iw_iscan_set_scan,
7338 (iw_handler) wl_iw_iscan_get_scan,
7339#else
7340 (iw_handler) wl_iw_set_scan,
7341 (iw_handler) wl_iw_get_scan,
7342#endif
7343#else
7344 (iw_handler) NULL,
7345 (iw_handler) NULL,
7346#endif
7347 (iw_handler) wl_iw_set_essid,
7348 (iw_handler) wl_iw_get_essid,
7349 (iw_handler) wl_iw_set_nick,
7350 (iw_handler) wl_iw_get_nick,
7351 (iw_handler) NULL,
7352 (iw_handler) NULL,
7353 (iw_handler) wl_iw_set_rate,
7354 (iw_handler) wl_iw_get_rate,
7355 (iw_handler) wl_iw_set_rts,
7356 (iw_handler) wl_iw_get_rts,
7357 (iw_handler) wl_iw_set_frag,
7358 (iw_handler) wl_iw_get_frag,
7359 (iw_handler) wl_iw_set_txpow,
7360 (iw_handler) wl_iw_get_txpow,
7361#if WIRELESS_EXT > 10
7362 (iw_handler) wl_iw_set_retry,
7363 (iw_handler) wl_iw_get_retry,
7364#endif
7365 (iw_handler) wl_iw_set_encode,
7366 (iw_handler) wl_iw_get_encode,
7367 (iw_handler) wl_iw_set_power,
7368 (iw_handler) wl_iw_get_power,
7369#if WIRELESS_EXT > 17
7370 (iw_handler) NULL,
7371 (iw_handler) NULL,
7372 (iw_handler) wl_iw_set_wpaie,
7373 (iw_handler) wl_iw_get_wpaie,
7374 (iw_handler) wl_iw_set_wpaauth,
7375 (iw_handler) wl_iw_get_wpaauth,
7376 (iw_handler) wl_iw_set_encodeext,
7377 (iw_handler) wl_iw_get_encodeext,
7378#ifdef BCMWPA2
7379 (iw_handler) wl_iw_set_pmksa,
7380#endif
7381#endif
7382};
7383
7384#if WIRELESS_EXT > 12
7385static const iw_handler wl_iw_priv_handler[] = {
7386 NULL,
7387 (iw_handler)wl_iw_set_active_scan,
7388 NULL,
7389 (iw_handler)wl_iw_get_rssi,
7390 NULL,
7391 (iw_handler)wl_iw_set_passive_scan,
7392 NULL,
7393 (iw_handler)wl_iw_get_link_speed,
7394 NULL,
7395 (iw_handler)wl_iw_get_macaddr,
7396 NULL,
7397 (iw_handler)wl_iw_control_wl_off,
7398 NULL,
7399 (iw_handler)wl_iw_control_wl_on,
7400#ifdef SOFTAP
7401 NULL,
7402 (iw_handler)iwpriv_set_ap_config,
7403
7404 NULL,
7405 (iw_handler)iwpriv_get_assoc_list,
7406
7407 NULL,
7408 (iw_handler)iwpriv_set_mac_filters,
7409
7410 NULL,
7411 (iw_handler)iwpriv_en_ap_bss,
7412
7413 NULL,
7414 (iw_handler)iwpriv_wpasupp_loop_tst,
7415
7416 NULL,
7417 (iw_handler)iwpriv_softap_stop,
7418
7419 NULL,
7420 (iw_handler)iwpriv_fw_reload,
7421
7422 NULL,
7423 (iw_handler)iwpriv_set_ap_sta_disassoc,
7424#endif
7425#if defined(CSCAN)
7426
7427 NULL,
7428 (iw_handler)iwpriv_set_cscan
7429#endif
7430};
7431
7432static const struct iw_priv_args wl_iw_priv_args[] = {
7433 {
7434 WL_IW_SET_ACTIVE_SCAN,
7435 0,
7436 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7437 "SCAN-ACTIVE"
7438 },
7439 {
7440 WL_IW_GET_RSSI,
7441 0,
7442 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7443 "RSSI"
7444 },
7445 {
7446 WL_IW_SET_PASSIVE_SCAN,
7447 0,
7448 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7449 "SCAN-PASSIVE"
7450 },
7451 {
7452 WL_IW_GET_LINK_SPEED,
7453 0,
7454 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7455 "LINKSPEED"
7456 },
7457 {
7458 WL_IW_GET_CURR_MACADDR,
7459 0,
7460 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7461 "Macaddr"
7462 },
7463 {
7464 WL_IW_SET_STOP,
7465 0,
7466 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7467 "STOP"
7468 },
7469 {
7470 WL_IW_SET_START,
7471 0,
7472 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7473 "START"
7474 },
7475
7476#ifdef SOFTAP
7477 {
7478 WL_SET_AP_CFG,
7479 IW_PRIV_TYPE_CHAR | 256,
7480 0,
7481 "AP_SET_CFG"
7482 },
7483
7484 {
7485 WL_AP_STA_LIST,
7486 IW_PRIV_TYPE_CHAR | 0,
7487 IW_PRIV_TYPE_CHAR | 1024,
7488 "AP_GET_STA_LIST"
7489 },
7490
7491 {
7492 WL_AP_MAC_FLTR,
7493 IW_PRIV_TYPE_CHAR | 256,
7494 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7495 "AP_SET_MAC_FLTR"
7496 },
7497
7498 {
7499 WL_AP_BSS_START,
7500 0,
7501 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
7502 "AP_BSS_START"
7503 },
7504
7505 {
7506 AP_LPB_CMD,
7507 IW_PRIV_TYPE_CHAR | 256,
7508 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7509 "AP_LPB_CMD"
7510 },
7511
7512 {
7513 WL_AP_STOP,
7514 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7515 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7516 "AP_BSS_STOP"
7517 },
7518
7519 {
7520 WL_FW_RELOAD,
7521 IW_PRIV_TYPE_CHAR | 256,
7522 IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
7523 "WL_FW_RELOAD"
7524 },
7525
7526 {
7527 WL_AP_STA_DISASSOC,
7528 IW_PRIV_TYPE_CHAR | 256,
7529 IW_PRIV_TYPE_CHAR | 0,
7530 "AP_STA_DISASSOC"
7531 },
7532#endif
7533#if defined(CSCAN)
7534 {
7535 WL_COMBO_SCAN,
7536 IW_PRIV_TYPE_CHAR | 1024,
7537 0,
7538 "CSCAN"
7539 },
7540#endif
7541};
7542
7543const struct iw_handler_def wl_iw_handler_def =
7544{
7545 .num_standard = ARRAYSIZE(wl_iw_handler),
7546 .standard = (iw_handler *) wl_iw_handler,
7547 .num_private = ARRAYSIZE(wl_iw_priv_handler),
7548 .num_private_args = ARRAY_SIZE(wl_iw_priv_args),
7549 .private = (iw_handler *)wl_iw_priv_handler,
7550 .private_args = (void *) wl_iw_priv_args,
7551
7552#if WIRELESS_EXT >= 19
7553 get_wireless_stats: dhd_get_wireless_stats,
7554#endif
7555};
7556#endif
7557
7558
7559int wl_iw_ioctl(
7560 struct net_device *dev,
7561 struct ifreq *rq,
7562 int cmd
7563)
7564{
7565 struct iwreq *wrq = (struct iwreq *) rq;
7566 struct iw_request_info info;
7567 iw_handler handler;
7568 char *extra = NULL;
7569 int token_size = 1, max_tokens = 0, ret = 0;
7570
7571 net_os_wake_lock(dev);
7572
7573 WL_TRACE(("%s: cmd:%x alled via dhd->do_ioctl()entry point\n", __FUNCTION__, cmd));
7574 if (cmd < SIOCIWFIRST ||
7575 IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) ||
7576 !(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) {
7577 WL_ERROR(("%s: error in cmd=%x : not supported\n", __FUNCTION__, cmd));
7578 net_os_wake_unlock(dev);
7579 return -EOPNOTSUPP;
7580 }
7581
7582 switch (cmd) {
7583
7584 case SIOCSIWESSID:
7585 case SIOCGIWESSID:
7586 case SIOCSIWNICKN:
7587 case SIOCGIWNICKN:
7588 max_tokens = IW_ESSID_MAX_SIZE + 1;
7589 break;
7590
7591 case SIOCSIWENCODE:
7592 case SIOCGIWENCODE:
7593#if WIRELESS_EXT > 17
7594 case SIOCSIWENCODEEXT:
7595 case SIOCGIWENCODEEXT:
7596#endif
7597 max_tokens = wrq->u.data.length;
7598 break;
7599
7600 case SIOCGIWRANGE:
7601 max_tokens = sizeof(struct iw_range) + 500;
7602 break;
7603
7604 case SIOCGIWAPLIST:
7605 token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality);
7606 max_tokens = IW_MAX_AP;
7607 break;
7608
7609#if WIRELESS_EXT > 13
7610 case SIOCGIWSCAN:
7611#if defined(WL_IW_USE_ISCAN)
7612 if (g_iscan)
7613 max_tokens = wrq->u.data.length;
7614 else
7615#endif
7616 max_tokens = IW_SCAN_MAX_DATA;
7617 break;
7618#endif
7619
7620 case SIOCSIWSPY:
7621 token_size = sizeof(struct sockaddr);
7622 max_tokens = IW_MAX_SPY;
7623 break;
7624
7625 case SIOCGIWSPY:
7626 token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality);
7627 max_tokens = IW_MAX_SPY;
7628 break;
7629
7630#if WIRELESS_EXT > 17
7631 case SIOCSIWPMKSA:
7632 case SIOCSIWGENIE:
7633#endif
7634 case SIOCSIWPRIV:
7635 max_tokens = wrq->u.data.length;
7636 break;
7637 }
7638
7639 if (max_tokens && wrq->u.data.pointer) {
7640 if (wrq->u.data.length > max_tokens) {
7641 WL_ERROR(("%s: error in cmd=%x wrq->u.data.length=%d > max_tokens=%d\n", \
7642 __FUNCTION__, cmd, wrq->u.data.length, max_tokens));
7643 ret = -E2BIG;
7644 goto wl_iw_ioctl_done;
7645 }
7646 if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) {
7647 ret = -ENOMEM;
7648 goto wl_iw_ioctl_done;
7649 }
7650
7651 if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) {
7652 kfree(extra);
7653 ret = -EFAULT;
7654 goto wl_iw_ioctl_done;
7655 }
7656 }
7657
7658 info.cmd = cmd;
7659 info.flags = 0;
7660
7661 ret = handler(dev, &info, &wrq->u, extra);
7662
7663 if (extra) {
7664 if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) {
7665 kfree(extra);
7666 ret = -EFAULT;
7667 goto wl_iw_ioctl_done;
7668 }
7669
7670 kfree(extra);
7671 }
7672
7673wl_iw_ioctl_done:
7674
7675 net_os_wake_unlock(dev);
7676
7677 return ret;
7678}
7679
7680
7681bool
7682wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason,
7683 char* stringBuf, uint buflen)
7684{
7685 typedef struct conn_fail_event_map_t {
7686 uint32 inEvent;
7687 uint32 inStatus;
7688 uint32 inReason;
7689 const char* outName;
7690 const char* outCause;
7691 } conn_fail_event_map_t;
7692
7693
7694# define WL_IW_DONT_CARE 9999
7695 const conn_fail_event_map_t event_map [] = {
7696
7697
7698 {WLC_E_SET_SSID, WLC_E_STATUS_SUCCESS, WL_IW_DONT_CARE,
7699 "Conn", "Success"},
7700 {WLC_E_SET_SSID, WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE,
7701 "Conn", "NoNetworks"},
7702 {WLC_E_SET_SSID, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
7703 "Conn", "ConfigMismatch"},
7704 {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_PRUNE_ENCR_MISMATCH,
7705 "Conn", "EncrypMismatch"},
7706 {WLC_E_PRUNE, WL_IW_DONT_CARE, WLC_E_RSN_MISMATCH,
7707 "Conn", "RsnMismatch"},
7708 {WLC_E_AUTH, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
7709 "Conn", "AuthTimeout"},
7710 {WLC_E_AUTH, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
7711 "Conn", "AuthFail"},
7712 {WLC_E_AUTH, WLC_E_STATUS_NO_ACK, WL_IW_DONT_CARE,
7713 "Conn", "AuthNoAck"},
7714 {WLC_E_REASSOC, WLC_E_STATUS_FAIL, WL_IW_DONT_CARE,
7715 "Conn", "ReassocFail"},
7716 {WLC_E_REASSOC, WLC_E_STATUS_TIMEOUT, WL_IW_DONT_CARE,
7717 "Conn", "ReassocTimeout"},
7718 {WLC_E_REASSOC, WLC_E_STATUS_ABORT, WL_IW_DONT_CARE,
7719 "Conn", "ReassocAbort"},
7720 {WLC_E_PSK_SUP, WLC_SUP_KEYED, WL_IW_DONT_CARE,
7721 "Sup", "ConnSuccess"},
7722 {WLC_E_PSK_SUP, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
7723 "Sup", "WpaHandshakeFail"},
7724 {WLC_E_DEAUTH_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
7725 "Conn", "Deauth"},
7726 {WLC_E_DISASSOC_IND, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
7727 "Conn", "DisassocInd"},
7728 {WLC_E_DISASSOC, WL_IW_DONT_CARE, WL_IW_DONT_CARE,
7729 "Conn", "Disassoc"}
7730 };
7731
7732 const char* name = "";
7733 const char* cause = NULL;
7734 int i;
7735
7736
7737 for (i = 0; i < sizeof(event_map)/sizeof(event_map[0]); i++) {
7738 const conn_fail_event_map_t* row = &event_map[i];
7739 if (row->inEvent == event_type &&
7740 (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) &&
7741 (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) {
7742 name = row->outName;
7743 cause = row->outCause;
7744 break;
7745 }
7746 }
7747
7748
7749 if (cause) {
7750 memset(stringBuf, 0, buflen);
7751 snprintf(stringBuf, buflen, "%s %s %02d %02d",
7752 name, cause, status, reason);
7753 WL_INFORM(("Connection status: %s\n", stringBuf));
7754 return TRUE;
7755 } else {
7756 return FALSE;
7757 }
7758}
7759
7760#if WIRELESS_EXT > 14
7761
7762static bool
7763wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen)
7764{
7765 uint32 event = ntoh32(e->event_type);
7766 uint32 status = ntoh32(e->status);
7767 uint32 reason = ntoh32(e->reason);
7768
7769 if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) {
7770 return TRUE;
7771 }
7772 else
7773 return FALSE;
7774}
7775#endif
7776
7777#ifndef IW_CUSTOM_MAX
7778#define IW_CUSTOM_MAX 256
7779#endif
7780
7781void
7782wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
7783{
7784#if WIRELESS_EXT > 13
7785 union iwreq_data wrqu;
7786 char extra[IW_CUSTOM_MAX + 1];
7787 int cmd = 0;
7788 uint32 event_type = ntoh32(e->event_type);
7789 uint16 flags = ntoh16(e->flags);
7790 uint32 datalen = ntoh32(e->datalen);
7791 uint32 status = ntoh32(e->status);
7792 uint32 toto;
7793#if defined(ROAM_NOT_USED)
7794 static uint32 roam_no_success = 0;
7795 static bool roam_no_success_send = FALSE;
7796#endif
7797 memset(&wrqu, 0, sizeof(wrqu));
7798 memset(extra, 0, sizeof(extra));
7799
7800 if (!dev) {
7801 WL_ERROR(("%s: dev is null\n", __FUNCTION__));
7802 return;
7803 }
7804
7805 net_os_wake_lock(dev);
7806
7807 WL_TRACE(("%s: dev=%s event=%d \n", __FUNCTION__, dev->name, event_type));
7808
7809 switch (event_type) {
7810
7811 case WLC_E_RELOAD:
7812 WL_ERROR(("%s: Firmware ERROR %d\n", __FUNCTION__, status));
7813 net_os_send_hang_message(dev);
7814 goto wl_iw_event_end;
7815
7816#if defined(SOFTAP)
7817 case WLC_E_PRUNE:
7818 if (ap_cfg_running) {
7819 char *macaddr = (char *)&e->addr;
7820 WL_SOFTAP(("PRUNE received, %02X:%02X:%02X:%02X:%02X:%02X!\n",
7821 macaddr[0], macaddr[1], macaddr[2], macaddr[3], \
7822 macaddr[4], macaddr[5]));
7823
7824 if (ap_macmode) {
7825 int i;
7826 for (i = 0; i < ap_black_list.count; i++) {
7827 if (!bcmp(macaddr, &ap_black_list.ea[i], \
7828 sizeof(struct ether_addr))) {
7829 WL_SOFTAP(("mac in black list, ignore it\n"));
7830 break;
7831 }
7832 }
7833
7834 if (i == ap_black_list.count) {
7835 char mac_buf[32] = {0};
7836 sprintf(mac_buf, "STA_BLOCK %02X:%02X:%02X:%02X:%02X:%02X",
7837 macaddr[0], macaddr[1], macaddr[2],
7838 macaddr[3], macaddr[4], macaddr[5]);
7839 wl_iw_send_priv_event(priv_dev, mac_buf);
7840 }
7841 }
7842 }
7843 break;
7844#endif
7845 case WLC_E_TXFAIL:
7846 cmd = IWEVTXDROP;
7847 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
7848 wrqu.addr.sa_family = ARPHRD_ETHER;
7849 break;
7850#if WIRELESS_EXT > 14
7851 case WLC_E_JOIN:
7852 case WLC_E_ASSOC_IND:
7853 case WLC_E_REASSOC_IND:
7854#if defined(SOFTAP)
7855 WL_SOFTAP(("STA connect received %d\n", event_type));
7856 if (ap_cfg_running) {
7857 wl_iw_send_priv_event(priv_dev, "STA_JOIN");
7858 goto wl_iw_event_end;
7859 }
7860#endif
7861 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
7862 wrqu.addr.sa_family = ARPHRD_ETHER;
7863 cmd = IWEVREGISTERED;
7864 break;
7865 case WLC_E_ROAM:
7866 if (status == WLC_E_STATUS_SUCCESS) {
7867 WL_ASSOC(("%s: WLC_E_ROAM: success\n", __FUNCTION__));
7868#if defined(ROAM_NOT_USED)
7869 roam_no_success_send = FALSE;
7870 roam_no_success = 0;
7871#endif
7872 goto wl_iw_event_end;
7873 }
7874#if defined(ROAM_NOT_USED)
7875 else if (status == WLC_E_STATUS_NO_NETWORKS) {
7876 roam_no_success++;
7877 if ((roam_no_success == 5) && (roam_no_success_send == FALSE)) {
7878 roam_no_success_send = TRUE;
7879 bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
7880 bzero(&extra, ETHER_ADDR_LEN);
7881 cmd = SIOCGIWAP;
7882 WL_ERROR(("%s ROAMING did not succeeded , send Link Down\n", \
7883 __FUNCTION__));
7884 } else {
7885 WL_TRACE(("##### ROAMING did not succeeded %d\n", roam_no_success));
7886 goto wl_iw_event_end;
7887 }
7888 }
7889#endif
7890 break;
7891 case WLC_E_DEAUTH_IND:
7892 case WLC_E_DISASSOC_IND:
7893#if defined(SOFTAP)
7894 WL_SOFTAP(("STA disconnect received %d\n", event_type));
7895 if (ap_cfg_running) {
7896 wl_iw_send_priv_event(priv_dev, "STA_LEAVE");
7897 goto wl_iw_event_end;
7898 }
7899#endif
7900 cmd = SIOCGIWAP;
7901 bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
7902 wrqu.addr.sa_family = ARPHRD_ETHER;
7903 bzero(&extra, ETHER_ADDR_LEN);
7904 break;
7905 case WLC_E_LINK:
7906 case WLC_E_NDIS_LINK:
7907 cmd = SIOCGIWAP;
7908 if (!(flags & WLC_EVENT_MSG_LINK)) {
7909#ifdef SOFTAP
7910#ifdef AP_ONLY
7911 if (ap_cfg_running) {
7912#else
7913 if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) {
7914#endif
7915 WL_SOFTAP(("AP DOWN %d\n", event_type));
7916 wl_iw_send_priv_event(priv_dev, "AP_DOWN");
7917 } else {
7918 WL_TRACE(("STA_Link Down\n"));
7919 g_ss_cache_ctrl.m_link_down = 1;
7920 }
7921#else
7922 g_ss_cache_ctrl.m_link_down = 1;
7923#endif
7924 WL_TRACE(("Link Down\n"));
7925
7926 bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
7927 bzero(&extra, ETHER_ADDR_LEN);
7928 }
7929 else {
7930 memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
7931 g_ss_cache_ctrl.m_link_down = 0;
7932
7933 memcpy(g_ss_cache_ctrl.m_active_bssid, &e->addr, ETHER_ADDR_LEN);
7934
7935#ifdef SOFTAP
7936#ifdef AP_ONLY
7937 if (ap_cfg_running) {
7938#else
7939 if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) {
7940#endif
7941 WL_SOFTAP(("AP UP %d\n", event_type));
7942 wl_iw_send_priv_event(priv_dev, "AP_UP");
7943 } else {
7944 WL_TRACE(("STA_LINK_UP\n"));
7945#if defined(ROAM_NOT_USED)
7946 roam_no_success_send = FALSE;
7947 roam_no_success = 0;
7948#endif
7949 }
7950#endif
7951 WL_TRACE(("Link UP\n"));
7952
7953 }
7954 net_os_wake_lock_timeout_enable(dev);
7955 wrqu.addr.sa_family = ARPHRD_ETHER;
7956 break;
7957 case WLC_E_ACTION_FRAME:
7958 cmd = IWEVCUSTOM;
7959 if (datalen + 1 <= sizeof(extra)) {
7960 wrqu.data.length = datalen + 1;
7961 extra[0] = WLC_E_ACTION_FRAME;
7962 memcpy(&extra[1], data, datalen);
7963 WL_TRACE(("WLC_E_ACTION_FRAME len %d \n", wrqu.data.length));
7964 }
7965 break;
7966
7967 case WLC_E_ACTION_FRAME_COMPLETE:
7968 cmd = IWEVCUSTOM;
7969 memcpy(&toto, data, 4);
7970 if (sizeof(status) + 1 <= sizeof(extra)) {
7971 wrqu.data.length = sizeof(status) + 1;
7972 extra[0] = WLC_E_ACTION_FRAME_COMPLETE;
7973 memcpy(&extra[1], &status, sizeof(status));
7974 printf("wl_iw_event status %d PacketId %d \n", status, toto);
7975 printf("WLC_E_ACTION_FRAME_COMPLETE len %d \n", wrqu.data.length);
7976 }
7977 break;
7978#endif
7979#if WIRELESS_EXT > 17
7980 case WLC_E_MIC_ERROR: {
7981 struct iw_michaelmicfailure *micerrevt = (struct iw_michaelmicfailure *)&extra;
7982 cmd = IWEVMICHAELMICFAILURE;
7983 wrqu.data.length = sizeof(struct iw_michaelmicfailure);
7984 if (flags & WLC_EVENT_MSG_GROUP)
7985 micerrevt->flags |= IW_MICFAILURE_GROUP;
7986 else
7987 micerrevt->flags |= IW_MICFAILURE_PAIRWISE;
7988 memcpy(micerrevt->src_addr.sa_data, &e->addr, ETHER_ADDR_LEN);
7989 micerrevt->src_addr.sa_family = ARPHRD_ETHER;
7990
7991 break;
7992 }
7993#ifdef BCMWPA2
7994 case WLC_E_PMKID_CACHE: {
7995 if (data)
7996 {
7997 struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra;
7998 pmkid_cand_list_t *pmkcandlist;
7999 pmkid_cand_t *pmkidcand;
8000 int count;
8001
8002 cmd = IWEVPMKIDCAND;
8003 pmkcandlist = data;
8004 count = ntoh32_ua((uint8 *)&pmkcandlist->npmkid_cand);
8005 ASSERT(count >= 0);
8006 wrqu.data.length = sizeof(struct iw_pmkid_cand);
8007 pmkidcand = pmkcandlist->pmkid_cand;
8008 while (count) {
8009 bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand));
8010 if (pmkidcand->preauth)
8011 iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH;
8012 bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data,
8013 ETHER_ADDR_LEN);
8014#ifndef SANDGATE2G
8015 wireless_send_event(dev, cmd, &wrqu, extra);
8016#endif
8017 pmkidcand++;
8018 count--;
8019 }
8020 }
8021 goto wl_iw_event_end;
8022 }
8023#endif
8024#endif
8025
8026 case WLC_E_SCAN_COMPLETE:
8027#if defined(WL_IW_USE_ISCAN)
8028 if ((g_iscan) && (g_iscan->sysioc_pid >= 0) &&
8029 (g_iscan->iscan_state != ISCAN_STATE_IDLE))
8030 {
8031 up(&g_iscan->sysioc_sem);
8032 } else {
8033 cmd = SIOCGIWSCAN;
8034 wrqu.data.length = strlen(extra);
8035 WL_TRACE(("Event WLC_E_SCAN_COMPLETE from specific scan %d\n", \
8036 g_iscan->iscan_state));
8037 }
8038#else
8039 cmd = SIOCGIWSCAN;
8040 wrqu.data.length = strlen(extra);
8041 WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n"));
8042#endif
8043 break;
8044
8045 case WLC_E_PFN_NET_FOUND:
8046 {
8047 wlc_ssid_t * ssid;
8048 ssid = (wlc_ssid_t *)data;
8049 WL_TRACE(("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n", \
8050 __FUNCTION__, PNO_EVENT_UP, ssid->SSID, ssid->SSID_len));
8051 net_os_wake_lock_timeout_enable(dev);
8052 cmd = IWEVCUSTOM;
8053 memset(&wrqu, 0, sizeof(wrqu));
8054 strcpy(extra, PNO_EVENT_UP);
8055 wrqu.data.length = strlen(extra);
8056 }
8057 break;
8058
8059 default:
8060
8061 WL_TRACE(("Unknown Event %d: ignoring\n", event_type));
8062 break;
8063 }
8064#ifndef SANDGATE2G
8065 if (cmd) {
8066#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31))
8067 if (cmd == SIOCGIWSCAN)
8068 wireless_send_event(dev, cmd, &wrqu, NULL);
8069 else
8070#endif
8071 wireless_send_event(dev, cmd, &wrqu, extra);
8072 }
8073#endif
8074
8075#if WIRELESS_EXT > 14
8076 memset(extra, 0, sizeof(extra));
8077 if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) {
8078 cmd = IWEVCUSTOM;
8079 wrqu.data.length = strlen(extra);
8080#ifndef SANDGATE2G
8081 wireless_send_event(dev, cmd, &wrqu, extra);
8082#endif
8083 }
8084#endif
8085wl_iw_event_end:
8086 net_os_wake_unlock(dev);
8087#endif
8088}
8089
8090int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
8091{
8092 int res = 0;
8093 wl_cnt_t cnt;
8094 int phy_noise;
8095 int rssi;
8096 scb_val_t scb_val;
8097
8098 phy_noise = 0;
8099 if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise))))
8100 goto done;
8101
8102 phy_noise = dtoh32(phy_noise);
8103 WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise));
8104
8105 bzero(&scb_val, sizeof(scb_val_t));
8106 if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t))))
8107 goto done;
8108
8109 rssi = dtoh32(scb_val.val);
8110 WL_TRACE(("wl_iw_get_wireless_stats rssi=%d\n", rssi));
8111 if (rssi <= WL_IW_RSSI_NO_SIGNAL)
8112 wstats->qual.qual = 0;
8113 else if (rssi <= WL_IW_RSSI_VERY_LOW)
8114 wstats->qual.qual = 1;
8115 else if (rssi <= WL_IW_RSSI_LOW)
8116 wstats->qual.qual = 2;
8117 else if (rssi <= WL_IW_RSSI_GOOD)
8118 wstats->qual.qual = 3;
8119 else if (rssi <= WL_IW_RSSI_VERY_GOOD)
8120 wstats->qual.qual = 4;
8121 else
8122 wstats->qual.qual = 5;
8123
8124
8125 wstats->qual.level = 0x100 + rssi;
8126 wstats->qual.noise = 0x100 + phy_noise;
8127#if WIRELESS_EXT > 18
8128 wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
8129#else
8130 wstats->qual.updated |= 7;
8131#endif
8132
8133#if WIRELESS_EXT > 11
8134 WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n", (int)sizeof(wl_cnt_t)));
8135
8136 memset(&cnt, 0, sizeof(wl_cnt_t));
8137 res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t));
8138 if (res)
8139 {
8140 WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d\n", res));
8141 goto done;
8142 }
8143
8144 cnt.version = dtoh16(cnt.version);
8145 if (cnt.version != WL_CNT_T_VERSION) {
8146 WL_TRACE(("\tIncorrect version of counters struct: expected %d; got %d\n",
8147 WL_CNT_T_VERSION, cnt.version));
8148 goto done;
8149 }
8150
8151 wstats->discard.nwid = 0;
8152 wstats->discard.code = dtoh32(cnt.rxundec);
8153 wstats->discard.fragment = dtoh32(cnt.rxfragerr);
8154 wstats->discard.retries = dtoh32(cnt.txfail);
8155 wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant);
8156 wstats->miss.beacon = 0;
8157
8158 WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n",
8159 dtoh32(cnt.txframe), dtoh32(cnt.txbyte)));
8160 WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", dtoh32(cnt.rxfrmtoolong)));
8161 WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", dtoh32(cnt.rxbadplcp)));
8162 WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n", dtoh32(cnt.rxundec)));
8163 WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n", dtoh32(cnt.rxfragerr)));
8164 WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n", dtoh32(cnt.txfail)));
8165 WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n", dtoh32(cnt.rxrunt)));
8166 WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n", dtoh32(cnt.rxgiant)));
8167
8168#endif
8169
8170done:
8171 return res;
8172}
8173static void
8174wl_iw_bt_flag_set(
8175 struct net_device *dev,
8176 bool set)
8177{
8178#if defined(BT_DHCP_USE_FLAGS)
8179 char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
8180 char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
8181#endif
8182
8183#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
8184 rtnl_lock();
8185#endif
8186
8187#if defined(BT_DHCP_eSCO_FIX)
8188 set_btc_esco_params(dev, set);
8189#endif
8190
8191#if defined(BT_DHCP_USE_FLAGS)
8192 WL_TRACE_COEX(("WI-FI priority boost via bt flags, set:%d\n", set));
8193 if (set == TRUE) {
8194 dev_wlc_bufvar_set(dev, "btc_flags",
8195 (char *)&buf_flag7_dhcp_on[0], sizeof(buf_flag7_dhcp_on));
8196 }
8197 else {
8198 dev_wlc_bufvar_set(dev, "btc_flags",
8199 (char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
8200 }
8201#endif
8202
8203#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
8204 rtnl_unlock();
8205#endif
8206}
8207
8208static void
8209wl_iw_bt_timerfunc(ulong data)
8210{
8211 bt_info_t *bt_local = (bt_info_t *)data;
8212 bt_local->timer_on = 0;
8213 WL_TRACE(("%s\n", __FUNCTION__));
8214
8215 up(&bt_local->bt_sem);
8216}
8217
8218static int
8219_bt_dhcp_sysioc_thread(void *data)
8220{
8221 DAEMONIZE("dhcp_sysioc");
8222
8223 while (down_interruptible(&g_bt->bt_sem) == 0) {
8224
8225 net_os_wake_lock(g_bt->dev);
8226
8227 if (g_bt->timer_on) {
8228 g_bt->timer_on = 0;
8229 del_timer_sync(&g_bt->timer);
8230 }
8231
8232 switch (g_bt->bt_state) {
8233 case BT_DHCP_START:
8234 WL_TRACE_COEX(("%s bt_dhcp stm: started \n", __FUNCTION__));
8235 g_bt->bt_state = BT_DHCP_OPPORTUNITY_WINDOW;
8236 mod_timer(&g_bt->timer, jiffies + BT_DHCP_OPPORTUNITY_WINDOW_TIME*HZ/1000);
8237 g_bt->timer_on = 1;
8238 break;
8239
8240 case BT_DHCP_OPPORTUNITY_WINDOW:
8241 if (g_bt->dhcp_done) {
8242 WL_TRACE_COEX(("%s DHCP Done before T1 expiration\n", \
8243 __FUNCTION__));
8244 g_bt->bt_state = BT_DHCP_IDLE;
8245 g_bt->timer_on = 0;
8246 break;
8247 }
8248
8249 WL_TRACE_COEX(("%s DHCP T1:%d expired\n", \
8250 __FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIME));
8251 if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, TRUE);
8252 g_bt->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
8253 mod_timer(&g_bt->timer, jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
8254 g_bt->timer_on = 1;
8255 break;
8256
8257 case BT_DHCP_FLAG_FORCE_TIMEOUT:
8258 if (g_bt->dhcp_done) {
8259 WL_TRACE_COEX(("%s DHCP Done before T2 expiration\n", \
8260 __FUNCTION__));
8261 } else {
8262 WL_TRACE_COEX(("%s DHCP wait interval T2:%d msec expired\n",
8263 __FUNCTION__, BT_DHCP_FLAG_FORCE_TIME));
8264 }
8265
8266 if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE);
8267 g_bt->bt_state = BT_DHCP_IDLE;
8268 g_bt->timer_on = 0;
8269 break;
8270
8271 default:
8272 WL_ERROR(("%s error g_status=%d !!!\n", __FUNCTION__, \
8273 g_bt->bt_state));
8274 if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE);
8275 g_bt->bt_state = BT_DHCP_IDLE;
8276 g_bt->timer_on = 0;
8277 break;
8278 }
8279
8280 net_os_wake_unlock(g_bt->dev);
8281 }
8282
8283 if (g_bt->timer_on) {
8284 g_bt->timer_on = 0;
8285 del_timer_sync(&g_bt->timer);
8286 }
8287
8288 complete_and_exit(&g_bt->bt_exited, 0);
8289}
8290
8291static void
8292wl_iw_bt_release(void)
8293{
8294 bt_info_t *bt_local = g_bt;
8295
8296 if (!bt_local) {
8297 return;
8298 }
8299
8300 if (bt_local->bt_pid >= 0) {
8301 KILL_PROC(bt_local->bt_pid, SIGTERM);
8302 wait_for_completion(&bt_local->bt_exited);
8303 }
8304 kfree(bt_local);
8305 g_bt = NULL;
8306}
8307
8308static int
8309wl_iw_bt_init(struct net_device *dev)
8310{
8311 bt_info_t *bt_dhcp = NULL;
8312
8313 bt_dhcp = kmalloc(sizeof(bt_info_t), GFP_KERNEL);
8314 if (!bt_dhcp)
8315 return -ENOMEM;
8316
8317 memset(bt_dhcp, 0, sizeof(bt_info_t));
8318 bt_dhcp->bt_pid = -1;
8319 g_bt = bt_dhcp;
8320 bt_dhcp->dev = dev;
8321 bt_dhcp->bt_state = BT_DHCP_IDLE;
8322
8323
8324 bt_dhcp->timer_ms = 10;
8325 init_timer(&bt_dhcp->timer);
8326 bt_dhcp->timer.data = (ulong)bt_dhcp;
8327 bt_dhcp->timer.function = wl_iw_bt_timerfunc;
8328
8329 sema_init(&bt_dhcp->bt_sem, 0);
8330 init_completion(&bt_dhcp->bt_exited);
8331 bt_dhcp->bt_pid = kernel_thread(_bt_dhcp_sysioc_thread, bt_dhcp, 0);
8332 if (bt_dhcp->bt_pid < 0) {
8333 WL_ERROR(("Failed in %s\n", __FUNCTION__));
8334 return -ENOMEM;
8335 }
8336
8337 return 0;
8338}
8339
8340int wl_iw_attach(struct net_device *dev, void *dhdp)
8341{
8342 int params_size;
8343 wl_iw_t *iw;
8344#if defined(WL_IW_USE_ISCAN)
8345 iscan_info_t *iscan = NULL;
8346#endif
8347
8348 mutex_init(&wl_cache_lock);
8349
8350#if defined(WL_IW_USE_ISCAN)
8351 if (!dev)
8352 return 0;
8353
8354 memset(&g_wl_iw_params, 0, sizeof(wl_iw_extra_params_t));
8355
8356#ifdef CSCAN
8357 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) +
8358 (WL_NUMCHANNELS * sizeof(uint16)) + WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
8359#else
8360 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params));
8361#endif
8362 iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL);
8363 if (!iscan)
8364 return -ENOMEM;
8365 memset(iscan, 0, sizeof(iscan_info_t));
8366
8367 iscan->iscan_ex_params_p = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL);
8368 if (!iscan->iscan_ex_params_p)
8369 return -ENOMEM;
8370 iscan->iscan_ex_param_size = params_size;
8371 iscan->sysioc_pid = -1;
8372
8373 g_iscan = iscan;
8374 iscan->dev = dev;
8375 iscan->iscan_state = ISCAN_STATE_IDLE;
8376#if defined(CONFIG_FIRST_SCAN)
8377 g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
8378 g_first_counter_scans = 0;
8379 g_iscan->scan_flag = 0;
8380#endif
8381
8382 iscan->timer_ms = 8000;
8383 init_timer(&iscan->timer);
8384 iscan->timer.data = (ulong)iscan;
8385 iscan->timer.function = wl_iw_timerfunc;
8386
8387 sema_init(&iscan->sysioc_sem, 0);
8388 init_completion(&iscan->sysioc_exited);
8389 iscan->sysioc_pid = kernel_thread(_iscan_sysioc_thread, iscan, 0);
8390 if (iscan->sysioc_pid < 0)
8391 return -ENOMEM;
8392#endif
8393
8394 iw = *(wl_iw_t **)netdev_priv(dev);
8395 iw->pub = (dhd_pub_t *)dhdp;
8396#ifdef SOFTAP
8397 priv_dev = dev;
8398#endif
8399 g_scan = NULL;
8400
8401 g_scan = (void *)kmalloc(G_SCAN_RESULTS, GFP_KERNEL);
8402 if (!g_scan)
8403 return -ENOMEM;
8404
8405 memset(g_scan, 0, G_SCAN_RESULTS);
8406 g_scan_specified_ssid = 0;
8407
8408#if !defined(CSCAN)
8409 wl_iw_init_ss_cache_ctrl();
8410#endif
8411
8412 wl_iw_bt_init(dev);
8413
8414 return 0;
8415}
8416
8417void wl_iw_detach(void)
8418{
8419#if defined(WL_IW_USE_ISCAN)
8420 iscan_buf_t *buf;
8421 iscan_info_t *iscan = g_iscan;
8422
8423 if (!iscan)
8424 return;
8425 if (iscan->sysioc_pid >= 0) {
8426 KILL_PROC(iscan->sysioc_pid, SIGTERM);
8427 wait_for_completion(&iscan->sysioc_exited);
8428 }
8429 mutex_lock(&wl_cache_lock);
8430 while (iscan->list_hdr) {
8431 buf = iscan->list_hdr->next;
8432 kfree(iscan->list_hdr);
8433 iscan->list_hdr = buf;
8434 }
8435 kfree(iscan->iscan_ex_params_p);
8436 kfree(iscan);
8437 g_iscan = NULL;
8438 mutex_unlock(&wl_cache_lock);
8439#endif
8440
8441 if (g_scan)
8442 kfree(g_scan);
8443
8444 g_scan = NULL;
8445#if !defined(CSCAN)
8446 wl_iw_release_ss_cache_ctrl();
8447#endif
8448 wl_iw_bt_release();
8449#ifdef SOFTAP
8450 if (ap_cfg_running) {
8451 WL_TRACE(("\n%s AP is going down\n", __FUNCTION__));
8452 wl_iw_send_priv_event(priv_dev, "AP_DOWN");
8453 }
8454#endif
8455}
diff --git a/drivers/net/wireless/bcm4329/wl_iw.h b/drivers/net/wireless/bcm4329/wl_iw.h
new file mode 100644
index 00000000000..ee6c699936e
--- /dev/null
+++ b/drivers/net/wireless/bcm4329/wl_iw.h
@@ -0,0 +1,309 @@
1/*
2 * Linux Wireless Extensions support
3 *
4 * Copyright (C) 1999-2010, 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.5.34.1.6.36.4.18 2011/02/10 19:33:12 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#define PNOSETUP_SET_CMD "PNOSETUP "
53#define PNOENABLE_SET_CMD "PNOFORCE"
54#define PNODEBUG_SET_CMD "PNODEBUG"
55#define TXPOWER_SET_CMD "TXPOWER"
56#define RXFILTER_START_CMD "RXFILTER-START"
57#define RXFILTER_STOP_CMD "RXFILTER-STOP"
58#define RXFILTER_ADD_CMD "RXFILTER-ADD"
59#define RXFILTER_REMOVE_CMD "RXFILTER-REMOVE"
60
61#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
62#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
63
64
65typedef struct wl_iw_extra_params {
66 int target_channel;
67} wl_iw_extra_params_t;
68
69struct cntry_locales_custom {
70 char iso_abbrev[WLC_CNTRY_BUF_SZ];
71 char custom_locale[WLC_CNTRY_BUF_SZ];
72 int32 custom_locale_rev;
73};
74
75#define WL_IW_RSSI_MINVAL -200
76#define WL_IW_RSSI_NO_SIGNAL -91
77#define WL_IW_RSSI_VERY_LOW -80
78#define WL_IW_RSSI_LOW -70
79#define WL_IW_RSSI_GOOD -68
80#define WL_IW_RSSI_VERY_GOOD -58
81#define WL_IW_RSSI_EXCELLENT -57
82#define WL_IW_RSSI_INVALID 0
83#define MAX_WX_STRING 80
84#define isprint(c) bcm_isprint(c)
85#define WL_IW_SET_ACTIVE_SCAN (SIOCIWFIRSTPRIV+1)
86#define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3)
87#define WL_IW_SET_PASSIVE_SCAN (SIOCIWFIRSTPRIV+5)
88#define WL_IW_GET_LINK_SPEED (SIOCIWFIRSTPRIV+7)
89#define WL_IW_GET_CURR_MACADDR (SIOCIWFIRSTPRIV+9)
90#define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11)
91#define WL_IW_SET_START (SIOCIWFIRSTPRIV+13)
92
93
94#define WL_SET_AP_CFG (SIOCIWFIRSTPRIV+15)
95#define WL_AP_STA_LIST (SIOCIWFIRSTPRIV+17)
96#define WL_AP_MAC_FLTR (SIOCIWFIRSTPRIV+19)
97#define WL_AP_BSS_START (SIOCIWFIRSTPRIV+21)
98#define AP_LPB_CMD (SIOCIWFIRSTPRIV+23)
99#define WL_AP_STOP (SIOCIWFIRSTPRIV+25)
100#define WL_FW_RELOAD (SIOCIWFIRSTPRIV+27)
101#define WL_AP_STA_DISASSOC (SIOCIWFIRSTPRIV+29)
102#define WL_COMBO_SCAN (SIOCIWFIRSTPRIV+31)
103
104#define G_SCAN_RESULTS (8*1024)
105#define WE_ADD_EVENT_FIX 0x80
106#define G_WLAN_SET_ON 0
107#define G_WLAN_SET_OFF 1
108
109#define CHECK_EXTRA_FOR_NULL(extra) \
110if (!extra) { \
111 WL_ERROR(("%s: error : extra is null pointer\n", __FUNCTION__)); \
112 return -EINVAL; \
113}
114
115typedef struct wl_iw {
116 char nickname[IW_ESSID_MAX_SIZE];
117
118 struct iw_statistics wstats;
119
120 int spy_num;
121 uint32 pwsec;
122 uint32 gwsec;
123 bool 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
131#define WLC_IW_SS_CACHE_MAXLEN 2048
132#define WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN 32
133#define WLC_IW_BSS_INFO_MAXLEN \
134 (WLC_IW_SS_CACHE_MAXLEN - WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN)
135
136typedef struct wl_iw_ss_cache {
137 struct wl_iw_ss_cache *next;
138 int dirty;
139 uint32 buflen;
140 uint32 version;
141 uint32 count;
142 wl_bss_info_t bss_info[1];
143} wl_iw_ss_cache_t;
144
145typedef struct wl_iw_ss_cache_ctrl {
146 wl_iw_ss_cache_t *m_cache_head;
147 int m_link_down;
148 int m_timer_expired;
149 char m_active_bssid[ETHER_ADDR_LEN];
150 uint m_prev_scan_mode;
151 uint m_cons_br_scan_cnt;
152 struct timer_list *m_timer;
153} wl_iw_ss_cache_ctrl_t;
154
155typedef enum broadcast_first_scan {
156 BROADCAST_SCAN_FIRST_IDLE = 0,
157 BROADCAST_SCAN_FIRST_STARTED,
158 BROADCAST_SCAN_FIRST_RESULT_READY,
159 BROADCAST_SCAN_FIRST_RESULT_CONSUMED
160} broadcast_first_scan_t;
161#ifdef SOFTAP
162#define SSID_LEN 33
163#define SEC_LEN 16
164#define KEY_LEN 65
165#define PROFILE_OFFSET 32
166struct ap_profile {
167 uint8 ssid[SSID_LEN];
168 uint8 sec[SEC_LEN];
169 uint8 key[KEY_LEN];
170 uint32 channel;
171 uint32 preamble;
172 uint32 max_scb;
173 uint32 closednet;
174 char country_code[WLC_CNTRY_BUF_SZ];
175};
176
177
178#define MACLIST_MODE_DISABLED 0
179#define MACLIST_MODE_DENY 1
180#define MACLIST_MODE_ALLOW 2
181struct mflist {
182 uint count;
183 struct ether_addr ea[16];
184};
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);
202int wl_control_wl_start(struct net_device *dev);
203
204extern int net_os_wake_lock(struct net_device *dev);
205extern int net_os_wake_unlock(struct net_device *dev);
206extern int net_os_wake_lock_timeout(struct net_device *dev);
207extern int net_os_wake_lock_timeout_enable(struct net_device *dev);
208extern int net_os_set_suspend_disable(struct net_device *dev, int val);
209extern int net_os_set_suspend(struct net_device *dev, int val);
210extern int net_os_set_dtim_skip(struct net_device *dev, int val);
211extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec);
212extern char *dhd_bus_country_get(struct net_device *dev);
213extern int dhd_get_dtim_skip(dhd_pub_t *dhd);
214
215#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
216#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \
217 iwe_stream_add_event(info, stream, ends, iwe, extra)
218#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \
219 iwe_stream_add_value(info, event, value, ends, iwe, event_len)
220#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \
221 iwe_stream_add_point(info, stream, ends, iwe, extra)
222#else
223#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \
224 iwe_stream_add_event(stream, ends, iwe, extra)
225#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \
226 iwe_stream_add_value(event, value, ends, iwe, event_len)
227#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \
228 iwe_stream_add_point(stream, ends, iwe, extra)
229#endif
230
231extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled);
232extern int dhd_pno_clean(dhd_pub_t *dhd);
233extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, \
234 ushort scan_fr, int pno_repeat, int pno_freq_expo_max);
235extern int dhd_pno_get_status(dhd_pub_t *dhd);
236extern int dhd_dev_pno_reset(struct net_device *dev);
237extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, \
238 int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max);
239extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled);
240extern int dhd_dev_get_pno_status(struct net_device *dev);
241extern void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec);
242
243#define PNO_TLV_PREFIX 'S'
244#define PNO_TLV_VERSION '1'
245#define PNO_TLV_SUBVERSION '2'
246#define PNO_TLV_RESERVED '0'
247#define PNO_TLV_TYPE_SSID_IE 'S'
248#define PNO_TLV_TYPE_TIME 'T'
249#define PNO_TLV_FREQ_REPEAT 'R'
250#define PNO_TLV_FREQ_EXPO_MAX 'M'
251#define PNO_EVENT_UP "PNO_EVENT"
252
253typedef struct cmd_tlv {
254 char prefix;
255 char version;
256 char subver;
257 char reserved;
258} cmd_tlv_t;
259
260#ifdef SOFTAP_TLV_CFG
261#define SOFTAP_SET_CMD "SOFTAPSET "
262#define SOFTAP_TLV_PREFIX 'A'
263#define SOFTAP_TLV_VERSION '1'
264#define SOFTAP_TLV_SUBVERSION '0'
265#define SOFTAP_TLV_RESERVED '0'
266
267#define TLV_TYPE_SSID 'S'
268#define TLV_TYPE_SECUR 'E'
269#define TLV_TYPE_KEY 'K'
270#define TLV_TYPE_CHANNEL 'C'
271#endif
272
273#if defined(CSCAN)
274
275typedef struct cscan_tlv {
276 char prefix;
277 char version;
278 char subver;
279 char reserved;
280} cscan_tlv_t;
281
282#define CSCAN_COMMAND "CSCAN "
283#define CSCAN_TLV_PREFIX 'S'
284#define CSCAN_TLV_VERSION 1
285#define CSCAN_TLV_SUBVERSION 0
286#define CSCAN_TLV_TYPE_SSID_IE 'S'
287#define CSCAN_TLV_TYPE_CHANNEL_IE 'C'
288#define CSCAN_TLV_TYPE_NPROBE_IE 'N'
289#define CSCAN_TLV_TYPE_ACTIVE_IE 'A'
290#define CSCAN_TLV_TYPE_PASSIVE_IE 'P'
291#define CSCAN_TLV_TYPE_HOME_IE 'H'
292#define CSCAN_TLV_TYPE_STYPE_IE 'T'
293
294extern int wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, \
295 int channel_num, int *bytes_left);
296
297extern int wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, \
298 const char token, int input_size, int *bytes_left);
299
300extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, \
301 int max, int *bytes_left);
302
303extern int wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max);
304
305extern int wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num);
306
307#endif
308
309#endif