diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/net/wireless/bcm4329 | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/net/wireless/bcm4329')
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 @@ | |||
1 | config 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 | |||
15 | config 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 | |||
23 | config 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 | |||
30 | config BCM4329_NVRAM_PATH | ||
31 | depends on BCM4329 | ||
32 | string "NVRAM path" | ||
33 | default "/proc/calibration" | ||
34 | ---help--- | ||
35 | Path to the calibration file. | ||
36 | |||
37 | config 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 | |||
45 | if BCM4329_WIFI_CONTROL_FUNC | ||
46 | |||
47 | config 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 | |||
55 | config 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 | |||
62 | config 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 | |||
69 | config 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 | |||
76 | config BCM4329_CSCAN_ENABLE | ||
77 | bool "Enable Combo Scan" | ||
78 | depends on BCM4329 | ||
79 | default n | ||
80 | ---help--- | ||
81 | Enable Combo Scan | ||
82 | endif | ||
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 | ||
2 | DHDCFLAGS = -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 | |||
12 | ifeq ($(CONFIG_BCM4329_WIFI_CONTROL_FUNC),y) | ||
13 | DHDCFLAGS += -DCONFIG_WIFI_CONTROL_FUNC | ||
14 | endif | ||
15 | |||
16 | ifeq ($(CONFIG_BCM4329_FIRST_SCAN),y) | ||
17 | DHDCFLAGS += -DCONFIG_FIRST_SCAN | ||
18 | endif | ||
19 | |||
20 | ifeq ($(CONFIG_BCM4329_DHD_USE_STATIC_BUF),y) | ||
21 | DHDCFLAGS += -DDHD_USE_STATIC_BUF | ||
22 | endif | ||
23 | ifeq ($(CONFIG_BCM4329_OOB_INTR_ONLY),y) | ||
24 | DHDCFLAGS += -DOOB_INTR_ONLY | ||
25 | endif | ||
26 | ifeq ($(CONFIG_BCM4329_GET_CUSTOM_MAC_ENABLE),y) | ||
27 | DHDCFLAGS += -DGET_CUSTOM_MAC_ENABLE | ||
28 | endif | ||
29 | ifeq ($(CONFIG_BCM4329_HW_OOB),y) | ||
30 | DHDCFLAGS += -DHW_OOB | ||
31 | else | ||
32 | DHDCFLAGS += -DSDIO_ISR_THREAD | ||
33 | endif | ||
34 | ifeq ($(CONFIG_BCM4329_CSCAN_ENABLE),y) | ||
35 | # implementation of PNO_SUPPORT currently requires CSCAN | ||
36 | DHDCFLAGS += -DCSCAN -DPNO_SUPPORT | ||
37 | endif | ||
38 | |||
39 | ifeq ($(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 | ||
46 | endif | ||
47 | |||
48 | DHDOFILES = 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 | |||
53 | obj-$(CONFIG_BCM4329) += bcm4329.o | ||
54 | bcm4329-objs += $(DHDOFILES) | ||
55 | EXTRA_CFLAGS = $(DHDCFLAGS) | ||
56 | EXTRA_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 | |||
39 | STATIC uint32 | ||
40 | get_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 | |||
46 | static uint32 | ||
47 | get_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 | |||
79 | STATIC uint32 | ||
80 | get_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 */ | ||
115 | void | ||
116 | ai_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 | |||
304 | error: | ||
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 | */ | ||
312 | void * | ||
313 | ai_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 */ | ||
365 | int | ||
366 | ai_numaddrspaces(si_t *sih) | ||
367 | { | ||
368 | return 2; | ||
369 | } | ||
370 | |||
371 | /* Return the address of the nth address space in the current core */ | ||
372 | uint32 | ||
373 | ai_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 */ | ||
393 | uint32 | ||
394 | ai_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 | |||
413 | uint | ||
414 | ai_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 | |||
425 | void | ||
426 | ai_setint(si_t *sih, int siflag) | ||
427 | { | ||
428 | } | ||
429 | |||
430 | void | ||
431 | ai_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 | |||
439 | uint | ||
440 | ai_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 | |||
450 | uint | ||
451 | ai_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 | |||
461 | bool | ||
462 | ai_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 | */ | ||
483 | uint | ||
484 | ai_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 | |||
567 | void | ||
568 | ai_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 | */ | ||
596 | void | ||
597 | ai_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 | |||
626 | void | ||
627 | ai_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 | |||
645 | uint32 | ||
646 | ai_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 | |||
666 | uint32 | ||
667 | ai_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 | |||
54 | int bcmpcispi_dump = 0; /* Set to dump complete trace of all SPI bus transactions */ | ||
55 | |||
56 | typedef 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 */ | ||
67 | bool | ||
68 | spi_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 */ | ||
178 | bool | ||
179 | spi_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, ®s->spih_ctrl, 0x00000010); | ||
189 | SPIPCI_WREG(osh, ®s->spih_gpio_ctrl, 0x00000000); /* Disable GPIO for CS# */ | ||
190 | SPIPCI_WREG(osh, ®s->spih_int_mask, 0x00000000); /* Clear Intmask */ | ||
191 | SPIPCI_WREG(osh, ®s->spih_hex_disp, 0x0000DEAF); | ||
192 | SPIPCI_WREG(osh, ®s->spih_int_edge, 0x00000000); | ||
193 | SPIPCI_WREG(osh, ®s->spih_int_pol, 0x00000000); | ||
194 | SPIPCI_WREG(osh, ®s->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 */ | ||
212 | static bool | ||
213 | sdspi_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, ®s->spih_pll_ctrl, ext_clk ? SPIH_EXT_CLK : 0); | ||
221 | |||
222 | SPINWAIT(((SPIPCI_RREG(osh, ®s->spih_pll_status) & SPIH_PLL_LOCKED) | ||
223 | != SPIH_PLL_LOCKED), 1000); | ||
224 | if ((SPIPCI_RREG(osh, ®s->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 | */ | ||
236 | bool | ||
237 | spi_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, ®s->spih_clk_count); | ||
272 | if (clk_tick == SPIPCI_RREG(osh, ®s->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, ®s->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, ®s->spih_ctrl); | ||
352 | t &= ~3; | ||
353 | t |= espr & 3; | ||
354 | SPIPCI_WREG(osh, ®s->spih_ctrl, t); | ||
355 | |||
356 | t = SPIPCI_RREG(osh, ®s->spih_ext); | ||
357 | t &= ~3; | ||
358 | t |= (espr >> 2) & 3; | ||
359 | SPIPCI_WREG(osh, ®s->spih_ext, t); | ||
360 | |||
361 | SPIPCI_WREG(osh, ®s->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, ®s->spih_ctrl), | ||
376 | SPIPCI_RREG(osh, ®s->spih_ext))); | ||
377 | |||
378 | return TRUE; | ||
379 | } | ||
380 | |||
381 | /* Configure PCI-SPI Host Controller High-Speed Clocking mode setting */ | ||
382 | bool | ||
383 | spi_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, ®s->spih_ext, 0x10); | ||
392 | } else { | ||
393 | SPIPCI_ANDREG(osh, ®s->spih_ext, ~0x10); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | return TRUE; | ||
398 | } | ||
399 | |||
400 | /* Disable device interrupt */ | ||
401 | void | ||
402 | spi_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, ®s->spih_int_mask, sd->intmask); /* Clear Intmask */ | ||
412 | } | ||
413 | } | ||
414 | |||
415 | /* Enable device interrupt */ | ||
416 | void | ||
417 | spi_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, ®s->spih_ctrl) & 0x02) { | ||
427 | /* Ack in case one was pending but is no longer... */ | ||
428 | SPIPCI_WREG(osh, ®s->spih_int_status, SPIH_DEV_INTR); | ||
429 | } | ||
430 | sd->intmask |= SPIH_DEV_INTR; | ||
431 | /* Set device intr in Intmask */ | ||
432 | SPIPCI_WREG(osh, ®s->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 */ | ||
437 | bool | ||
438 | spi_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, ®s->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, ®s->spih_int_status, SPIH_DEV_INTR); | ||
465 | SPIPCI_RREG(osh, ®s->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, ®s->spih_stat, 0x00000080); | ||
474 | |||
475 | /* Ack the interrupt in the interrupt controller */ | ||
476 | SPIPCI_WREG(osh, ®s->spih_int_status, SPIH_CTLR_INTR); | ||
477 | SPIPCI_RREG(osh, ®s->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, ®s->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 | |||
501 | static void | ||
502 | hexdump(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 */ | ||
526 | void | ||
527 | spi_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, ®s->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, ®s->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, ®s->spih_int_status, SPIH_WFIFO_INTR); | ||
565 | SPIPCI_RREG(osh, ®s->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, ®s->spih_int_mask, sd->intmask); | ||
571 | |||
572 | } | ||
573 | #endif /* BCMSDYIELD */ | ||
574 | |||
575 | /* Wait for write fifo to empty... */ | ||
576 | SPIPCI_ANDREG(osh, ®s->spih_gpio_data, ~0x00000020); /* Set GPIO 5 Low */ | ||
577 | |||
578 | if (yield) { | ||
579 | ASSERT((SPIPCI_RREG(sd->osh, ®s->spih_stat) & SPIH_WFEMPTY) == 0); | ||
580 | } | ||
581 | |||
582 | spi_waitbits(sd, yield); | ||
583 | SPIPCI_ORREG(osh, ®s->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, ®s->spih_data); | ||
587 | ((uint32 *)msg_in)[count] = spi_data_in; | ||
588 | } | ||
589 | |||
590 | /* Set GPIO CS# High (de-asserted) */ | ||
591 | SPIPCI_ORREG(osh, ®s->spih_gpio_data, SPIH_CS); | ||
592 | |||
593 | if (bcmpcispi_dump) { | ||
594 | hexdump(" IN : ", msg_in, msglen); | ||
595 | } | ||
596 | } | ||
597 | |||
598 | void | ||
599 | spi_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, ®s->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, ®s->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 | ||
44 | const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL; | ||
45 | |||
46 | |||
47 | struct 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 */ | ||
57 | bcmsdh_info_t * l_bcmsdh = NULL; | ||
58 | |||
59 | #if defined(OOB_INTR_ONLY) && defined(HW_OOB) | ||
60 | extern int | ||
61 | sdioh_enable_hw_oob_intr(void *sdioh, bool enable); | ||
62 | |||
63 | void | ||
64 | bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable) | ||
65 | { | ||
66 | sdioh_enable_hw_oob_intr(sdh->sdioh, enable); | ||
67 | } | ||
68 | #endif | ||
69 | |||
70 | bcmsdh_info_t * | ||
71 | bcmsdh_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 | |||
99 | int | ||
100 | bcmsdh_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 | |||
116 | int | ||
117 | bcmsdh_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 | |||
124 | bool | ||
125 | bcmsdh_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 | |||
139 | int | ||
140 | bcmsdh_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 | |||
150 | int | ||
151 | bcmsdh_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 | |||
161 | int | ||
162 | bcmsdh_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 | |||
172 | int | ||
173 | bcmsdh_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) | ||
184 | bool | ||
185 | bcmsdh_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 | |||
195 | int | ||
196 | bcmsdh_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 | |||
204 | uint8 | ||
205 | bcmsdh_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 | |||
237 | void | ||
238 | bcmsdh_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 | |||
267 | uint32 | ||
268 | bcmsdh_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 | |||
291 | void | ||
292 | bcmsdh_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 | |||
313 | int | ||
314 | bcmsdh_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 | |||
352 | static int | ||
353 | bcmsdhsdio_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 | |||
370 | uint32 | ||
371 | bcmsdh_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 | |||
423 | uint32 | ||
424 | bcmsdh_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 | |||
461 | bool | ||
462 | bcmsdh_regfail(void *sdh) | ||
463 | { | ||
464 | return ((bcmsdh_info_t *)sdh)->regfail; | ||
465 | } | ||
466 | |||
467 | int | ||
468 | bcmsdh_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 | |||
510 | int | ||
511 | bcmsdh_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 | |||
553 | int | ||
554 | bcmsdh_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 | |||
573 | int | ||
574 | bcmsdh_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 | |||
581 | int | ||
582 | bcmsdh_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 | |||
589 | int | ||
590 | bcmsdh_stop(void *sdh) | ||
591 | { | ||
592 | bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh; | ||
593 | |||
594 | return sdioh_stop(bcmsdh->sdioh); | ||
595 | } | ||
596 | |||
597 | |||
598 | int | ||
599 | bcmsdh_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 | |||
606 | uint | ||
607 | bcmsdh_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 | |||
617 | int | ||
618 | bcmsdh_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 | |||
625 | void *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. */ | ||
632 | uint32 | ||
633 | bcmsdh_get_dstatus(void *sdh) | ||
634 | { | ||
635 | return 0; | ||
636 | } | ||
637 | uint32 | ||
638 | bcmsdh_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 | |||
648 | void | ||
649 | bcmsdh_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> | ||
46 | extern 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 | */ | ||
64 | typedef struct bcmsdh_hc bcmsdh_hc_t; | ||
65 | |||
66 | struct 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 | }; | ||
84 | static bcmsdh_hc_t *sdhcinfo = NULL; | ||
85 | |||
86 | /* driver info, initialized when bcmsdh_register is called */ | ||
87 | static 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 | */ | ||
95 | bool | ||
96 | bcmsdh_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 */ | ||
145 | int bcmsdh_probe(struct device *dev); | ||
146 | int bcmsdh_remove(struct device *dev); | ||
147 | |||
148 | EXPORT_SYMBOL(bcmsdh_probe); | ||
149 | EXPORT_SYMBOL(bcmsdh_remove); | ||
150 | |||
151 | #else | ||
152 | /* forward declarations */ | ||
153 | static int __devinit bcmsdh_probe(struct device *dev); | ||
154 | static int __devexit bcmsdh_remove(struct device *dev); | ||
155 | #endif /* BCMLXSDMMC */ | ||
156 | |||
157 | #ifndef BCMLXSDMMC | ||
158 | static 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 | ||
169 | static | ||
170 | #endif /* BCMLXSDMMC */ | ||
171 | int 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 **)®s, 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 **)®s, 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 */ | ||
260 | err: | ||
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 | ||
272 | static | ||
273 | #endif /* BCMLXSDMMC */ | ||
274 | int 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. */ | ||
315 | static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); | ||
316 | static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev); | ||
317 | |||
318 | /** | ||
319 | * pci id table | ||
320 | */ | ||
321 | static 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 | }; | ||
332 | MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid); | ||
333 | |||
334 | /** | ||
335 | * SDIO Host Controller pci driver info | ||
336 | */ | ||
337 | static 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 | |||
351 | extern 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 */ | ||
360 | module_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 | */ | ||
369 | static int __devinit | ||
370 | bcmsdh_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 **)®s, 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 */ | ||
483 | err: | ||
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 | */ | ||
497 | static void __devexit | ||
498 | bcmsdh_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 | |||
529 | extern int sdio_function_init(void); | ||
530 | |||
531 | int | ||
532 | bcmsdh_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 | |||
564 | extern void sdio_function_cleanup(void); | ||
565 | |||
566 | void | ||
567 | bcmsdh_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) | ||
585 | void 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 | |||
601 | static 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 | |||
619 | int 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 | |||
646 | void 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 | |||
660 | void 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 | |||
674 | extern uint sd_msglevel; /* Debug message level */ | ||
675 | module_param(sd_msglevel, uint, 0); | ||
676 | |||
677 | extern uint sd_power; /* 0 = SD Power OFF, 1 = SD Power ON. */ | ||
678 | module_param(sd_power, uint, 0); | ||
679 | |||
680 | extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF, 1 = SD Clock ON */ | ||
681 | module_param(sd_clock, uint, 0); | ||
682 | |||
683 | extern uint sd_divisor; /* Divisor (-1 means external clock) */ | ||
684 | module_param(sd_divisor, uint, 0); | ||
685 | |||
686 | extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */ | ||
687 | module_param(sd_sdmode, uint, 0); | ||
688 | |||
689 | extern uint sd_hiok; /* Ok to use hi-speed mode */ | ||
690 | module_param(sd_hiok, uint, 0); | ||
691 | |||
692 | extern uint sd_f2_blocksize; | ||
693 | module_param(sd_f2_blocksize, int, 0); | ||
694 | |||
695 | |||
696 | #ifdef BCMSDH_MODULE | ||
697 | EXPORT_SYMBOL(bcmsdh_attach); | ||
698 | EXPORT_SYMBOL(bcmsdh_detach); | ||
699 | EXPORT_SYMBOL(bcmsdh_intr_query); | ||
700 | EXPORT_SYMBOL(bcmsdh_intr_enable); | ||
701 | EXPORT_SYMBOL(bcmsdh_intr_disable); | ||
702 | EXPORT_SYMBOL(bcmsdh_intr_reg); | ||
703 | EXPORT_SYMBOL(bcmsdh_intr_dereg); | ||
704 | |||
705 | #if defined(DHD_DEBUG) | ||
706 | EXPORT_SYMBOL(bcmsdh_intr_pending); | ||
707 | #endif | ||
708 | |||
709 | EXPORT_SYMBOL(bcmsdh_devremove_reg); | ||
710 | EXPORT_SYMBOL(bcmsdh_cfg_read); | ||
711 | EXPORT_SYMBOL(bcmsdh_cfg_write); | ||
712 | EXPORT_SYMBOL(bcmsdh_cis_read); | ||
713 | EXPORT_SYMBOL(bcmsdh_reg_read); | ||
714 | EXPORT_SYMBOL(bcmsdh_reg_write); | ||
715 | EXPORT_SYMBOL(bcmsdh_regfail); | ||
716 | EXPORT_SYMBOL(bcmsdh_send_buf); | ||
717 | EXPORT_SYMBOL(bcmsdh_recv_buf); | ||
718 | |||
719 | EXPORT_SYMBOL(bcmsdh_rwdata); | ||
720 | EXPORT_SYMBOL(bcmsdh_abort); | ||
721 | EXPORT_SYMBOL(bcmsdh_query_device); | ||
722 | EXPORT_SYMBOL(bcmsdh_query_iofnum); | ||
723 | EXPORT_SYMBOL(bcmsdh_iovar_op); | ||
724 | EXPORT_SYMBOL(bcmsdh_register); | ||
725 | EXPORT_SYMBOL(bcmsdh_unregister); | ||
726 | EXPORT_SYMBOL(bcmsdh_chipmatch); | ||
727 | EXPORT_SYMBOL(bcmsdh_reset); | ||
728 | |||
729 | EXPORT_SYMBOL(bcmsdh_get_dstatus); | ||
730 | EXPORT_SYMBOL(bcmsdh_cfg_read_word); | ||
731 | EXPORT_SYMBOL(bcmsdh_cfg_write_word); | ||
732 | EXPORT_SYMBOL(bcmsdh_cur_sbwad); | ||
733 | EXPORT_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> | ||
46 | extern volatile bool dhd_mmc_suspend; | ||
47 | #endif | ||
48 | #include "bcmsdh_sdmmc.h" | ||
49 | |||
50 | #ifndef BCMSDH_MODULE | ||
51 | extern int sdio_function_init(void); | ||
52 | extern void sdio_function_cleanup(void); | ||
53 | #endif /* BCMSDH_MODULE */ | ||
54 | |||
55 | #if !defined(OOB_INTR_ONLY) | ||
56 | static void IRQHandler(struct sdio_func *func); | ||
57 | static void IRQHandlerF2(struct sdio_func *func); | ||
58 | #endif /* !defined(OOB_INTR_ONLY) */ | ||
59 | static int sdioh_sdmmc_get_cisaddr(sdioh_info_t *sd, uint32 regaddr); | ||
60 | extern int sdio_reset_comm(struct mmc_card *card); | ||
61 | |||
62 | extern PBCMSDH_SDMMC_INSTANCE gInstance; | ||
63 | |||
64 | uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ | ||
65 | uint sd_f2_blocksize = 512; /* Default blocksize */ | ||
66 | |||
67 | uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ | ||
68 | |||
69 | uint sd_power = 1; /* Default to SD Slot powered ON */ | ||
70 | uint sd_clock = 1; /* Default to SD Clock turned ON */ | ||
71 | uint sd_hiok = FALSE; /* Don't use hi-speed mode by default */ | ||
72 | uint sd_msglevel = 0x01; | ||
73 | uint sd_use_dma = TRUE; | ||
74 | DHD_PM_RESUME_WAIT_INIT(sdioh_request_byte_wait); | ||
75 | DHD_PM_RESUME_WAIT_INIT(sdioh_request_word_wait); | ||
76 | DHD_PM_RESUME_WAIT_INIT(sdioh_request_packet_wait); | ||
77 | DHD_PM_RESUME_WAIT_INIT(sdioh_request_buffer_wait); | ||
78 | |||
79 | #define DMA_ALIGN_MASK 0x03 | ||
80 | |||
81 | int sdioh_sdmmc_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data); | ||
82 | |||
83 | static int | ||
84 | sdioh_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 | */ | ||
122 | extern sdioh_info_t * | ||
123 | sdioh_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 | |||
188 | extern SDIOH_API_RC | ||
189 | sdioh_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 | |||
215 | extern SDIOH_API_RC | ||
216 | sdioh_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 | |||
246 | extern SDIOH_API_RC | ||
247 | sdioh_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 */ | ||
278 | extern SDIOH_API_RC | ||
279 | sdioh_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 | |||
309 | extern SDIOH_API_RC | ||
310 | sdioh_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 | |||
339 | extern SDIOH_API_RC | ||
340 | sdioh_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) | ||
348 | extern bool | ||
349 | sdioh_interrupt_pending(sdioh_info_t *sd) | ||
350 | { | ||
351 | return (0); | ||
352 | } | ||
353 | #endif | ||
354 | |||
355 | uint | ||
356 | sdioh_query_iofnum(sdioh_info_t *sd) | ||
357 | { | ||
358 | return sd->num_funcs; | ||
359 | } | ||
360 | |||
361 | /* IOVar table */ | ||
362 | enum { | ||
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 | |||
381 | const 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 | |||
400 | int | ||
401 | sdioh_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 | } | ||
661 | exit: | ||
662 | |||
663 | return bcmerror; | ||
664 | } | ||
665 | |||
666 | #if defined(OOB_INTR_ONLY) && defined(HW_OOB) | ||
667 | |||
668 | SDIOH_API_RC | ||
669 | sdioh_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 | |||
685 | extern SDIOH_API_RC | ||
686 | sdioh_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 | |||
694 | extern SDIOH_API_RC | ||
695 | sdioh_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 | |||
703 | static int | ||
704 | sdioh_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, ®data)) != 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 | |||
724 | extern SDIOH_API_RC | ||
725 | sdioh_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 | |||
756 | extern SDIOH_API_RC | ||
757 | sdioh_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 | |||
839 | extern SDIOH_API_RC | ||
840 | sdioh_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 | |||
887 | static SDIOH_API_RC | ||
888 | sdioh_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 | */ | ||
980 | extern SDIOH_API_RC | ||
981 | sdioh_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 */ | ||
1069 | extern int | ||
1070 | sdioh_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 */ | ||
1087 | int 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 */ | ||
1095 | void | ||
1096 | sdioh_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 */ | ||
1103 | void | ||
1104 | sdioh_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 */ | ||
1111 | int | ||
1112 | sdioh_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 */ | ||
1137 | static 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) */ | ||
1163 | static 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 */ | ||
1177 | static int | ||
1178 | sdioh_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 | |||
1202 | int | ||
1203 | sdioh_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 | |||
1279 | int | ||
1280 | sdioh_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 | |||
63 | extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); | ||
64 | extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); | ||
65 | |||
66 | int sdio_function_init(void); | ||
67 | void sdio_function_cleanup(void); | ||
68 | |||
69 | #define DESCRIPTION "bcmsdh_sdmmc Driver" | ||
70 | #define AUTHOR "Broadcom Corporation" | ||
71 | |||
72 | /* module param defaults */ | ||
73 | static int clockoverride = 0; | ||
74 | |||
75 | module_param(clockoverride, int, 0644); | ||
76 | MODULE_PARM_DESC(clockoverride, "SDIO card clock override"); | ||
77 | |||
78 | PBCMSDH_SDMMC_INSTANCE gInstance; | ||
79 | |||
80 | /* Maximum number of bcmsdh_sdmmc devices supported by driver */ | ||
81 | #define BCMSDH_SDMMC_MAX_DEVICES 1 | ||
82 | |||
83 | extern int bcmsdh_probe(struct device *dev); | ||
84 | extern int bcmsdh_remove(struct device *dev); | ||
85 | |||
86 | static 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 | |||
118 | static 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 */ | ||
133 | static 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 | |||
142 | MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids); | ||
143 | |||
144 | #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) | ||
145 | static 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 | |||
170 | out: | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | static 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 | |||
180 | static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = { | ||
181 | .suspend = bcmsdh_sdmmc_suspend, | ||
182 | .resume = bcmsdh_sdmmc_resume, | ||
183 | }; | ||
184 | #endif | ||
185 | |||
186 | static 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 | |||
198 | struct sdos_info { | ||
199 | sdioh_info_t *sd; | ||
200 | spinlock_t lock; | ||
201 | }; | ||
202 | |||
203 | |||
204 | int | ||
205 | sdioh_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 | |||
219 | void | ||
220 | sdioh_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 */ | ||
230 | SDIOH_API_RC | ||
231 | sdioh_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 | ||
265 | static int __init | ||
266 | bcmsdh_module_init(void) | ||
267 | { | ||
268 | int error = 0; | ||
269 | sdio_function_init(); | ||
270 | return error; | ||
271 | } | ||
272 | |||
273 | static void __exit | ||
274 | bcmsdh_module_cleanup(void) | ||
275 | { | ||
276 | sdio_function_cleanup(); | ||
277 | } | ||
278 | |||
279 | module_init(bcmsdh_module_init); | ||
280 | module_exit(bcmsdh_module_cleanup); | ||
281 | |||
282 | MODULE_LICENSE("GPL v2"); | ||
283 | MODULE_DESCRIPTION(DESCRIPTION); | ||
284 | MODULE_AUTHOR(AUTHOR); | ||
285 | |||
286 | #endif /* BCMSDH_MODULE */ | ||
287 | /* | ||
288 | * module init | ||
289 | */ | ||
290 | int 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 | */ | ||
307 | extern int bcmsdh_remove(struct device *dev); | ||
308 | void 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 | |||
51 | uint sd_msglevel = SDH_ERROR_VAL; | ||
52 | uint sd_hiok = FALSE; /* Use hi-speed mode if available? */ | ||
53 | uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */ | ||
54 | uint sd_f2_blocksize = 512; /* Default blocksize */ | ||
55 | |||
56 | uint sd_divisor = 2; /* Default 33MHz/2 = 16MHz for dongle */ | ||
57 | uint sd_power = 1; /* Default to SD Slot powered ON */ | ||
58 | uint sd_clock = 1; /* Default to SD Clock turned ON */ | ||
59 | uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */ | ||
60 | uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ | ||
61 | |||
62 | uint sd_toctl = 7; | ||
63 | |||
64 | /* Prototypes */ | ||
65 | static bool sdspi_start_power(sdioh_info_t *sd); | ||
66 | static int sdspi_set_highspeed_mode(sdioh_info_t *sd, bool HSMode); | ||
67 | static int sdspi_card_enablefuncs(sdioh_info_t *sd); | ||
68 | static void sdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count); | ||
69 | static int sdspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg, | ||
70 | uint32 *data, uint32 datalen); | ||
71 | static int sdspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, | ||
72 | int regsize, uint32 *data); | ||
73 | static int sdspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, | ||
74 | int regsize, uint32 data); | ||
75 | static int sdspi_driver_init(sdioh_info_t *sd); | ||
76 | static bool sdspi_reset(sdioh_info_t *sd, bool host_reset, bool client_reset); | ||
77 | static int sdspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, | ||
78 | uint32 addr, int nbytes, uint32 *data); | ||
79 | static int sdspi_abort(sdioh_info_t *sd, uint func); | ||
80 | |||
81 | static int set_client_block_size(sdioh_info_t *sd, int func, int blocksize); | ||
82 | |||
83 | static uint8 sdspi_crc7(unsigned char* p, uint32 len); | ||
84 | static uint16 sdspi_crc16(unsigned char* p, uint32 len); | ||
85 | static int sdspi_crc_onoff(sdioh_info_t *sd, bool use_crc); | ||
86 | |||
87 | /* | ||
88 | * Public entry points & extern's | ||
89 | */ | ||
90 | extern sdioh_info_t * | ||
91 | sdioh_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 | |||
153 | extern SDIOH_API_RC | ||
154 | sdioh_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 */ | ||
173 | extern SDIOH_API_RC | ||
174 | sdioh_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 | |||
185 | extern SDIOH_API_RC | ||
186 | sdioh_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 | |||
197 | extern SDIOH_API_RC | ||
198 | sdioh_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) | ||
208 | extern bool | ||
209 | sdioh_interrupt_pending(sdioh_info_t *sd) | ||
210 | { | ||
211 | return 0; | ||
212 | } | ||
213 | #endif | ||
214 | |||
215 | uint | ||
216 | sdioh_query_iofnum(sdioh_info_t *sd) | ||
217 | { | ||
218 | return sd->num_funcs; | ||
219 | } | ||
220 | |||
221 | /* IOVar table */ | ||
222 | enum { | ||
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 | |||
241 | const 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 | |||
260 | int | ||
261 | sdioh_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 | } | ||
511 | exit: | ||
512 | |||
513 | return bcmerror; | ||
514 | } | ||
515 | |||
516 | extern SDIOH_API_RC | ||
517 | sdioh_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 | |||
525 | extern SDIOH_API_RC | ||
526 | sdioh_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 | |||
534 | extern SDIOH_API_RC | ||
535 | sdioh_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 | |||
565 | extern SDIOH_API_RC | ||
566 | sdioh_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 | |||
605 | extern SDIOH_API_RC | ||
606 | sdioh_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 | |||
622 | extern SDIOH_API_RC | ||
623 | sdioh_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 | |||
670 | static int | ||
671 | sdspi_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 | |||
687 | extern int | ||
688 | sdioh_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 | |||
699 | int | ||
700 | sdioh_start(sdioh_info_t *sd, int stage) | ||
701 | { | ||
702 | return SUCCESS; | ||
703 | } | ||
704 | |||
705 | int | ||
706 | sdioh_stop(sdioh_info_t *sd) | ||
707 | { | ||
708 | return SUCCESS; | ||
709 | } | ||
710 | |||
711 | |||
712 | /* | ||
713 | * Private/Static work routines | ||
714 | */ | ||
715 | static bool | ||
716 | sdspi_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 | |||
739 | static int | ||
740 | sdspi_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 | |||
757 | static int | ||
758 | get_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 | |||
818 | static int | ||
819 | sdspi_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 | |||
836 | static int | ||
837 | sdspi_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 | |||
891 | static int | ||
892 | sdspi_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, ®data)) != 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, ®data)) != 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 | |||
950 | bool | ||
951 | sdspi_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 | |||
994 | static int | ||
995 | sdspi_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 | |||
1010 | static int | ||
1011 | sdspi_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, ®data)) != 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, ®data)) | ||
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 */ | ||
1067 | static int | ||
1068 | sdspi_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 */ | ||
1132 | static int | ||
1133 | sdspi_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 | |||
1187 | void | ||
1188 | sdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count /* num 32 bit words */) | ||
1189 | { | ||
1190 | *rsp_buffer = sd->card_response; | ||
1191 | } | ||
1192 | |||
1193 | int max_errors = 0; | ||
1194 | |||
1195 | #define SPI_MAX_PKT_LEN 768 | ||
1196 | uint8 spi_databuf[SPI_MAX_PKT_LEN]; | ||
1197 | uint8 spi_rspbuf[SPI_MAX_PKT_LEN]; | ||
1198 | |||
1199 | /* datalen is used for CMD53 length only (0 for sd->data_xfer_count) */ | ||
1200 | static int | ||
1201 | sdspi_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 | |||
1436 | static int | ||
1437 | sdspi_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 | |||
1518 | static int | ||
1519 | set_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 */ | ||
1545 | int | ||
1546 | sdioh_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 | |||
1555 | static 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 | |||
1579 | static 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 | |||
40 | extern uint sd_crc; | ||
41 | module_param(sd_crc, uint, 0); | ||
42 | |||
43 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) | ||
44 | #define KERNEL26 | ||
45 | #endif | ||
46 | |||
47 | struct 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 */ | ||
60 | static irqreturn_t | ||
61 | sdspi_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 */ | ||
91 | int | ||
92 | spi_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 */ | ||
103 | void | ||
104 | spi_free_irq(uint irq, sdioh_info_t *sd) | ||
105 | { | ||
106 | free_irq(irq, sd); | ||
107 | } | ||
108 | |||
109 | /* Map Host controller registers */ | ||
110 | |||
111 | uint32 * | ||
112 | spi_reg_map(osl_t *osh, uintptr addr, int size) | ||
113 | { | ||
114 | return (uint32 *)REG_MAP(addr, size); | ||
115 | } | ||
116 | |||
117 | void | ||
118 | spi_reg_unmap(osl_t *osh, uintptr addr, int size) | ||
119 | { | ||
120 | REG_UNMAP((void*)(uintptr)addr); | ||
121 | } | ||
122 | |||
123 | int | ||
124 | spi_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 | |||
139 | void | ||
140 | spi_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 */ | ||
150 | SDIOH_API_RC | ||
151 | sdioh_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) */ | ||
186 | void | ||
187 | spi_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 */ | ||
208 | void | ||
209 | spi_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 | |||
227 | void 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 */ | ||
47 | uint sd_msglevel = SDH_ERROR_VAL; | ||
48 | uint sd_hiok = TRUE; /* Use hi-speed mode if available? */ | ||
49 | uint sd_sdmode = SDIOH_MODE_SD4; /* Use SD4 mode by default */ | ||
50 | uint sd_f2_blocksize = 64; /* Default blocksize */ | ||
51 | |||
52 | #ifdef BCMSDYIELD | ||
53 | bool sd_yieldcpu = TRUE; /* Allow CPU yielding for buffer requests */ | ||
54 | uint sd_minyield = 0; /* Minimum xfer size to allow CPU yield */ | ||
55 | bool sd_forcerb = FALSE; /* Force sync readback in intrs_on/off */ | ||
56 | #endif | ||
57 | |||
58 | uint sd_divisor = 2; /* Default 48MHz/2 = 24MHz */ | ||
59 | |||
60 | uint sd_power = 1; /* Default to SD Slot powered ON */ | ||
61 | uint sd_clock = 1; /* Default to SD Clock turned ON */ | ||
62 | uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */ | ||
63 | uint8 sd_dma_mode = DMA_MODE_SDMA; /* Default to SDMA for now */ | ||
64 | |||
65 | uint sd_toctl = 7; | ||
66 | |||
67 | static bool trap_errs = FALSE; | ||
68 | |||
69 | static const char *dma_mode_description[] = { "PIO", "SDMA", "ADMA1", "32b ADMA2", "64b ADMA2" }; | ||
70 | |||
71 | /* Prototypes */ | ||
72 | static bool sdstd_start_clock(sdioh_info_t *sd, uint16 divisor); | ||
73 | static bool sdstd_start_power(sdioh_info_t *sd); | ||
74 | static bool sdstd_bus_width(sdioh_info_t *sd, int width); | ||
75 | static int sdstd_set_highspeed_mode(sdioh_info_t *sd, bool HSMode); | ||
76 | static int sdstd_set_dma_mode(sdioh_info_t *sd, int8 dma_mode); | ||
77 | static int sdstd_card_enablefuncs(sdioh_info_t *sd); | ||
78 | static void sdstd_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count); | ||
79 | static int sdstd_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg); | ||
80 | static int sdstd_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, | ||
81 | int regsize, uint32 *data); | ||
82 | static int sdstd_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, | ||
83 | int regsize, uint32 data); | ||
84 | static int sdstd_driver_init(sdioh_info_t *sd); | ||
85 | static bool sdstd_reset(sdioh_info_t *sd, bool host_reset, bool client_reset); | ||
86 | static int sdstd_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, | ||
87 | uint32 addr, int nbytes, uint32 *data); | ||
88 | static int sdstd_abort(sdioh_info_t *sd, uint func); | ||
89 | static int sdstd_check_errs(sdioh_info_t *sdioh_info, uint32 cmd, uint32 arg); | ||
90 | static int set_client_block_size(sdioh_info_t *sd, int func, int blocksize); | ||
91 | static void sd_map_dma(sdioh_info_t * sd); | ||
92 | static void sd_unmap_dma(sdioh_info_t * sd); | ||
93 | static void sd_clear_adma_dscr_buf(sdioh_info_t *sd); | ||
94 | static void sd_fill_dma_data_buf(sdioh_info_t *sd, uint8 data); | ||
95 | static void sd_create_adma_descriptor(sdioh_info_t *sd, | ||
96 | uint32 index, uint32 addr_phys, | ||
97 | uint16 length, uint16 flags); | ||
98 | static void sd_dump_adma_dscr(sdioh_info_t *sd); | ||
99 | static void sdstd_dumpregs(sdioh_info_t *sd); | ||
100 | |||
101 | |||
102 | /* | ||
103 | * Private register access routines. | ||
104 | */ | ||
105 | |||
106 | /* 16 bit PCI regs */ | ||
107 | |||
108 | extern uint16 sdstd_rreg16(sdioh_info_t *sd, uint reg); | ||
109 | uint16 | ||
110 | sdstd_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 | |||
118 | extern void sdstd_wreg16(sdioh_info_t *sd, uint reg, uint16 data); | ||
119 | void | ||
120 | sdstd_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 | |||
126 | static void | ||
127 | sdstd_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 | } | ||
135 | static void | ||
136 | sdstd_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 */ | ||
148 | static uint32 | ||
149 | sdstd_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 | } | ||
155 | static inline void | ||
156 | sdstd_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 */ | ||
164 | static inline void | ||
165 | sdstd_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 | } | ||
170 | static uint8 | ||
171 | sdstd_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 | |||
182 | sdioh_info_t *glob_sd; | ||
183 | |||
184 | /* | ||
185 | * Public entry points & extern's | ||
186 | */ | ||
187 | extern sdioh_info_t * | ||
188 | sdioh_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 | |||
268 | extern SDIOH_API_RC | ||
269 | sdioh_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 */ | ||
291 | extern SDIOH_API_RC | ||
292 | sdioh_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 | |||
301 | extern SDIOH_API_RC | ||
302 | sdioh_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 | |||
311 | extern SDIOH_API_RC | ||
312 | sdioh_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) | ||
320 | extern bool | ||
321 | sdioh_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 | |||
329 | uint | ||
330 | sdioh_query_iofnum(sdioh_info_t *sd) | ||
331 | { | ||
332 | return sd->num_funcs; | ||
333 | } | ||
334 | |||
335 | /* IOVar table */ | ||
336 | enum { | ||
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 | |||
357 | const 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 | |||
380 | int | ||
381 | sdioh_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 | } | ||
713 | exit: | ||
714 | |||
715 | return bcmerror; | ||
716 | } | ||
717 | |||
718 | extern SDIOH_API_RC | ||
719 | sdioh_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 | |||
727 | extern SDIOH_API_RC | ||
728 | sdioh_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 | |||
736 | extern SDIOH_API_RC | ||
737 | sdioh_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 | |||
767 | extern SDIOH_API_RC | ||
768 | sdioh_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 | |||
807 | extern SDIOH_API_RC | ||
808 | sdioh_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 | |||
830 | extern SDIOH_API_RC | ||
831 | sdioh_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 | |||
908 | static | ||
909 | int 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 | |||
1083 | done: | ||
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 | |||
1106 | extern int | ||
1107 | sdioh_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 | |||
1118 | int | ||
1119 | sdioh_start(sdioh_info_t *sd, int stage) | ||
1120 | { | ||
1121 | return SUCCESS; | ||
1122 | } | ||
1123 | |||
1124 | int | ||
1125 | sdioh_stop(sdioh_info_t *sd) | ||
1126 | { | ||
1127 | return SUCCESS; | ||
1128 | } | ||
1129 | |||
1130 | static int | ||
1131 | sdstd_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 | */ | ||
1192 | static bool | ||
1193 | sdstd_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 */ | ||
1234 | void | ||
1235 | sdstd_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 */ | ||
1246 | void | ||
1247 | sdstd_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 */ | ||
1264 | void | ||
1265 | sdstd_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 | |||
1278 | void | ||
1279 | sdstd_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 | |||
1293 | static int | ||
1294 | sdstd_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 | ||
1453 | static int | ||
1454 | get_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 | |||
1479 | static int | ||
1480 | sdstd_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 | |||
1608 | static int | ||
1609 | sdstd_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, ®data)) != 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, ®data)) != 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, ®data)) != 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 | */ | ||
1685 | static int | ||
1686 | sdstd_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 | |||
1761 | bool | ||
1762 | sdstd_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 | |||
1850 | bool | ||
1851 | sdstd_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 | |||
1922 | bool | ||
1923 | sdstd_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, ®data)) != 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 | |||
1962 | static int | ||
1963 | sdstd_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 | |||
1977 | static int | ||
1978 | sdstd_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, ®data)) != 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 | |||
1997 | static int | ||
1998 | sdstd_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 */ | ||
2029 | static int | ||
2030 | sdstd_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 | |||
2148 | bool | ||
2149 | check_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 | |||
2187 | void | ||
2188 | sdstd_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 */ | ||
2205 | static int | ||
2206 | sdstd_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 | |||
2308 | void | ||
2309 | sdstd_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 | |||
2323 | static int | ||
2324 | sdstd_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 | |||
2638 | static int | ||
2639 | sdstd_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 | |||
2870 | static int | ||
2871 | set_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 */ | ||
2897 | int | ||
2898 | sdioh_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 | |||
2918 | static void | ||
2919 | sd_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 | |||
2964 | static void | ||
2965 | sd_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 | |||
2978 | static 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 | |||
2984 | static 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 | |||
2990 | static 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 | |||
3031 | static 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 | |||
3116 | static 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 | |||
38 | struct 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 */ | ||
51 | static irqreturn_t | ||
52 | sdstd_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 */ | ||
81 | int | ||
82 | sdstd_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 */ | ||
93 | void | ||
94 | sdstd_free_irq(uint irq, sdioh_info_t *sd) | ||
95 | { | ||
96 | free_irq(irq, sd); | ||
97 | } | ||
98 | |||
99 | /* Map Host controller registers */ | ||
100 | |||
101 | uint32 * | ||
102 | sdstd_reg_map(osl_t *osh, int32 addr, int size) | ||
103 | { | ||
104 | return (uint32 *)REG_MAP(addr, size); | ||
105 | } | ||
106 | |||
107 | void | ||
108 | sdstd_reg_unmap(osl_t *osh, int32 addr, int size) | ||
109 | { | ||
110 | REG_UNMAP((void*)(uintptr)addr); | ||
111 | } | ||
112 | |||
113 | int | ||
114 | sdstd_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 | |||
129 | void | ||
130 | sdstd_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 */ | ||
140 | SDIOH_API_RC | ||
141 | sdioh_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) */ | ||
176 | void | ||
177 | sdstd_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 */ | ||
200 | void | ||
201 | sdstd_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 | |||
219 | uint16 | ||
220 | sdstd_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 */ | ||
55 | uint | ||
56 | pktcopy(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 */ | ||
87 | uint | ||
88 | pktfrombuf(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 */ | ||
118 | uint | ||
119 | pkttotlen(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 */ | ||
130 | void * | ||
131 | pktlast(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 */ | ||
140 | uint | ||
141 | pktsegcnt(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 | */ | ||
156 | void * | ||
157 | pktq_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 | |||
185 | void * | ||
186 | pktq_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 | |||
213 | void * | ||
214 | pktq_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 | |||
238 | void * | ||
239 | pktq_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 | |||
267 | void | ||
268 | pktq_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 | |||
287 | bool | ||
288 | pktq_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 | |||
320 | void | ||
321 | pktq_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 | |||
338 | void * | ||
339 | pktq_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 | |||
371 | void * | ||
372 | pktq_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 | |||
411 | void * | ||
412 | pktq_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 | |||
428 | void * | ||
429 | pktq_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 | |||
446 | void | ||
447 | pktq_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 */ | ||
456 | int | ||
457 | pktq_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 */ | ||
471 | void * | ||
472 | pktq_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 | |||
511 | const 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 | |||
547 | ulong | ||
548 | bcm_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 | |||
601 | int | ||
602 | bcm_atoi(char *s) | ||
603 | { | ||
604 | return (int)bcm_strtoul(s, NULL, 10); | ||
605 | } | ||
606 | |||
607 | /* return pointer to location of substring 'needle' in 'haystack' */ | ||
608 | char* | ||
609 | bcmstrstr(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 | |||
626 | char* | ||
627 | bcmstrcat(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 | |||
639 | char* | ||
640 | bcmstrncat(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 | */ | ||
674 | char * | ||
675 | bcmstrtok(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 | */ | ||
752 | int | ||
753 | bcmstricmp(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 | */ | ||
786 | int | ||
787 | bcmstrnicmp(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 */ | ||
808 | int | ||
809 | bcm_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 | */ | ||
828 | ulong | ||
829 | wchar2ascii(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 | |||
852 | char * | ||
853 | bcm_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 | |||
862 | char * | ||
863 | bcm_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 | |||
872 | void | ||
873 | bcm_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 */ | ||
889 | void | ||
890 | prpkt(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 | */ | ||
906 | uint | ||
907 | pktsetprio(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 | |||
968 | static char bcm_undeferrstr[BCME_STRLEN]; | ||
969 | |||
970 | static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; | ||
971 | |||
972 | /* Convert the error codes into related error strings */ | ||
973 | const char * | ||
974 | bcmerrorstr(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 */ | ||
992 | const bcm_iovar_t* | ||
993 | bcm_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 | |||
1016 | int | ||
1017 | bcm_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 | |||
1086 | STATIC 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 | |||
1124 | uint8 | ||
1125 | hndcrc8( | ||
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 | |||
1162 | static 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 | |||
1197 | uint16 | ||
1198 | hndcrc16( | ||
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 | |||
1209 | STATIC 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 | |||
1276 | uint32 | ||
1277 | hndcrc32( | ||
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 | |||
1323 | void 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 | */ | ||
1361 | bcm_tlv_t * | ||
1362 | bcm_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 | */ | ||
1387 | bcm_tlv_t * | ||
1388 | bcm_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 | */ | ||
1417 | bcm_tlv_t * | ||
1418 | bcm_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) | ||
1447 | int | ||
1448 | bcm_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 */ | ||
1495 | int | ||
1496 | bcm_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 */ | ||
1510 | void | ||
1511 | prhex(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 */ | ||
1539 | char * | ||
1540 | bcm_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 */ | ||
1553 | void | ||
1554 | printbig(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 */ | ||
1578 | uint | ||
1579 | bcmdumpfields(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 | |||
1605 | uint | ||
1606 | bcm_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 | |||
1644 | static 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 | |||
1653 | uint16 | ||
1654 | bcm_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 | |||
1678 | uint8 | ||
1679 | bcm_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 | |||
1710 | uint | ||
1711 | bcm_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 */ | ||
1728 | void | ||
1729 | bcm_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 */ | ||
1736 | int | ||
1737 | bcm_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 | |||
1761 | void | ||
1762 | bcm_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 | |||
1774 | int | ||
1775 | bcm_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 | |||
1786 | void | ||
1787 | bcm_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) | ||
1811 | int | ||
1812 | bcm_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 | |||
51 | char * | ||
52 | wf_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 | |||
83 | chanspec_t | ||
84 | wf_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 | |||
141 | done: | ||
142 | return (channel | band | bw | ctl_sb); | ||
143 | } | ||
144 | |||
145 | |||
146 | int | ||
147 | wf_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 | |||
185 | int | ||
186 | wf_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 */ | ||
74 | struct dhd_bus; | ||
75 | struct dhd_prot; | ||
76 | struct dhd_info; | ||
77 | |||
78 | /* The level of bus communication with the dongle */ | ||
79 | enum 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 | |||
85 | enum 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 | }; | ||
101 | enum 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 | ||
108 | extern void * dhd_os_prealloc(int section, unsigned long size); | ||
109 | #endif | ||
110 | /* Common structure for module and instance linkage */ | ||
111 | typedef 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 | |||
226 | inline 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 | |||
233 | inline 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 */ | ||
241 | extern int dhd_os_wake_lock(dhd_pub_t *pub); | ||
242 | extern int dhd_os_wake_unlock(dhd_pub_t *pub); | ||
243 | extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); | ||
244 | extern int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub); | ||
245 | |||
246 | extern void dhd_os_start_lock(dhd_pub_t *pub); | ||
247 | extern void dhd_os_start_unlock(dhd_pub_t *pub); | ||
248 | extern unsigned long dhd_os_spin_lock(dhd_pub_t *pub); | ||
249 | extern void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags); | ||
250 | |||
251 | typedef 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 */ | ||
263 | osl_t *dhd_osl_attach(void *pdev, uint bustype); | ||
264 | void 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 | */ | ||
271 | extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen, void *dev); | ||
272 | extern int dhd_net_attach(dhd_pub_t *dhdp, int idx); | ||
273 | |||
274 | /* Indication from bus module regarding removal/absence of dongle */ | ||
275 | extern void dhd_detach(dhd_pub_t *dhdp); | ||
276 | |||
277 | /* Indication from bus module to change flow-control state */ | ||
278 | extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); | ||
279 | |||
280 | extern 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. */ | ||
283 | extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt); | ||
284 | |||
285 | /* Return pointer to interface name */ | ||
286 | extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); | ||
287 | |||
288 | /* Request scheduling of the bus dpc */ | ||
289 | extern void dhd_sched_dpc(dhd_pub_t *dhdp); | ||
290 | |||
291 | /* Notify tx completion */ | ||
292 | extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); | ||
293 | |||
294 | /* Query ioctl */ | ||
295 | extern int dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); | ||
296 | |||
297 | /* OS independent layer functions */ | ||
298 | extern int dhd_os_proto_block(dhd_pub_t * pub); | ||
299 | extern int dhd_os_proto_unblock(dhd_pub_t * pub); | ||
300 | extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending); | ||
301 | extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub); | ||
302 | extern unsigned int dhd_os_get_ioctl_resp_timeout(void); | ||
303 | extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); | ||
304 | extern void * dhd_os_open_image(char * filename); | ||
305 | extern int dhd_os_get_image_block(char * buf, int len, void * image); | ||
306 | extern void dhd_os_close_image(void * image); | ||
307 | extern void dhd_os_wd_timer(void *bus, uint wdtick); | ||
308 | extern void dhd_os_sdlock(dhd_pub_t * pub); | ||
309 | extern void dhd_os_sdunlock(dhd_pub_t * pub); | ||
310 | extern void dhd_os_sdlock_txq(dhd_pub_t * pub); | ||
311 | extern void dhd_os_sdunlock_txq(dhd_pub_t * pub); | ||
312 | extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); | ||
313 | extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); | ||
314 | extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); | ||
315 | extern void dhd_customer_gpio_wlan_ctrl(int onoff); | ||
316 | extern int dhd_custom_get_mac_address(unsigned char *buf); | ||
317 | extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); | ||
318 | extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); | ||
319 | extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); | ||
320 | #ifdef DHD_DEBUG | ||
321 | extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); | ||
322 | #endif /* DHD_DEBUG */ | ||
323 | #if defined(OOB_INTR_ONLY) | ||
324 | extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr); | ||
325 | #endif /* defined(OOB_INTR_ONLY) */ | ||
326 | extern void dhd_os_sdtxlock(dhd_pub_t * pub); | ||
327 | extern void dhd_os_sdtxunlock(dhd_pub_t * pub); | ||
328 | |||
329 | int setScheduler(struct task_struct *p, int policy, struct sched_param *param); | ||
330 | |||
331 | typedef 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 | |||
338 | extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); | ||
339 | extern int dhd_timeout_expired(dhd_timeout_t *tmo); | ||
340 | |||
341 | extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); | ||
342 | extern uint8 *dhd_bssidx2bssid(dhd_pub_t *dhd, int idx); | ||
343 | extern int wl_host_event(struct dhd_info *dhd, int *idx, void *pktdata, | ||
344 | wl_event_msg_t *, void **data_ptr); | ||
345 | extern void wl_event_to_host_order(wl_event_msg_t * evt); | ||
346 | |||
347 | extern void dhd_common_init(void); | ||
348 | |||
349 | extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle, | ||
350 | char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx); | ||
351 | extern void dhd_del_if(struct dhd_info *dhd, int ifidx); | ||
352 | |||
353 | extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); | ||
354 | extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); | ||
355 | |||
356 | extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx); | ||
357 | extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); | ||
358 | |||
359 | |||
360 | /* Send packet to dongle via data channel */ | ||
361 | extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); | ||
362 | |||
363 | /* Send event to host */ | ||
364 | extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); | ||
365 | extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); | ||
366 | extern uint dhd_bus_status(dhd_pub_t *dhdp); | ||
367 | extern int dhd_bus_start(dhd_pub_t *dhdp); | ||
368 | |||
369 | extern void print_buf(void *pbuf, int len, int bytes_per_line); | ||
370 | |||
371 | |||
372 | typedef 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 | |||
379 | extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); | ||
380 | extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); | ||
381 | extern int net_os_send_hang_message(struct net_device *dev); | ||
382 | |||
383 | /* | ||
384 | * Insmod parameters for debug/test | ||
385 | */ | ||
386 | |||
387 | /* Watchdog timer interval */ | ||
388 | extern uint dhd_watchdog_ms; | ||
389 | |||
390 | #if defined(DHD_DEBUG) | ||
391 | /* Console output poll interval */ | ||
392 | extern uint dhd_console_ms; | ||
393 | #endif /* defined(DHD_DEBUG) */ | ||
394 | |||
395 | /* Use interrupts */ | ||
396 | extern uint dhd_intr; | ||
397 | |||
398 | /* Use polling */ | ||
399 | extern uint dhd_poll; | ||
400 | |||
401 | /* ARP offload agent mode */ | ||
402 | extern uint dhd_arp_mode; | ||
403 | |||
404 | /* ARP offload enable */ | ||
405 | extern uint dhd_arp_enable; | ||
406 | |||
407 | /* Pkt filte enable control */ | ||
408 | extern uint dhd_pkt_filter_enable; | ||
409 | |||
410 | /* Pkt filter init setup */ | ||
411 | extern uint dhd_pkt_filter_init; | ||
412 | |||
413 | /* Pkt filter mode control */ | ||
414 | extern uint dhd_master_mode; | ||
415 | |||
416 | /* Roaming mode control */ | ||
417 | extern uint dhd_roam; | ||
418 | |||
419 | /* Roaming mode control */ | ||
420 | extern uint dhd_radio_up; | ||
421 | |||
422 | /* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ | ||
423 | extern int dhd_idletime; | ||
424 | #define DHD_IDLETIME_TICKS 1 | ||
425 | |||
426 | /* SDIO Drive Strength */ | ||
427 | extern uint dhd_sdiod_drive_strength; | ||
428 | |||
429 | /* Override to force tx queueing all the time */ | ||
430 | extern 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 */ | ||
438 | extern uint dhd_pktgen; | ||
439 | |||
440 | /* Echo packet len (0 => sawtooth, max 1800) */ | ||
441 | extern 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 | ||
448 | extern char fw_path[MOD_PARAM_PATHLEN]; | ||
449 | extern 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 | |||
457 | extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); | ||
458 | extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); | ||
459 | |||
460 | /* dhd_commn arp offload wrapers */ | ||
461 | extern void dhd_arp_cleanup(dhd_pub_t *dhd); | ||
462 | int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen); | ||
463 | void 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 | ||
469 | extern int net_os_set_packet_filter(struct net_device *dev, int val); | ||
470 | extern 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. */ | ||
38 | extern int dhd_bus_register(void); | ||
39 | extern void dhd_bus_unregister(void); | ||
40 | |||
41 | /* Download firmware image and nvram image */ | ||
42 | extern 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 */ | ||
46 | extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); | ||
47 | |||
48 | /* Initialize bus module: prepare for communication w/dongle */ | ||
49 | extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex); | ||
50 | |||
51 | /* Send a data frame to the dongle. Callee disposes of txp. */ | ||
52 | extern 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 | */ | ||
57 | extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen); | ||
58 | extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen); | ||
59 | |||
60 | /* Watchdog timer function */ | ||
61 | extern bool dhd_bus_watchdog(dhd_pub_t *dhd); | ||
62 | |||
63 | #ifdef DHD_DEBUG | ||
64 | /* Device console input function */ | ||
65 | extern 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 */ | ||
69 | extern bool dhd_bus_dpc(struct dhd_bus *bus); | ||
70 | extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg); | ||
71 | |||
72 | |||
73 | /* Check for and handle local prot-specific iovar commands */ | ||
74 | extern 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 */ | ||
78 | extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); | ||
79 | |||
80 | /* Clear any bus counters */ | ||
81 | extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); | ||
82 | |||
83 | /* return the dongle chipid */ | ||
84 | extern uint dhd_bus_chip(struct dhd_bus *bus); | ||
85 | |||
86 | /* Set user-specified nvram parameters. */ | ||
87 | extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params); | ||
88 | |||
89 | extern void *dhd_bus_pub(struct dhd_bus *bus); | ||
90 | extern void *dhd_bus_txq(struct dhd_bus *bus); | ||
91 | extern 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 | |||
44 | extern 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 | |||
63 | typedef 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 | |||
72 | static int | ||
73 | dhdcdc_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 | |||
96 | static int | ||
97 | dhdcdc_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 | |||
113 | int | ||
114 | dhdcdc_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 | |||
158 | retry: | ||
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 | |||
194 | done: | ||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | int | ||
199 | dhdcdc_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 | |||
256 | done: | ||
257 | return ret; | ||
258 | } | ||
259 | |||
260 | extern int dhd_bus_interface(struct dhd_bus *bus, uint arg, void* arg2); | ||
261 | int | ||
262 | dhd_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 | |||
320 | done: | ||
321 | dhd_os_proto_unblock(dhd); | ||
322 | |||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | int | ||
327 | dhd_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 | |||
333 | void | ||
334 | dhd_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 | |||
340 | void | ||
341 | dhd_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 | |||
370 | bool | ||
371 | dhd_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 | |||
392 | int | ||
393 | dhd_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 | |||
438 | int | ||
439 | dhd_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 | |||
469 | fail: | ||
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? */ | ||
478 | void | ||
479 | dhd_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 | |||
487 | void | ||
488 | dhd_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 | |||
500 | int | ||
501 | dhd_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 | |||
531 | void | ||
532 | dhd_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 | ||
48 | int wifi_get_mac_addr(unsigned char *buf); | ||
49 | #endif /* GET_CUSTOM_MAC_ENABLE */ | ||
50 | |||
51 | int dhd_msg_level; | ||
52 | |||
53 | #include <wl_iw.h> | ||
54 | |||
55 | char fw_path[MOD_PARAM_PATHLEN]; | ||
56 | char nv_path[MOD_PARAM_PATHLEN]; | ||
57 | |||
58 | /* Last connection success/failure status */ | ||
59 | uint32 dhd_conn_event; | ||
60 | uint32 dhd_conn_status; | ||
61 | uint32 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 | |||
68 | extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); | ||
69 | extern void dhd_ind_scan_confirm(void *h, bool status); | ||
70 | extern int dhd_wl_ioctl(dhd_pub_t *dhd, uint cmd, char *buf, uint buflen); | ||
71 | void dhd_iscan_lock(void); | ||
72 | void dhd_iscan_unlock(void); | ||
73 | |||
74 | #if defined(SOFTAP) | ||
75 | extern bool ap_fw_loaded; | ||
76 | #endif | ||
77 | #if defined(KEEP_ALIVE) | ||
78 | int 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 | ||
90 | const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on " | ||
91 | __DATE__ " at " __TIME__; | ||
92 | #else | ||
93 | const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR; | ||
94 | #endif | ||
95 | |||
96 | void dhd_set_timer(void *bus, uint wdtick); | ||
97 | |||
98 | /* IOVar table */ | ||
99 | enum { | ||
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 | |||
119 | const 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 | |||
138 | void | ||
139 | dhd_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 | |||
160 | static int | ||
161 | dhd_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 | |||
214 | static int | ||
215 | dhd_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 | |||
321 | exit: | ||
322 | return bcmerror; | ||
323 | } | ||
324 | |||
325 | /* Store the status of a connection attempt for later retrieval by an iovar */ | ||
326 | void | ||
327 | dhd_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 | |||
341 | bool | ||
342 | dhd_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 | |||
394 | static int | ||
395 | dhd_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 | |||
441 | exit: | ||
442 | return bcmerror; | ||
443 | } | ||
444 | |||
445 | int | ||
446 | dhd_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 | ||
524 | static void | ||
525 | wl_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 | |||
814 | int | ||
815 | wl_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 | |||
916 | void | ||
917 | wl_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 | |||
931 | void 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 */ | ||
957 | static int | ||
958 | wl_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 | |||
981 | void | ||
982 | dhd_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 | |||
1050 | fail: | ||
1051 | if (arg_org) | ||
1052 | MFREE(dhd->osh, arg_org, strlen(arg) + 1); | ||
1053 | } | ||
1054 | |||
1055 | void | ||
1056 | dhd_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 | |||
1184 | fail: | ||
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 | ||
1194 | void | ||
1195 | dhd_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 | |||
1211 | void | ||
1212 | dhd_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 | |||
1230 | void 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 | |||
1254 | void 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 | |||
1278 | int 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 | |||
1305 | int | ||
1306 | dhd_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 | |||
1519 | uint iscan_thread_id; | ||
1520 | iscan_buf_t * iscan_chain = 0; | ||
1521 | |||
1522 | iscan_buf_t * | ||
1523 | dhd_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 | |||
1552 | fail: | ||
1553 | dhd_iscan_unlock(); | ||
1554 | return iscanbuf_alloc; | ||
1555 | } | ||
1556 | |||
1557 | void | ||
1558 | dhd_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 | |||
1596 | iscan_buf_t * | ||
1597 | dhd_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 | */ | ||
1608 | int | ||
1609 | dhd_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 | |||
1652 | done: | ||
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 | */ | ||
1660 | int | ||
1661 | dhd_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 | |||
1750 | done: | ||
1751 | dhd_iscan_unlock(); | ||
1752 | return 0; | ||
1753 | } | ||
1754 | |||
1755 | int | ||
1756 | dhd_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 | |||
1800 | done: | ||
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 | |||
1807 | void | ||
1808 | dhd_iscan_ind_scan_confirm(void *dhdp, bool status) | ||
1809 | { | ||
1810 | |||
1811 | dhd_ind_scan_confirm(dhdp, status); | ||
1812 | } | ||
1813 | |||
1814 | int | ||
1815 | dhd_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(¶ms, 0, sizeof(wl_iscan_params_t)); | ||
1824 | memcpy(¶ms.params.bssid, ðer_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 *)¶ms, 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 | |||
1845 | static int | ||
1846 | dhd_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 | |||
1893 | fail: | ||
1894 | return status; | ||
1895 | } | ||
1896 | |||
1897 | #endif | ||
1898 | |||
1899 | /* Function to estimate possible DTIM_SKIP value */ | ||
1900 | int 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 | |||
1946 | exit: | ||
1947 | return bcn_li_dtim; | ||
1948 | } | ||
1949 | |||
1950 | #ifdef PNO_SUPPORT | ||
1951 | int 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 | |||
1979 | int 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 */ | ||
2021 | int | ||
2022 | dhd_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 | |||
2123 | int 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) | ||
2136 | int 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 | */ | ||
2188 | int | ||
2189 | wl_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 | */ | ||
2237 | int | ||
2238 | wl_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 | */ | ||
2284 | int | ||
2285 | wl_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 | */ | ||
2357 | int | ||
2358 | wl_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 | */ | ||
2397 | int | ||
2398 | wl_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 | ||
42 | extern void bcm_wlan_power_off(int); | ||
43 | extern void bcm_wlan_power_on(int); | ||
44 | #endif /* CUSTOMER_HW */ | ||
45 | #ifdef CUSTOMER_HW2 | ||
46 | int wifi_set_carddetect(int on); | ||
47 | int wifi_set_power(int on, unsigned long msec); | ||
48 | int wifi_get_irq_number(unsigned long *irq_flags_ptr); | ||
49 | int wifi_get_mac_addr(unsigned char *buf); | ||
50 | void *wifi_get_country_code(char *ccode); | ||
51 | #endif | ||
52 | |||
53 | #if defined(OOB_INTR_ONLY) | ||
54 | |||
55 | #if defined(BCMLXSDMMC) | ||
56 | extern 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 */ | ||
64 | static int dhd_oob_gpio_num = -1; /* GG 19 */ | ||
65 | |||
66 | module_param(dhd_oob_gpio_num, int, 0644); | ||
67 | MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); | ||
68 | |||
69 | int 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 */ | ||
106 | void | ||
107 | dhd_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 */ | ||
156 | int | ||
157 | dhd_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 */ | ||
183 | const 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 | */ | ||
236 | void 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) | ||
95 | extern 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> | ||
68 | static struct wifi_platform_data *wifi_control_data = NULL; | ||
69 | #endif | ||
70 | struct semaphore wifi_control_sem; | ||
71 | |||
72 | static struct resource *wifi_irqres = NULL; | ||
73 | |||
74 | int 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 | |||
87 | int 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 | |||
98 | int 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 | |||
111 | int 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 | |||
124 | int 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 | |||
137 | void *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 | |||
150 | static 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 | |||
169 | static 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 | |||
185 | static 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 | } | ||
193 | static 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 | |||
202 | static 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 | |||
212 | int wifi_add_dev(void) | ||
213 | { | ||
214 | DHD_TRACE(("## Calling platform_driver_register\n")); | ||
215 | return platform_driver_register(&wifi_device); | ||
216 | } | ||
217 | |||
218 | void 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 | |||
225 | static int dhd_device_event(struct notifier_block *this, unsigned long event, | ||
226 | void *ptr); | ||
227 | |||
228 | static 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> | ||
234 | volatile bool dhd_mmc_suspend = FALSE; | ||
235 | DECLARE_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) | ||
239 | extern 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)) | ||
242 | MODULE_LICENSE("GPL v2"); | ||
243 | #endif /* LinuxVer */ | ||
244 | |||
245 | #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) | ||
246 | const char * | ||
247 | print_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 | |||
258 | extern 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 | ||
265 | extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); | ||
266 | extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); | ||
267 | #endif | ||
268 | |||
269 | /* Interface control information */ | ||
270 | typedef 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) */ | ||
285 | typedef 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 | */ | ||
344 | char firmware_path[MOD_PARAM_PATHLEN]; | ||
345 | char nvram_path[MOD_PARAM_PATHLEN]; | ||
346 | |||
347 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) | ||
348 | struct 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 */ | ||
352 | module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0); | ||
353 | module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); | ||
354 | |||
355 | /* Error bits */ | ||
356 | module_param(dhd_msg_level, int, 0); | ||
357 | |||
358 | /* Spawn a thread for system ioctls (set mac, set mcast) */ | ||
359 | uint dhd_sysioc = TRUE; | ||
360 | module_param(dhd_sysioc, uint, 0); | ||
361 | |||
362 | /* Watchdog interval */ | ||
363 | uint dhd_watchdog_ms = 10; | ||
364 | module_param(dhd_watchdog_ms, uint, 0); | ||
365 | |||
366 | #ifdef DHD_DEBUG | ||
367 | /* Console poll interval */ | ||
368 | uint dhd_console_ms = 0; | ||
369 | module_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 */ | ||
373 | uint dhd_arp_mode = 0xb; | ||
374 | module_param(dhd_arp_mode, uint, 0); | ||
375 | |||
376 | /* ARP offload enable */ | ||
377 | uint dhd_arp_enable = TRUE; | ||
378 | module_param(dhd_arp_enable, uint, 0); | ||
379 | |||
380 | /* Global Pkt filter enable control */ | ||
381 | uint dhd_pkt_filter_enable = TRUE; | ||
382 | module_param(dhd_pkt_filter_enable, uint, 0); | ||
383 | |||
384 | /* Pkt filter init setup */ | ||
385 | uint dhd_pkt_filter_init = 0; | ||
386 | module_param(dhd_pkt_filter_init, uint, 0); | ||
387 | |||
388 | /* Pkt filter mode control */ | ||
389 | uint dhd_master_mode = TRUE; | ||
390 | module_param(dhd_master_mode, uint, 1); | ||
391 | |||
392 | /* Watchdog thread priority, -1 to use kernel timer */ | ||
393 | int dhd_watchdog_prio = 97; | ||
394 | module_param(dhd_watchdog_prio, int, 0); | ||
395 | |||
396 | /* DPC thread priority, -1 to use tasklet */ | ||
397 | int dhd_dpc_prio = 98; | ||
398 | module_param(dhd_dpc_prio, int, 0); | ||
399 | |||
400 | /* DPC thread priority, -1 to use tasklet */ | ||
401 | extern int dhd_dongle_memsize; | ||
402 | module_param(dhd_dongle_memsize, int, 0); | ||
403 | |||
404 | /* Control fw roaming */ | ||
405 | #ifdef CUSTOMER_HW2 | ||
406 | uint dhd_roam = 0; | ||
407 | #else | ||
408 | uint dhd_roam = 1; | ||
409 | #endif | ||
410 | |||
411 | /* Control radio state */ | ||
412 | uint dhd_radio_up = 1; | ||
413 | |||
414 | /* Network inteface name */ | ||
415 | char iface_name[IFNAMSIZ]; | ||
416 | module_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 */ | ||
440 | int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; | ||
441 | |||
442 | /* Idle timeout for backplane clock */ | ||
443 | int dhd_idletime = DHD_IDLETIME_TICKS; | ||
444 | module_param(dhd_idletime, int, 0); | ||
445 | |||
446 | /* Use polling */ | ||
447 | uint dhd_poll = FALSE; | ||
448 | module_param(dhd_poll, uint, 0); | ||
449 | |||
450 | /* Use interrupts */ | ||
451 | uint dhd_intr = TRUE; | ||
452 | module_param(dhd_intr, uint, 0); | ||
453 | |||
454 | /* SDIO Drive Strength (in milliamps) */ | ||
455 | uint dhd_sdiod_drive_strength = 6; | ||
456 | module_param(dhd_sdiod_drive_strength, uint, 0); | ||
457 | |||
458 | /* Tx/Rx bounds */ | ||
459 | extern uint dhd_txbound; | ||
460 | extern uint dhd_rxbound; | ||
461 | module_param(dhd_txbound, uint, 0); | ||
462 | module_param(dhd_rxbound, uint, 0); | ||
463 | |||
464 | /* Deferred transmits */ | ||
465 | extern uint dhd_deferred_tx; | ||
466 | module_param(dhd_deferred_tx, uint, 0); | ||
467 | |||
468 | |||
469 | |||
470 | #ifdef SDTEST | ||
471 | /* Echo packet generator (pkts/s) */ | ||
472 | uint dhd_pktgen = 0; | ||
473 | module_param(dhd_pktgen, uint, 0); | ||
474 | |||
475 | /* Echo packet len (0 => sawtooth, max 2040) */ | ||
476 | uint dhd_pktgen_len = 0; | ||
477 | module_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 | |||
490 | static 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) | ||
498 | struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); | ||
499 | #endif /* defined(CONFIG_WIRELESS_EXT) */ | ||
500 | |||
501 | static void dhd_dpc(ulong data); | ||
502 | /* forward decl */ | ||
503 | extern int dhd_wait_pend8021x(struct net_device *dev); | ||
504 | |||
505 | #ifdef TOE | ||
506 | #ifndef BDC | ||
507 | #error TOE requires BDC | ||
508 | #endif /* !BDC */ | ||
509 | static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); | ||
510 | static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); | ||
511 | #endif /* TOE */ | ||
512 | |||
513 | static 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) | ||
517 | static 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 | |||
537 | static struct notifier_block dhd_sleep_pm_notifier = { | ||
538 | .notifier_call = dhd_sleep_pm_callback, | ||
539 | .priority = 0 | ||
540 | }; | ||
541 | extern int register_pm_notifier(struct notifier_block *nb); | ||
542 | extern int unregister_pm_notifier(struct notifier_block *nb); | ||
543 | #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ | ||
544 | |||
545 | static 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) | ||
566 | static 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 | |||
633 | static 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 | |||
647 | static 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 | |||
657 | static 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 | |||
680 | void | ||
681 | dhd_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 | |||
689 | int | ||
690 | dhd_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 | |||
727 | static int | ||
728 | dhd_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 | |||
742 | int | ||
743 | dhd_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 | |||
761 | char * | ||
762 | dhd_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 | |||
784 | static 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 | |||
913 | static 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 | ||
942 | extern struct net_device *ap_net_dev; | ||
943 | /* semaphore that the soft AP CODE waits on */ | ||
944 | extern struct semaphore ap_eth_sema; | ||
945 | #endif | ||
946 | |||
947 | static void | ||
948 | dhd_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 | |||
1031 | static 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 | |||
1091 | static int | ||
1092 | dhd_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 | |||
1113 | static void | ||
1114 | dhd_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 | |||
1129 | int | ||
1130 | dhd_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 | |||
1168 | static int | ||
1169 | dhd_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 | |||
1230 | done: | ||
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 | |||
1242 | void | ||
1243 | dhd_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 | |||
1259 | void | ||
1260 | dhd_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 | |||
1357 | void | ||
1358 | dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) | ||
1359 | { | ||
1360 | /* Linux version has nothing to do */ | ||
1361 | return; | ||
1362 | } | ||
1363 | |||
1364 | void | ||
1365 | dhd_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 | |||
1382 | static struct net_device_stats * | ||
1383 | dhd_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 | |||
1417 | static int | ||
1418 | dhd_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, ¶m); | ||
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 | |||
1462 | static void | ||
1463 | dhd_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 | |||
1492 | static int | ||
1493 | dhd_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, ¶m); | ||
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 | |||
1535 | static void | ||
1536 | dhd_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 | |||
1551 | void | ||
1552 | dhd_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 */ | ||
1567 | static int | ||
1568 | dhd_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 */ | ||
1599 | static int | ||
1600 | dhd_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) | ||
1641 | static 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 | |||
1650 | struct 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) | ||
1657 | static int | ||
1658 | dhd_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 | |||
1767 | static int | ||
1768 | dhd_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 | |||
1896 | done: | ||
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 | |||
1916 | static int | ||
1917 | dhd_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 | |||
1938 | static int | ||
1939 | dhd_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 | |||
1983 | osl_t * | ||
1984 | dhd_osl_attach(void *pdev, uint bustype) | ||
1985 | { | ||
1986 | return osl_attach(pdev, bustype, TRUE); | ||
1987 | } | ||
1988 | |||
1989 | void | ||
1990 | dhd_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 | |||
2001 | int | ||
2002 | dhd_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 | |||
2036 | void | ||
2037 | dhd_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 | |||
2057 | dhd_pub_t * | ||
2058 | dhd_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 | |||
2218 | fail: | ||
2219 | if (net) | ||
2220 | free_netdev(net); | ||
2221 | if (dhd) | ||
2222 | dhd_detach(&dhd->pub); | ||
2223 | |||
2224 | return NULL; | ||
2225 | } | ||
2226 | |||
2227 | |||
2228 | int | ||
2229 | dhd_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 | |||
2335 | int | ||
2336 | dhd_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)) | ||
2360 | static 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 | |||
2370 | static 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 | |||
2379 | static 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 | |||
2421 | int | ||
2422 | dhd_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 | |||
2512 | fail: | ||
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 | |||
2521 | void | ||
2522 | dhd_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 | |||
2547 | void | ||
2548 | dhd_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 | |||
2630 | static void __exit | ||
2631 | dhd_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 | |||
2643 | static int __init | ||
2644 | dhd_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)) | ||
2710 | fail_2: | ||
2711 | dhd_bus_unregister(); | ||
2712 | #endif | ||
2713 | fail_1: | ||
2714 | #if defined(CUSTOMER_HW2) && defined(CONFIG_WIFI_CONTROL_FUNC) | ||
2715 | wifi_del_dev(); | ||
2716 | fail_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 | |||
2725 | module_init(dhd_module_init); | ||
2726 | module_exit(dhd_module_cleanup); | ||
2727 | |||
2728 | /* | ||
2729 | * OS specific functions required to implement DHD driver in OS independent way | ||
2730 | */ | ||
2731 | int | ||
2732 | dhd_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 | |||
2744 | int | ||
2745 | dhd_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 | |||
2757 | unsigned int | ||
2758 | dhd_os_get_ioctl_resp_timeout(void) | ||
2759 | { | ||
2760 | return ((unsigned int)dhd_ioctl_timeout_msec); | ||
2761 | } | ||
2762 | |||
2763 | void | ||
2764 | dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) | ||
2765 | { | ||
2766 | dhd_ioctl_timeout_msec = (int)timeout_msec; | ||
2767 | } | ||
2768 | |||
2769 | int | ||
2770 | dhd_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 | |||
2798 | int | ||
2799 | dhd_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 | |||
2810 | void | ||
2811 | dhd_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 | |||
2839 | void * | ||
2840 | dhd_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 | |||
2857 | int | ||
2858 | dhd_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 | |||
2873 | void | ||
2874 | dhd_os_close_image(void *image) | ||
2875 | { | ||
2876 | if (image) | ||
2877 | filp_close((struct file *)image, NULL); | ||
2878 | } | ||
2879 | |||
2880 | |||
2881 | void | ||
2882 | dhd_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 | |||
2894 | void | ||
2895 | dhd_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 | |||
2907 | void | ||
2908 | dhd_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 | |||
2916 | void | ||
2917 | dhd_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 | } | ||
2924 | void | ||
2925 | dhd_os_sdlock_rxq(dhd_pub_t *pub) | ||
2926 | { | ||
2927 | } | ||
2928 | void | ||
2929 | dhd_os_sdunlock_rxq(dhd_pub_t *pub) | ||
2930 | { | ||
2931 | } | ||
2932 | |||
2933 | void | ||
2934 | dhd_os_sdtxlock(dhd_pub_t *pub) | ||
2935 | { | ||
2936 | dhd_os_sdlock(pub); | ||
2937 | } | ||
2938 | |||
2939 | void | ||
2940 | dhd_os_sdtxunlock(dhd_pub_t *pub) | ||
2941 | { | ||
2942 | dhd_os_sdunlock(pub); | ||
2943 | } | ||
2944 | |||
2945 | #ifdef DHD_USE_STATIC_BUF | ||
2946 | void * 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 | ||
2964 | return 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) | ||
2969 | struct iw_statistics * | ||
2970 | dhd_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 | |||
2984 | static int | ||
2985 | dhd_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 */ | ||
3016 | void | ||
3017 | dhd_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 | |||
3025 | void 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 | |||
3036 | void 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 | |||
3046 | int | ||
3047 | dhd_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 | |||
3063 | int 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 | |||
3075 | int 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 | |||
3090 | int 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 | |||
3100 | int 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 | |||
3129 | int 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 | |||
3151 | void | ||
3152 | dhd_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 */ | ||
3161 | int | ||
3162 | dhd_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 */ | ||
3171 | int | ||
3172 | dhd_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 */ | ||
3181 | int | ||
3182 | dhd_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 */ | ||
3191 | int | ||
3192 | dhd_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 | |||
3201 | int 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 | |||
3215 | void 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 | |||
3223 | char *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 | |||
3232 | void 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 | |||
3242 | void 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 | |||
3252 | static int | ||
3253 | dhd_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 | |||
3260 | int | ||
3261 | dhd_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 | ||
3281 | int | ||
3282 | write_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 | |||
3304 | exit: | ||
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 | |||
3317 | int 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 | |||
3337 | int 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 | |||
3347 | int 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 | |||
3361 | int 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 | |||
3371 | int 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 | |||
3391 | int 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 | |||
3401 | int 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 | |||
3424 | int 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 | |||
3434 | unsigned 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 | |||
3445 | void 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 | |||
31 | int 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 */ | ||
49 | extern int dhd_prot_attach(dhd_pub_t *dhdp); | ||
50 | |||
51 | /* Unlink, frees allocated protocol memory (including dhd_prot) */ | ||
52 | extern 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 | */ | ||
57 | extern int dhd_prot_init(dhd_pub_t *dhdp); | ||
58 | |||
59 | /* Stop protocol: sync w/dongle state. */ | ||
60 | extern void dhd_prot_stop(dhd_pub_t *dhdp); | ||
61 | |||
62 | extern 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 | */ | ||
67 | extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp); | ||
68 | |||
69 | /* Remove any protocol-specific data header. */ | ||
70 | extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp); | ||
71 | |||
72 | /* Use protocol to issue ioctl to dongle */ | ||
73 | extern 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 */ | ||
76 | extern 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 */ | ||
80 | extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); | ||
81 | |||
82 | /* Update local copy of dongle statistics */ | ||
83 | extern void dhd_prot_dstats(dhd_pub_t *dhdp); | ||
84 | |||
85 | extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen); | ||
86 | |||
87 | extern 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); | ||
150 | DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); | ||
151 | extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); | ||
152 | |||
153 | extern void bcmsdh_set_irq(int flag); | ||
154 | |||
155 | #ifdef DHD_DEBUG | ||
156 | /* Device console log buffer state */ | ||
157 | typedef 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 */ | ||
168 | typedef 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 | ||
315 | static int qcount[NUMPRIO]; | ||
316 | static int tx_packets[NUMPRIO]; | ||
317 | #endif /* DHD_DEBUG */ | ||
318 | |||
319 | /* Deferred transmit */ | ||
320 | const uint dhd_deferred_tx = 1; | ||
321 | |||
322 | extern uint dhd_watchdog_ms; | ||
323 | extern void dhd_os_wd_timer(void *bus, uint wdtick); | ||
324 | |||
325 | /* Tx/Rx bounds */ | ||
326 | uint dhd_txbound; | ||
327 | uint dhd_rxbound; | ||
328 | uint dhd_txminmax; | ||
329 | |||
330 | /* override the RAM size if possible */ | ||
331 | #define DONGLE_MIN_MEMSIZE (128 *1024) | ||
332 | int dhd_dongle_memsize; | ||
333 | |||
334 | static bool dhd_doflow; | ||
335 | static bool dhd_alignctl; | ||
336 | |||
337 | static bool sd1idle; | ||
338 | |||
339 | static bool retrydata; | ||
340 | #define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) | ||
341 | |||
342 | static const uint watermark = 8; | ||
343 | static const uint firstread = DHD_FIRSTREAD; | ||
344 | |||
345 | #define HDATLEN (firstread - (SDPCM_HDRLEN)) | ||
346 | |||
347 | /* Retry count for register access failures */ | ||
348 | static const uint retry_limit = 2; | ||
349 | |||
350 | /* Force even SD lengths (some host controllers mess up on odd bytes) */ | ||
351 | static bool forcealign; | ||
352 | |||
353 | #define ALIGNMENT 4 | ||
354 | |||
355 | #if defined(OOB_INTR_ONLY) && defined(HW_OOB) | ||
356 | extern 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 */ | ||
375 | static const uint max_roundup = 512; | ||
376 | |||
377 | /* Try doing readahead */ | ||
378 | static 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) \ | ||
389 | do { \ | ||
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) \ | ||
405 | do { \ | ||
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 | ||
429 | static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); | ||
430 | static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start); | ||
431 | #endif | ||
432 | |||
433 | #ifdef DHD_DEBUG_TRAP | ||
434 | static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size); | ||
435 | #endif /* DHD_DEBUG_TRAP */ | ||
436 | static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); | ||
437 | |||
438 | static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); | ||
439 | static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh); | ||
440 | static void dhdsdio_disconnect(void *ptr); | ||
441 | static bool dhdsdio_chipmatch(uint16 chipid); | ||
442 | static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, | ||
443 | void * regsva, uint16 devid); | ||
444 | static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); | ||
445 | static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); | ||
446 | static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, int reset_flag); | ||
447 | |||
448 | static uint process_nvram_vars(char *varbuf, uint len); | ||
449 | |||
450 | static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size); | ||
451 | static 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); | ||
454 | static 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 | |||
458 | static bool dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh); | ||
459 | static int _dhdsdio_download_firmware(struct dhd_bus *bus); | ||
460 | |||
461 | static int dhdsdio_download_code_file(struct dhd_bus *bus, char *image_path); | ||
462 | static int dhdsdio_download_nvram(struct dhd_bus *bus); | ||
463 | #ifdef BCMEMBEDIMAGE | ||
464 | static int dhdsdio_download_code_array(struct dhd_bus *bus); | ||
465 | #endif | ||
466 | |||
467 | |||
468 | static void | ||
469 | dhd_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 | |||
480 | static int | ||
481 | dhdsdio_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 */ | ||
497 | static int | ||
498 | dhdsdio_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 */ | ||
624 | static int | ||
625 | dhdsdio_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 */ | ||
710 | static int | ||
711 | dhdsdio_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 | |||
771 | int | ||
772 | dhdsdio_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, ®s->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, ®s->tosbmailboxdata, retries); | ||
835 | if (retries <= retry_limit) | ||
836 | W_SDREG(SMB_DEV_INT, ®s->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) | ||
857 | void | ||
858 | dhd_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, ®s->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, ®s->tosbmailboxdata, retries); | ||
877 | if (retries <= retry_limit) | ||
878 | W_SDREG(SMB_DEV_INT, ®s->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 */ | ||
896 | static int | ||
897 | dhdsdio_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 | |||
1035 | done: | ||
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 | |||
1048 | int | ||
1049 | dhd_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 | |||
1147 | static uint | ||
1148 | dhdsdio_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, ®s->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 | |||
1207 | int | ||
1208 | dhd_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 | |||
1354 | int | ||
1355 | dhd_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 */ | ||
1406 | enum { | ||
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 | |||
1441 | const 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 | |||
1479 | static void | ||
1480 | dhd_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 | |||
1493 | void | ||
1494 | dhd_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 | |||
1575 | void | ||
1576 | dhd_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 | ||
1589 | static int | ||
1590 | dhdsdio_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 | |||
1612 | static int | ||
1613 | dhdsdio_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 | |||
1646 | static int | ||
1647 | dhdsdio_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 | |||
1689 | xfer_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 | ||
1700 | static int | ||
1701 | dhdsdio_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 | |||
1747 | static int | ||
1748 | dhdsdio_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 | |||
1852 | done: | ||
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 | |||
1865 | static int | ||
1866 | dhdsdio_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 | } | ||
1930 | break2: | ||
1931 | |||
1932 | return BCME_OK; | ||
1933 | } | ||
1934 | #endif /* DHD_DEBUG */ | ||
1935 | |||
1936 | int | ||
1937 | dhdsdio_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); | ||
1966 | err: | ||
1967 | return bcmerror; | ||
1968 | } | ||
1969 | |||
1970 | static int | ||
1971 | dhdsdio_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 | |||
2356 | exit: | ||
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 | |||
2370 | static int | ||
2371 | dhdsdio_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 | |||
2453 | static int | ||
2454 | dhdsdio_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 | |||
2544 | fail: | ||
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 | |||
2552 | int | ||
2553 | dhd_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 | |||
2653 | exit: | ||
2654 | return bcmerror; | ||
2655 | } | ||
2656 | |||
2657 | void | ||
2658 | dhd_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 | |||
2729 | int | ||
2730 | dhd_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; | ||
2829 | exit: | ||
2830 | if (enforce_mutex) | ||
2831 | dhd_os_sdunlock(bus->dhd); | ||
2832 | |||
2833 | return ret; | ||
2834 | } | ||
2835 | |||
2836 | static void | ||
2837 | dhdsdio_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, ®s->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 | |||
2895 | static void | ||
2896 | dhdsdio_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 | |||
2978 | gotpkt: | ||
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 | |||
2990 | done: | ||
2991 | /* Awake any waiters */ | ||
2992 | dhd_os_ioctl_resp_wake(bus->dhd); | ||
2993 | } | ||
2994 | |||
2995 | static uint8 | ||
2996 | dhdsdio_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 */ | ||
3378 | static uint | ||
3379 | dhdsdio_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 | |||
3887 | deliver: | ||
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 | |||
3957 | static uint32 | ||
3958 | dhdsdio_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, ®s->tohostmailboxdata, retries); | ||
3970 | if (retries <= retry_limit) | ||
3971 | W_SDREG(SMB_INT_ACK, ®s->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 | |||
4026 | bool | ||
4027 | dhdsdio_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, ®s->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, ®s->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, ®s->intstatus, retries); | ||
4124 | R_SDREG(newstatus, ®s->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 | |||
4179 | clkwait: | ||
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 | |||
4273 | bool | ||
4274 | dhd_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 | |||
4285 | void | ||
4286 | dhdsdio_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 | ||
4336 | static void | ||
4337 | dhdsdio_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 | |||
4359 | static void | ||
4360 | dhdsdio_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 | |||
4458 | static void | ||
4459 | dhdsdio_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 | |||
4485 | static void | ||
4486 | dhdsdio_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 | |||
4577 | extern bool | ||
4578 | dhd_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 | ||
4666 | extern int | ||
4667 | dhd_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 | |||
4716 | done: | ||
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 | ||
4729 | static void | ||
4730 | dhd_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 | |||
4758 | static bool | ||
4759 | dhdsdio_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 | |||
4772 | static void * | ||
4773 | dhdsdio_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 | |||
4932 | fail: | ||
4933 | dhdsdio_release(bus, osh); | ||
4934 | return NULL; | ||
4935 | } | ||
4936 | |||
4937 | |||
4938 | static bool | ||
4939 | dhdsdio_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 | |||
5083 | fail: | ||
5084 | return FALSE; | ||
5085 | } | ||
5086 | |||
5087 | static bool | ||
5088 | dhdsdio_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 | |||
5135 | fail: | ||
5136 | return FALSE; | ||
5137 | } | ||
5138 | |||
5139 | |||
5140 | static bool | ||
5141 | dhdsdio_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 | |||
5213 | bool | ||
5214 | dhd_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 | |||
5226 | static bool | ||
5227 | dhdsdio_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 */ | ||
5243 | static void | ||
5244 | dhdsdio_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 | |||
5276 | static void | ||
5277 | dhdsdio_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 | |||
5301 | static void | ||
5302 | dhdsdio_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 | |||
5324 | static void | ||
5325 | dhdsdio_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 | |||
5345 | static bcmsdh_driver_t dhd_sdio = { | ||
5346 | dhdsdio_probe, | ||
5347 | dhdsdio_disconnect | ||
5348 | }; | ||
5349 | |||
5350 | int | ||
5351 | dhd_bus_register(void) | ||
5352 | { | ||
5353 | DHD_TRACE(("%s: Enter\n", __FUNCTION__)); | ||
5354 | |||
5355 | return bcmsdh_register(&dhd_sdio); | ||
5356 | } | ||
5357 | |||
5358 | void | ||
5359 | dhd_bus_unregister(void) | ||
5360 | { | ||
5361 | DHD_TRACE(("%s: Enter\n", __FUNCTION__)); | ||
5362 | |||
5363 | bcmsdh_unregister(); | ||
5364 | } | ||
5365 | |||
5366 | #ifdef BCMEMBEDIMAGE | ||
5367 | static int | ||
5368 | dhdsdio_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 | |||
5438 | err: | ||
5439 | return bcmerror; | ||
5440 | } | ||
5441 | #endif /* BCMEMBEDIMAGE */ | ||
5442 | |||
5443 | static int | ||
5444 | dhdsdio_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 | |||
5478 | err: | ||
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 | |||
5494 | static uint | ||
5495 | process_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 | |||
5551 | void | ||
5552 | dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params) | ||
5553 | { | ||
5554 | bus->nvram_params = nvram_params; | ||
5555 | } | ||
5556 | |||
5557 | static int | ||
5558 | dhdsdio_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 | |||
5618 | err: | ||
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 | |||
5628 | static 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 | |||
5699 | err: | ||
5700 | return bcmerror; | ||
5701 | } | ||
5702 | |||
5703 | static int | ||
5704 | dhd_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 | |||
5714 | static int | ||
5715 | dhd_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 | |||
5721 | uint | ||
5722 | dhd_bus_chip(struct dhd_bus *bus) | ||
5723 | { | ||
5724 | ASSERT(bus->sih != NULL); | ||
5725 | return bus->sih->chip; | ||
5726 | } | ||
5727 | |||
5728 | void * | ||
5729 | dhd_bus_pub(struct dhd_bus *bus) | ||
5730 | { | ||
5731 | return bus->dhd; | ||
5732 | } | ||
5733 | |||
5734 | void * | ||
5735 | dhd_bus_txq(struct dhd_bus *bus) | ||
5736 | { | ||
5737 | return &bus->txq; | ||
5738 | } | ||
5739 | |||
5740 | uint | ||
5741 | dhd_bus_hdrlen(struct dhd_bus *bus) | ||
5742 | { | ||
5743 | return SDPCM_HDRLEN; | ||
5744 | } | ||
5745 | |||
5746 | int | ||
5747 | dhd_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 | |||
31 | typedef 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 */ | ||
45 | typedef 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 */ | ||
51 | static 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 */ | ||
58 | static 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 | |||
69 | void | ||
70 | si_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 | |||
9 | SRCBASE = .. | ||
10 | |||
11 | TARGETS = epivers.h | ||
12 | |||
13 | |||
14 | all release: | ||
15 | bash epivers.sh | ||
16 | |||
17 | clean: | ||
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 | |||
117 | typedef 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 | |||
31 | typedef 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 | |||
95 | struct 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 | |||
54 | static INLINE uint16 | ||
55 | bcmswap16(uint16 val) | ||
56 | { | ||
57 | return BCMSWAP16(val); | ||
58 | } | ||
59 | |||
60 | static INLINE uint32 | ||
61 | bcmswap32(uint32 val) | ||
62 | { | ||
63 | return BCMSWAP32(val); | ||
64 | } | ||
65 | |||
66 | static INLINE uint32 | ||
67 | bcmswap32by16(uint32 val) | ||
68 | { | ||
69 | return BCMSWAP32BY16(val); | ||
70 | } | ||
71 | |||
72 | |||
73 | |||
74 | |||
75 | static INLINE void | ||
76 | bcmswap16_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 | |||
125 | static INLINE void | ||
126 | htol16_ua_store(uint16 val, uint8 *bytes) | ||
127 | { | ||
128 | bytes[0] = val & 0xff; | ||
129 | bytes[1] = val >> 8; | ||
130 | } | ||
131 | |||
132 | |||
133 | static INLINE void | ||
134 | htol32_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 | |||
143 | static INLINE void | ||
144 | hton16_ua_store(uint16 val, uint8 *bytes) | ||
145 | { | ||
146 | bytes[0] = val >> 8; | ||
147 | bytes[1] = val & 0xff; | ||
148 | } | ||
149 | |||
150 | |||
151 | static INLINE void | ||
152 | hton32_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 | |||
166 | static INLINE uint16 | ||
167 | ltoh16_ua(const void *bytes) | ||
168 | { | ||
169 | return _LTOH16_UA((const uint8 *)bytes); | ||
170 | } | ||
171 | |||
172 | |||
173 | static INLINE uint32 | ||
174 | ltoh32_ua(const void *bytes) | ||
175 | { | ||
176 | return _LTOH32_UA((const uint8 *)bytes); | ||
177 | } | ||
178 | |||
179 | |||
180 | static INLINE uint16 | ||
181 | ntoh16_ua(const void *bytes) | ||
182 | { | ||
183 | return _NTOH16_UA((const uint8 *)bytes); | ||
184 | } | ||
185 | |||
186 | |||
187 | static INLINE uint32 | ||
188 | ntoh32_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 | |||
63 | typedef 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 | |||
95 | typedef 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 | |||
50 | typedef int SDIOH_API_RC; | ||
51 | |||
52 | /* SDio Host structure */ | ||
53 | typedef struct sdioh_info sdioh_info_t; | ||
54 | |||
55 | /* callback function, taking one arg */ | ||
56 | typedef 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 | */ | ||
62 | extern sdioh_info_t * sdioh_attach(osl_t *osh, void *cfghdl, uint irq); | ||
63 | extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *si); | ||
64 | extern SDIOH_API_RC sdioh_interrupt_register(sdioh_info_t *si, sdioh_cb_fn_t fn, void *argh); | ||
65 | extern SDIOH_API_RC sdioh_interrupt_deregister(sdioh_info_t *si); | ||
66 | |||
67 | /* query whether SD interrupt is enabled or not */ | ||
68 | extern SDIOH_API_RC sdioh_interrupt_query(sdioh_info_t *si, bool *onoff); | ||
69 | |||
70 | /* enable or disable SD interrupt */ | ||
71 | extern SDIOH_API_RC sdioh_interrupt_set(sdioh_info_t *si, bool enable_disable); | ||
72 | |||
73 | #if defined(DHD_DEBUG) | ||
74 | extern bool sdioh_interrupt_pending(sdioh_info_t *si); | ||
75 | #endif | ||
76 | |||
77 | /* read or write one byte using cmd52 */ | ||
78 | extern 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 */ | ||
81 | extern 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 */ | ||
85 | extern 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 */ | ||
90 | extern SDIOH_API_RC sdioh_cis_read(sdioh_info_t *si, uint fuc, uint8 *cis, uint32 length); | ||
91 | |||
92 | extern SDIOH_API_RC sdioh_cfg_read(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); | ||
93 | extern SDIOH_API_RC sdioh_cfg_write(sdioh_info_t *si, uint fuc, uint32 addr, uint8 *data); | ||
94 | |||
95 | /* query number of io functions */ | ||
96 | extern uint sdioh_query_iofnum(sdioh_info_t *si); | ||
97 | |||
98 | /* handle iovars */ | ||
99 | extern 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 */ | ||
103 | extern int sdioh_abort(sdioh_info_t *si, uint fnc); | ||
104 | |||
105 | /* Start and Stop SDIO without re-enumerating the SD card. */ | ||
106 | extern int sdioh_start(sdioh_info_t *si, int stage); | ||
107 | extern int sdioh_stop(sdioh_info_t *si); | ||
108 | |||
109 | /* Reset and re-initialize the device */ | ||
110 | extern int sdioh_sdio_reset(sdioh_info_t *si); | ||
111 | |||
112 | /* Helper function */ | ||
113 | void *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 */ | ||
34 | extern const uint bcmsdh_msglevel; | ||
35 | |||
36 | #define BCMSDH_ERROR(x) | ||
37 | #define BCMSDH_INFO(x) | ||
38 | |||
39 | /* forward declarations */ | ||
40 | typedef struct bcmsdh_info bcmsdh_info_t; | ||
41 | typedef 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 | */ | ||
50 | extern bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq); | ||
51 | |||
52 | /* Detach - freeup resources allocated in attach */ | ||
53 | extern int bcmsdh_detach(osl_t *osh, void *sdh); | ||
54 | |||
55 | /* Query if SD device interrupts are enabled */ | ||
56 | extern bool bcmsdh_intr_query(void *sdh); | ||
57 | |||
58 | /* Enable/disable SD interrupt */ | ||
59 | extern int bcmsdh_intr_enable(void *sdh); | ||
60 | extern int bcmsdh_intr_disable(void *sdh); | ||
61 | |||
62 | /* Register/deregister device interrupt handler. */ | ||
63 | extern int bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh); | ||
64 | extern int bcmsdh_intr_dereg(void *sdh); | ||
65 | |||
66 | #if defined(DHD_DEBUG) | ||
67 | /* Query pending interrupt status from the host controller */ | ||
68 | extern bool bcmsdh_intr_pending(void *sdh); | ||
69 | #endif | ||
70 | |||
71 | #ifdef BCMLXSDMMC | ||
72 | extern int bcmsdh_claim_host_and_lock(void *sdh); | ||
73 | extern 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 | */ | ||
79 | extern 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 | */ | ||
87 | extern uint8 bcmsdh_cfg_read(void *sdh, uint func, uint32 addr, int *err); | ||
88 | extern void bcmsdh_cfg_write(void *sdh, uint func, uint32 addr, uint8 data, int *err); | ||
89 | |||
90 | /* Read/Write 4bytes from/to cfg space */ | ||
91 | extern uint32 bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err); | ||
92 | extern 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 | */ | ||
101 | extern 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 | */ | ||
108 | extern uint32 bcmsdh_reg_read(void *sdh, uint32 addr, uint size); | ||
109 | extern uint32 bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data); | ||
110 | |||
111 | /* Indicate if last reg read/write failed */ | ||
112 | extern 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 | */ | ||
126 | typedef void (*bcmsdh_cmplt_fn_t)(void *handle, int status, bool sync_waiting); | ||
127 | extern 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); | ||
130 | extern 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 | */ | ||
149 | extern int bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes); | ||
150 | |||
151 | /* Issue an abort to the specified function */ | ||
152 | extern int bcmsdh_abort(void *sdh, uint fn); | ||
153 | |||
154 | /* Start SDIO Host Controller communication */ | ||
155 | extern int bcmsdh_start(void *sdh, int stage); | ||
156 | |||
157 | /* Stop SDIO Host Controller communication */ | ||
158 | extern int bcmsdh_stop(void *sdh); | ||
159 | |||
160 | /* Returns the "Device ID" of target device on the SDIO bus. */ | ||
161 | extern int bcmsdh_query_device(void *sdh); | ||
162 | |||
163 | /* Returns the number of IO functions reported by the device */ | ||
164 | extern uint bcmsdh_query_iofnum(void *sdh); | ||
165 | |||
166 | /* Miscellaneous knob tweaker. */ | ||
167 | extern 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 */ | ||
171 | extern int bcmsdh_reset(bcmsdh_info_t *sdh); | ||
172 | |||
173 | /* helper functions */ | ||
174 | |||
175 | extern void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh); | ||
176 | |||
177 | /* callback functions */ | ||
178 | typedef 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 */ | ||
188 | extern int bcmsdh_register(bcmsdh_driver_t *driver); | ||
189 | extern void bcmsdh_unregister(void); | ||
190 | extern bool bcmsdh_chipmatch(uint16 vendor, uint16 device); | ||
191 | extern void bcmsdh_device_remove(void * sdh); | ||
192 | |||
193 | #if defined(OOB_INTR_ONLY) | ||
194 | extern int bcmsdh_register_oob_intr(void * dhdp); | ||
195 | extern void bcmsdh_unregister_oob_intr(void); | ||
196 | extern void bcmsdh_oob_intr_set(bool enable); | ||
197 | #endif /* defined(OOB_INTR_ONLY) */ | ||
198 | /* Function to pass device-status bits to DHD. */ | ||
199 | extern uint32 bcmsdh_get_dstatus(void *sdh); | ||
200 | |||
201 | /* Function to return current window addr */ | ||
202 | extern uint32 bcmsdh_cur_sbwad(void *sdh); | ||
203 | |||
204 | /* Function to pass chipid and rev to lower layers for controlling pr's */ | ||
205 | extern 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 */ | ||
43 | extern int sdioh_sdmmc_osinit(sdioh_info_t *sd); | ||
44 | extern 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 | |||
64 | struct 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 */ | ||
95 | extern uint sd_msglevel; | ||
96 | |||
97 | /* OS-independent interrupt handler */ | ||
98 | extern bool check_client_intr(sdioh_info_t *sd); | ||
99 | |||
100 | /* Core interrupt enable/disable of device interrupts */ | ||
101 | extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd); | ||
102 | extern 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 */ | ||
110 | extern uint32 *sdioh_sdmmc_reg_map(osl_t *osh, int32 addr, int size); | ||
111 | extern void sdioh_sdmmc_reg_unmap(osl_t *osh, int32 addr, int size); | ||
112 | |||
113 | /* Interrupt (de)registration routines */ | ||
114 | extern int sdioh_sdmmc_register_irq(sdioh_info_t *sd, uint irq); | ||
115 | extern void sdioh_sdmmc_free_irq(uint irq, sdioh_info_t *sd); | ||
116 | |||
117 | typedef 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 | |||
162 | typedef 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 | |||
250 | typedef 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 | |||
261 | extern 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 | |||
57 | struct 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 */ | ||
111 | extern uint sd_msglevel; | ||
112 | |||
113 | /************************************************************** | ||
114 | * Internal interfaces: bcmsdspi.c references to per-port code | ||
115 | */ | ||
116 | |||
117 | /* Register mapping routines */ | ||
118 | extern uint32 *spi_reg_map(osl_t *osh, uintptr addr, int size); | ||
119 | extern void spi_reg_unmap(osl_t *osh, uintptr addr, int size); | ||
120 | |||
121 | /* Interrupt (de)registration routines */ | ||
122 | extern int spi_register_irq(sdioh_info_t *sd, uint irq); | ||
123 | extern void spi_free_irq(uint irq, sdioh_info_t *sd); | ||
124 | |||
125 | /* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ | ||
126 | extern void spi_lock(sdioh_info_t *sd); | ||
127 | extern void spi_unlock(sdioh_info_t *sd); | ||
128 | |||
129 | /* Allocate/init/free per-OS private data */ | ||
130 | extern int spi_osinit(sdioh_info_t *sd); | ||
131 | extern 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 */ | ||
42 | extern int sdstd_osinit(sdioh_info_t *sd); | ||
43 | extern 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 | |||
91 | struct 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 */ | ||
174 | typedef struct adma2_dscr_32b { | ||
175 | uint32 len_attr; | ||
176 | uint32 phys_addr; | ||
177 | } adma2_dscr_32b_t; | ||
178 | |||
179 | /* ADMA1 Descriptor Table Entry */ | ||
180 | typedef 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 */ | ||
189 | extern uint sd_msglevel; | ||
190 | |||
191 | /* OS-independent interrupt handler */ | ||
192 | extern bool check_client_intr(sdioh_info_t *sd); | ||
193 | |||
194 | /* Core interrupt enable/disable of device interrupts */ | ||
195 | extern void sdstd_devintr_on(sdioh_info_t *sd); | ||
196 | extern void sdstd_devintr_off(sdioh_info_t *sd); | ||
197 | |||
198 | /* Enable/disable interrupts for local controller events */ | ||
199 | extern void sdstd_intrs_on(sdioh_info_t *sd, uint16 norm, uint16 err); | ||
200 | extern void sdstd_intrs_off(sdioh_info_t *sd, uint16 norm, uint16 err); | ||
201 | |||
202 | /* Wait for specified interrupt and error bits to be set */ | ||
203 | extern 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 */ | ||
211 | extern uint32 *sdstd_reg_map(osl_t *osh, int32 addr, int size); | ||
212 | extern void sdstd_reg_unmap(osl_t *osh, int32 addr, int size); | ||
213 | |||
214 | /* Interrupt (de)registration routines */ | ||
215 | extern int sdstd_register_irq(sdioh_info_t *sd, uint irq); | ||
216 | extern void sdstd_free_irq(uint irq, sdioh_info_t *sd); | ||
217 | |||
218 | /* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ | ||
219 | extern void sdstd_lock(sdioh_info_t *sd); | ||
220 | extern void sdstd_unlock(sdioh_info_t *sd); | ||
221 | |||
222 | /* OS-specific wait-for-interrupt-or-status */ | ||
223 | extern 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 | |||
27 | extern void spi_devintr_off(sdioh_info_t *sd); | ||
28 | extern void spi_devintr_on(sdioh_info_t *sd); | ||
29 | extern bool spi_start_clock(sdioh_info_t *sd, uint16 new_sd_divisor); | ||
30 | extern bool spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode); | ||
31 | extern bool spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr); | ||
32 | extern bool spi_hw_attach(sdioh_info_t *sd); | ||
33 | extern bool spi_hw_detach(sdioh_info_t *sd); | ||
34 | extern void spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen); | ||
35 | extern void spi_spinbits(sdioh_info_t *sd); | ||
36 | extern 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 | |||
48 | struct 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 */ | ||
107 | extern uint sd_msglevel; | ||
108 | |||
109 | /************************************************************** | ||
110 | * Internal interfaces: bcmspibrcm.c references to per-port code | ||
111 | */ | ||
112 | |||
113 | /* Interrupt (de)registration routines */ | ||
114 | extern int spi_register_irq(sdioh_info_t *sd, uint irq); | ||
115 | extern void spi_free_irq(uint irq, sdioh_info_t *sd); | ||
116 | |||
117 | /* OS-specific interrupt wrappers (atomic interrupt enable/disable) */ | ||
118 | extern void spi_lock(sdioh_info_t *sd); | ||
119 | extern void spi_unlock(sdioh_info_t *sd); | ||
120 | |||
121 | /* Allocate/init/free per-OS private data */ | ||
122 | extern int spi_osinit(sdioh_info_t *sd); | ||
123 | extern 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 | ||
31 | extern "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 | |||
44 | extern 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 | |||
63 | struct 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 | |||
94 | typedef struct pktq_prec { | ||
95 | void *head; | ||
96 | void *tail; | ||
97 | uint16 len; | ||
98 | uint16 max; | ||
99 | } pktq_prec_t; | ||
100 | |||
101 | |||
102 | |||
103 | struct 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 | |||
113 | struct 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 | |||
127 | struct ether_addr; | ||
128 | |||
129 | extern int ether_isbcast(const void *ea); | ||
130 | extern 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 | |||
143 | extern void *pktq_penq(struct pktq *pq, int prec, void *p); | ||
144 | extern void *pktq_penq_head(struct pktq *pq, int prec, void *p); | ||
145 | extern void *pktq_pdeq(struct pktq *pq, int prec); | ||
146 | extern void *pktq_pdeq_tail(struct pktq *pq, int prec); | ||
147 | |||
148 | extern bool pktq_pdel(struct pktq *pq, void *p, int prec); | ||
149 | |||
150 | |||
151 | extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec, bool dir); | ||
152 | |||
153 | extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir); | ||
154 | |||
155 | |||
156 | |||
157 | extern int pktq_mlen(struct pktq *pq, uint prec_bmp); | ||
158 | extern 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 | |||
175 | extern void pktq_init(struct pktq *pq, int num_prec, int max_len); | ||
176 | |||
177 | extern void *pktq_deq(struct pktq *pq, int *prec_out); | ||
178 | extern void *pktq_deq_tail(struct pktq *pq, int *prec_out); | ||
179 | extern void *pktq_peek(struct pktq *pq, int *prec_out); | ||
180 | extern void *pktq_peek_tail(struct pktq *pq, int *prec_out); | ||
181 | |||
182 | |||
183 | |||
184 | extern uint pktcopy(osl_t *osh, void *p, uint offset, int len, uchar *buf); | ||
185 | extern uint pktfrombuf(osl_t *osh, void *p, uint offset, int len, uchar *buf); | ||
186 | extern uint pkttotlen(osl_t *osh, void *p); | ||
187 | extern void *pktlast(osl_t *osh, void *p); | ||
188 | extern uint pktsegcnt(osl_t *osh, void *p); | ||
189 | |||
190 | |||
191 | extern 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 | |||
198 | extern int bcm_atoi(char *s); | ||
199 | extern ulong bcm_strtoul(char *cp, char **endp, uint base); | ||
200 | extern char *bcmstrstr(char *haystack, char *needle); | ||
201 | extern char *bcmstrcat(char *dest, const char *src); | ||
202 | extern char *bcmstrncat(char *dest, const char *src, uint size); | ||
203 | extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen, ulong abuflen); | ||
204 | char* bcmstrtok(char **string, const char *delimiters, char *tokdelim); | ||
205 | int bcmstricmp(const char *s1, const char *s2); | ||
206 | int bcmstrnicmp(const char* s1, const char* s2, int cnt); | ||
207 | |||
208 | |||
209 | |||
210 | extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf); | ||
211 | extern int bcm_ether_atoe(char *p, struct ether_addr *ea); | ||
212 | |||
213 | |||
214 | struct ipv4_addr; | ||
215 | extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); | ||
216 | |||
217 | |||
218 | extern void bcm_mdelay(uint ms); | ||
219 | |||
220 | extern char *getvar(char *vars, const char *name); | ||
221 | extern int getintvar(char *vars, const char *name); | ||
222 | extern 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 | |||
236 | typedef 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 | |||
257 | extern const bcm_iovar_t *bcm_iovar_lookup(const bcm_iovar_t *table, const char *name); | ||
258 | extern 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 | |||
467 | typedef struct bcm_bit_desc { | ||
468 | uint32 bit; | ||
469 | const char* name; | ||
470 | } bcm_bit_desc_t; | ||
471 | |||
472 | |||
473 | typedef 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 | ||
487 | static INLINE uint32 | ||
488 | load32_ua(uint8 *a) | ||
489 | { | ||
490 | return ((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]); | ||
491 | } | ||
492 | |||
493 | static INLINE void | ||
494 | store32_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 | |||
502 | static INLINE uint16 | ||
503 | load16_ua(uint8 *a) | ||
504 | { | ||
505 | return ((a[0] << 8) | a[1]); | ||
506 | } | ||
507 | |||
508 | static INLINE void | ||
509 | store16_ua(uint8 *a, uint16 v) | ||
510 | { | ||
511 | a[0] = (v >> 8) & 0xff; | ||
512 | a[1] = v & 0xff; | ||
513 | } | ||
514 | |||
515 | #else | ||
516 | |||
517 | static INLINE uint32 | ||
518 | load32_ua(uint8 *a) | ||
519 | { | ||
520 | return ((a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]); | ||
521 | } | ||
522 | |||
523 | static INLINE void | ||
524 | store32_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 | |||
532 | static INLINE uint16 | ||
533 | load16_ua(uint8 *a) | ||
534 | { | ||
535 | return ((a[1] << 8) | a[0]); | ||
536 | } | ||
537 | |||
538 | static INLINE void | ||
539 | store16_ua(uint8 *a, uint16 v) | ||
540 | { | ||
541 | a[1] = (v >> 8) & 0xff; | ||
542 | a[0] = v & 0xff; | ||
543 | } | ||
544 | |||
545 | #endif | ||
546 | |||
547 | |||
548 | |||
549 | static INLINE void | ||
550 | xor_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 | |||
573 | extern uint8 hndcrc8(uint8 *p, uint nbytes, uint8 crc); | ||
574 | extern uint16 hndcrc16(uint8 *p, uint nbytes, uint16 crc); | ||
575 | extern uint32 hndcrc32(uint8 *p, uint nbytes, uint32 crc); | ||
576 | |||
577 | #if defined(DHD_DEBUG) || defined(WLMSG_PRHDRS) || defined(WLMSG_PRPKT) || \ | ||
578 | defined(WLMSG_ASSOC) | ||
579 | extern int bcm_format_flags(const bcm_bit_desc_t *bd, uint32 flags, char* buf, int len); | ||
580 | extern int bcm_format_hex(char *str, const void *bytes, int len); | ||
581 | extern void prhex(const char *msg, uchar *buf, uint len); | ||
582 | #endif | ||
583 | extern char *bcm_brev_str(uint32 brev, char *buf); | ||
584 | extern void printbig(char *buf); | ||
585 | |||
586 | |||
587 | extern bcm_tlv_t *bcm_next_tlv(bcm_tlv_t *elt, int *buflen); | ||
588 | extern bcm_tlv_t *bcm_parse_tlvs(void *buf, int buflen, uint key); | ||
589 | extern bcm_tlv_t *bcm_parse_ordered_tlvs(void *buf, int buflen, uint key); | ||
590 | |||
591 | |||
592 | extern const char *bcmerrorstr(int bcmerror); | ||
593 | |||
594 | |||
595 | typedef 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 | |||
602 | extern uint16 bcm_qdbm_to_mw(uint8 qdbm); | ||
603 | extern uint8 bcm_mw_to_qdbm(uint16 mw); | ||
604 | |||
605 | |||
606 | struct fielddesc { | ||
607 | const char *nameandfmt; | ||
608 | uint32 offset; | ||
609 | uint32 len; | ||
610 | }; | ||
611 | |||
612 | extern void bcm_binit(struct bcmstrbuf *b, char *buf, uint size); | ||
613 | extern int bcm_bprintf(struct bcmstrbuf *b, const char *fmt, ...); | ||
614 | extern void bcm_inc_bytes(uchar *num, int num_bytes, uint8 amount); | ||
615 | extern int bcm_cmp_bytes(uchar *arg1, uchar *arg2, uint8 nbytes); | ||
616 | extern void bcm_print_bytes(char *name, const uchar *cdata, int len); | ||
617 | |||
618 | typedef uint32 (*bcmutl_rdreg_rtn)(void *arg0, uint arg1, uint32 offset); | ||
619 | extern uint bcmdumpfields(bcmutl_rdreg_rtn func_ptr, void *arg0, uint arg1, struct fielddesc *str, | ||
620 | char *buf, uint32 bufsize); | ||
621 | |||
622 | extern uint bcm_mkiovar(char *name, char *data, uint datalen, char *buf, uint len); | ||
623 | extern 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) | ||
627 | extern 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 | |||
34 | typedef 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 | |||
143 | extern char * wf_chspec_ntoa(chanspec_t chspec, char *buf); | ||
144 | |||
145 | |||
146 | extern chanspec_t wf_chspec_aton(char *a); | ||
147 | |||
148 | |||
149 | extern int wf_mhz2channel(uint freq, uint start_factor); | ||
150 | |||
151 | |||
152 | extern 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 */ | ||
43 | typedef 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 */ | ||
86 | typedef 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 | |||
31 | extern void si_pmu_otp_power(si_t *sih, osl_t *osh, bool on); | ||
32 | extern 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 | |||
63 | typedef 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 | |||
33 | typedef 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 | |||
40 | typedef 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) | ||
49 | extern 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)) | ||
57 | extern void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size); | ||
58 | extern 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)) | ||
65 | extern uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size); | ||
66 | extern 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) | ||
71 | extern uint osl_pci_bus(osl_t *osh); | ||
72 | extern uint osl_pci_slot(osl_t *osh); | ||
73 | |||
74 | |||
75 | typedef 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 | |||
84 | extern osl_t *osl_attach(void *pdev, uint bustype, bool pkttag); | ||
85 | extern 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 | |||
104 | extern void *osl_malloc(osl_t *osh, uint size); | ||
105 | extern void osl_mfree(osl_t *osh, void *addr, uint size); | ||
106 | extern uint osl_malloced(osl_t *osh); | ||
107 | extern 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)) | ||
115 | extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap); | ||
116 | extern 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)) | ||
127 | extern uint osl_dma_map(osl_t *osh, void *va, uint size, int direction); | ||
128 | extern 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 | |||
260 | extern void *osl_pktget(osl_t *osh, uint len); | ||
261 | extern void osl_pktfree(osl_t *osh, void *skb, bool send); | ||
262 | extern void *osl_pktget_static(osl_t *osh, uint len); | ||
263 | extern void osl_pktfree_static(osl_t *osh, void *skb, bool send); | ||
264 | extern void *osl_pktdup(osl_t *osh, void *skb); | ||
265 | |||
266 | |||
267 | |||
268 | static INLINE void * | ||
269 | osl_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 | |||
286 | static INLINE struct sk_buff * | ||
287 | osl_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) | ||
315 | extern 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) | ||
97 | typedef void (*work_func_t)(void *work); | ||
98 | #endif | ||
99 | |||
100 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)) | ||
101 | |||
102 | #ifndef IRQ_NONE | ||
103 | typedef void irqreturn_t; | ||
104 | #define IRQ_NONE | ||
105 | #define IRQ_HANDLED | ||
106 | #define IRQ_RETVAL(x) | ||
107 | #endif | ||
108 | #else | ||
109 | typedef 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 | |||
152 | struct 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 | |||
159 | struct 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 | ||
175 | extern int pci_register_driver(struct pci_driver *drv); | ||
176 | extern 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 | |||
222 | typedef u32 dma_addr_t; | ||
223 | |||
224 | |||
225 | static 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 | |||
238 | static 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 | } | ||
252 | static 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 | |||
277 | static 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 | ||
294 | static inline void tasklet_schedule(struct tasklet_struct *tasklet) | ||
295 | { | ||
296 | queue_task(tasklet, &tq_immediate); | ||
297 | mark_bh(IMMEDIATE_BH); | ||
298 | } | ||
299 | |||
300 | static 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 | |||
343 | static inline int | ||
344 | pci_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 | |||
354 | static inline int | ||
355 | pci_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 | ||
31 | extern "C" { | ||
32 | #endif | ||
33 | |||
34 | /* ---- Include Files ---------------------------------------------------- */ | ||
35 | /* ---- Constants and Types ---------------------------------------------- */ | ||
36 | |||
37 | #define MINIOPT_MAXKEY 128 /* Max options */ | ||
38 | typedef 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 | |||
65 | void miniopt_init(miniopt_t *t, const char* name, const char* flags, bool longflags); | ||
66 | int 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 */ | ||
41 | typedef 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 | */ | ||
60 | extern bool msgtrace_hbus_trace; | ||
61 | |||
62 | typedef void (*msgtrace_func_send_t)(void *hdl1, void *hdl2, uint8 *hdr, | ||
63 | uint16 hdrlen, uint8 *buf, uint16 buflen); | ||
64 | |||
65 | extern void msgtrace_sent(void); | ||
66 | extern void msgtrace_put(char *buf, int count); | ||
67 | extern 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 | |||
31 | typedef struct osl_info osl_t; | ||
32 | typedef struct osl_dmainfo osldma_t; | ||
33 | |||
34 | #define OSL_PKTTAG_SZ 32 | ||
35 | |||
36 | |||
37 | typedef 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 | ||
96 | BWL_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 | |||
109 | BWL_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 | |||
121 | BWL_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 | |||
129 | BWL_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 | |||
136 | BWL_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 | |||
143 | BWL_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 | |||
151 | BWL_PRE_PACKED_STRUCT struct dot11_cf_end_frame { | ||
152 | uint16 fc; | ||
153 | uint16 durid; | ||
154 | struct ether_addr ra; | ||
155 | struct ether_addr bssid; | ||
156 | } BWL_POST_PACKED_STRUCT; | ||
157 | #define DOT11_CS_END_LEN 16 | ||
158 | |||
159 | BWL_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 | |||
168 | typedef 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 | |||
184 | BWL_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 | |||
193 | BWL_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 | |||
202 | BWL_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 | |||
210 | BWL_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 | |||
222 | BWL_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 | |||
229 | BWL_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 | |||
236 | BWL_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 | |||
242 | BWL_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 | |||
249 | BWL_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 | |||
256 | BWL_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 | |||
264 | BWL_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 | |||
270 | BWL_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 | |||
280 | BWL_PRE_PACKED_STRUCT struct dot11_power_cnst { | ||
281 | uint8 id; | ||
282 | uint8 len; | ||
283 | uint8 power; | ||
284 | } BWL_POST_PACKED_STRUCT; | ||
285 | typedef struct dot11_power_cnst dot11_power_cnst_t; | ||
286 | |||
287 | BWL_PRE_PACKED_STRUCT struct dot11_power_cap { | ||
288 | uint8 min; | ||
289 | uint8 max; | ||
290 | } BWL_POST_PACKED_STRUCT; | ||
291 | typedef struct dot11_power_cap dot11_power_cap_t; | ||
292 | |||
293 | BWL_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; | ||
299 | typedef struct dot11_tpc_rep dot11_tpc_rep_t; | ||
300 | #define DOT11_MNG_IE_TPC_REPORT_LEN 2 | ||
301 | |||
302 | BWL_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; | ||
308 | typedef struct dot11_supp_channels dot11_supp_channels_t; | ||
309 | |||
310 | |||
311 | BWL_PRE_PACKED_STRUCT struct dot11_extch { | ||
312 | uint8 id; | ||
313 | uint8 len; | ||
314 | uint8 extch; | ||
315 | } BWL_POST_PACKED_STRUCT; | ||
316 | typedef struct dot11_extch dot11_extch_ie_t; | ||
317 | |||
318 | BWL_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; | ||
325 | typedef 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 | |||
335 | BWL_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 | |||
343 | BWL_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; | ||
350 | typedef 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 | |||
357 | BWL_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 | |||
364 | BWL_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 | |||
372 | BWL_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 | |||
378 | BWL_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; | ||
383 | typedef struct dot11_ext_csa dot11_ext_csa_ie_t; | ||
384 | #define DOT11_EXT_CSA_IE_LEN 4 | ||
385 | |||
386 | BWL_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 | |||
392 | BWL_PRE_PACKED_STRUCT struct dot11_obss_coex { | ||
393 | uint8 id; | ||
394 | uint8 len; | ||
395 | uint8 info; | ||
396 | } BWL_POST_PACKED_STRUCT; | ||
397 | typedef 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 | |||
404 | BWL_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; | ||
410 | typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; | ||
411 | #define DOT11_OBSS_CHANLIST_FIXED_LEN 1 | ||
412 | |||
413 | BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { | ||
414 | uint8 id; | ||
415 | uint8 len; | ||
416 | uint8 cap; | ||
417 | } BWL_POST_PACKED_STRUCT; | ||
418 | typedef 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 | |||
442 | BWL_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; | ||
452 | typedef 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 | |||
457 | BWL_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; | ||
474 | typedef struct dot11_meas_rep dot11_meas_rep_t; | ||
475 | |||
476 | |||
477 | #define DOT11_MNG_IE_MREP_FIXED_LEN 3 | ||
478 | |||
479 | BWL_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; | ||
485 | typedef struct dot11_meas_rep_basic dot11_meas_rep_basic_t; | ||
486 | #define DOT11_MEASURE_BASIC_REP_LEN 12 | ||
487 | |||
488 | BWL_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; | ||
496 | typedef struct dot11_quiet dot11_quiet_t; | ||
497 | |||
498 | BWL_PRE_PACKED_STRUCT struct chan_map_tuple { | ||
499 | uint8 channel; | ||
500 | uint8 map; | ||
501 | } BWL_POST_PACKED_STRUCT; | ||
502 | typedef struct chan_map_tuple chan_map_tuple_t; | ||
503 | |||
504 | BWL_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; | ||
511 | typedef 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 | |||
528 | typedef 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 | |||
537 | BWL_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; | ||
544 | typedef struct wme_ie wme_ie_t; | ||
545 | #define WME_IE_LEN 7 | ||
546 | |||
547 | BWL_PRE_PACKED_STRUCT struct edcf_acparam { | ||
548 | uint8 ACI; | ||
549 | uint8 ECW; | ||
550 | uint16 TXOP; | ||
551 | } BWL_POST_PACKED_STRUCT; | ||
552 | typedef struct edcf_acparam edcf_acparam_t; | ||
553 | |||
554 | |||
555 | BWL_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; | ||
564 | typedef 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 | |||
641 | BWL_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; | ||
646 | typedef struct edca_param_ie edca_param_ie_t; | ||
647 | #define EDCA_PARAM_IE_LEN 18 | ||
648 | |||
649 | |||
650 | BWL_PRE_PACKED_STRUCT struct qos_cap_ie { | ||
651 | uint8 qosinfo; | ||
652 | } BWL_POST_PACKED_STRUCT; | ||
653 | typedef struct qos_cap_ie qos_cap_ie_t; | ||
654 | |||
655 | BWL_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; | ||
662 | typedef 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 | |||
674 | BWL_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 | |||
1059 | BWL_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; | ||
1067 | typedef struct dot11_addba_req dot11_addba_req_t; | ||
1068 | #define DOT11_ADDBA_REQ_LEN 9 | ||
1069 | |||
1070 | BWL_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; | ||
1078 | typedef 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 | |||
1087 | BWL_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; | ||
1093 | typedef 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 | |||
1138 | typedef 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 | |||
1161 | BWL_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; | ||
1168 | typedef 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 | |||
1178 | BWL_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; | ||
1188 | typedef 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 | |||
1218 | BWL_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; | ||
1226 | typedef struct ht_cap_ie ht_cap_ie_t; | ||
1227 | |||
1228 | |||
1229 | |||
1230 | BWL_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; | ||
1237 | typedef 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 | |||
1288 | BWL_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; | ||
1295 | typedef struct ht_add_ie ht_add_ie_t; | ||
1296 | |||
1297 | |||
1298 | |||
1299 | BWL_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; | ||
1306 | typedef 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 | |||
1357 | BWL_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; | ||
1366 | typedef struct obss_params obss_params_t; | ||
1367 | |||
1368 | BWL_PRE_PACKED_STRUCT struct dot11_obss_ie { | ||
1369 | uint8 id; | ||
1370 | uint8 len; | ||
1371 | obss_params_t obss_params; | ||
1372 | } BWL_POST_PACKED_STRUCT; | ||
1373 | typedef struct dot11_obss_ie dot11_obss_ie_t; | ||
1374 | #define DOT11_OBSS_SCAN_IE_LEN sizeof(obss_params_t) | ||
1375 | |||
1376 | |||
1377 | BWL_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; | ||
1383 | typedef 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 | |||
47 | BWL_PRE_PACKED_STRUCT struct tsinfo { | ||
48 | uint8 octets[3]; | ||
49 | } BWL_POST_PACKED_STRUCT; | ||
50 | |||
51 | typedef struct tsinfo tsinfo_t; | ||
52 | |||
53 | /* 802.11e TSPEC IE */ | ||
54 | typedef 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 | |||
69 | typedef 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 | |||
53 | typedef 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 | |||
67 | typedef 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 | |||
101 | BWL_PRE_PACKED_STRUCT struct ipv4_addr { | ||
102 | uint8 addr[IPV4_ADDR_LEN]; | ||
103 | } BWL_POST_PACKED_STRUCT; | ||
104 | |||
105 | BWL_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 */ | ||
26 | typedef 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 */ | ||
60 | typedef 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 */ | ||
91 | typedef 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 */ | ||
130 | typedef 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 */ | ||
146 | typedef 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 */ | ||
160 | typedef 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 | |||
91 | BWL_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 | |||
98 | BWL_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 | |||
128 | static const struct ether_addr ether_bcast = {{255, 255, 255, 255, 255, 255}}; | ||
129 | static 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 | |||
49 | struct 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 | |||
56 | typedef 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 | |||
71 | typedef 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 | ||
81 | typedef uint8 wpa_pmkid_t[WPA2_PMKID_LEN]; | ||
82 | |||
83 | |||
84 | typedef 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 | |||
92 | typedef 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 | ||
101 | typedef 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 | |||
44 | typedef 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 | |||
80 | typedef 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 | |||
38 | typedef volatile struct { | ||
39 | uint32 control; | ||
40 | uint32 addr; | ||
41 | uint32 ptr; | ||
42 | uint32 status; | ||
43 | } dma32regs_t; | ||
44 | |||
45 | typedef volatile struct { | ||
46 | dma32regs_t xmt; | ||
47 | dma32regs_t rcv; | ||
48 | } dma32regp_t; | ||
49 | |||
50 | typedef volatile struct { | ||
51 | uint32 fifoaddr; | ||
52 | uint32 fifodatalow; | ||
53 | uint32 fifodatahigh; | ||
54 | uint32 pad; | ||
55 | } dma32diag_t; | ||
56 | |||
57 | |||
58 | typedef 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 | |||
162 | typedef volatile struct { | ||
163 | uint32 control; | ||
164 | uint32 ptr; | ||
165 | uint32 addrlow; | ||
166 | uint32 addrhigh; | ||
167 | uint32 status0; | ||
168 | uint32 status1; | ||
169 | } dma64regs_t; | ||
170 | |||
171 | typedef volatile struct { | ||
172 | dma64regs_t tx; | ||
173 | dma64regs_t rx; | ||
174 | } dma64regp_t; | ||
175 | |||
176 | typedef volatile struct { | ||
177 | uint32 fifoaddr; | ||
178 | uint32 fifodatalow; | ||
179 | uint32 fifodatahigh; | ||
180 | uint32 pad; | ||
181 | } dma64diag_t; | ||
182 | |||
183 | |||
184 | typedef 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 | |||
38 | typedef 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 */ | ||
46 | typedef 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 */ | ||
53 | typedef 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 */ | ||
60 | typedef 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 */ | ||
67 | typedef 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 */ | ||
273 | typedef 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 | |||
41 | typedef 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 */ | ||
33 | typedef 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 */ | ||
146 | typedef 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 | |||
37 | typedef 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 | |||
33 | struct 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) | ||
57 | typedef struct si_pub si_t; | ||
58 | #else | ||
59 | typedef 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 | |||
113 | typedef void (*gpio_handler_t)(uint32 stat, void *arg); | ||
114 | |||
115 | |||
116 | |||
117 | extern si_t *si_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, | ||
118 | void *sdh, char **vars, uint *varsz); | ||
119 | extern si_t *si_kattach(osl_t *osh); | ||
120 | extern void si_detach(si_t *sih); | ||
121 | extern bool si_pci_war16165(si_t *sih); | ||
122 | |||
123 | extern uint si_corelist(si_t *sih, uint coreid[]); | ||
124 | extern uint si_coreid(si_t *sih); | ||
125 | extern uint si_flag(si_t *sih); | ||
126 | extern uint si_intflag(si_t *sih); | ||
127 | extern uint si_coreidx(si_t *sih); | ||
128 | extern uint si_coreunit(si_t *sih); | ||
129 | extern uint si_corevendor(si_t *sih); | ||
130 | extern uint si_corerev(si_t *sih); | ||
131 | extern void *si_osh(si_t *sih); | ||
132 | extern void si_setosh(si_t *sih, osl_t *osh); | ||
133 | extern uint si_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); | ||
134 | extern void *si_coreregs(si_t *sih); | ||
135 | extern void si_write_wrapperreg(si_t *sih, uint32 offset, uint32 val); | ||
136 | extern uint32 si_core_cflags(si_t *sih, uint32 mask, uint32 val); | ||
137 | extern void si_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); | ||
138 | extern uint32 si_core_sflags(si_t *sih, uint32 mask, uint32 val); | ||
139 | extern bool si_iscoreup(si_t *sih); | ||
140 | extern uint si_findcoreidx(si_t *sih, uint coreid, uint coreunit); | ||
141 | extern void *si_setcoreidx(si_t *sih, uint coreidx); | ||
142 | extern void *si_setcore(si_t *sih, uint coreid, uint coreunit); | ||
143 | extern void *si_switch_core(si_t *sih, uint coreid, uint *origidx, uint *intr_val); | ||
144 | extern void si_restore_core(si_t *sih, uint coreid, uint intr_val); | ||
145 | extern int si_numaddrspaces(si_t *sih); | ||
146 | extern uint32 si_addrspace(si_t *sih, uint asidx); | ||
147 | extern uint32 si_addrspacesize(si_t *sih, uint asidx); | ||
148 | extern int si_corebist(si_t *sih); | ||
149 | extern void si_core_reset(si_t *sih, uint32 bits, uint32 resetbits); | ||
150 | extern void si_core_tofixup(si_t *sih); | ||
151 | extern void si_core_disable(si_t *sih, uint32 bits); | ||
152 | extern uint32 si_clock_rate(uint32 pll_type, uint32 n, uint32 m); | ||
153 | extern uint32 si_clock(si_t *sih); | ||
154 | extern void si_clock_pmu_spuravoid(si_t *sih, bool spuravoid); | ||
155 | extern uint32 si_alp_clock(si_t *sih); | ||
156 | extern uint32 si_ilp_clock(si_t *sih); | ||
157 | extern void si_pci_setup(si_t *sih, uint coremask); | ||
158 | extern void si_pcmcia_init(si_t *sih); | ||
159 | extern void si_setint(si_t *sih, int siflag); | ||
160 | extern bool si_backplane64(si_t *sih); | ||
161 | extern void si_register_intr_callback(si_t *sih, void *intrsoff_fn, void *intrsrestore_fn, | ||
162 | void *intrsenabled_fn, void *intr_arg); | ||
163 | extern void si_deregister_intr_callback(si_t *sih); | ||
164 | extern void si_clkctl_init(si_t *sih); | ||
165 | extern uint16 si_clkctl_fast_pwrup_delay(si_t *sih); | ||
166 | extern bool si_clkctl_cc(si_t *sih, uint mode); | ||
167 | extern int si_clkctl_xtal(si_t *sih, uint what, bool on); | ||
168 | extern uint32 si_gpiotimerval(si_t *sih, uint32 mask, uint32 val); | ||
169 | extern bool si_backplane64(si_t *sih); | ||
170 | extern void si_btcgpiowar(si_t *sih); | ||
171 | extern bool si_deviceremoved(si_t *sih); | ||
172 | extern uint32 si_socram_size(si_t *sih); | ||
173 | |||
174 | extern void si_watchdog(si_t *sih, uint ticks); | ||
175 | extern void si_watchdog_ms(si_t *sih, uint32 ms); | ||
176 | extern void *si_gpiosetcore(si_t *sih); | ||
177 | extern uint32 si_gpiocontrol(si_t *sih, uint32 mask, uint32 val, uint8 priority); | ||
178 | extern uint32 si_gpioouten(si_t *sih, uint32 mask, uint32 val, uint8 priority); | ||
179 | extern uint32 si_gpioout(si_t *sih, uint32 mask, uint32 val, uint8 priority); | ||
180 | extern uint32 si_gpioin(si_t *sih); | ||
181 | extern uint32 si_gpiointpolarity(si_t *sih, uint32 mask, uint32 val, uint8 priority); | ||
182 | extern uint32 si_gpiointmask(si_t *sih, uint32 mask, uint32 val, uint8 priority); | ||
183 | extern uint32 si_gpioled(si_t *sih, uint32 mask, uint32 val); | ||
184 | extern uint32 si_gpioreserve(si_t *sih, uint32 gpio_num, uint8 priority); | ||
185 | extern uint32 si_gpiorelease(si_t *sih, uint32 gpio_num, uint8 priority); | ||
186 | extern uint32 si_gpiopull(si_t *sih, bool updown, uint32 mask, uint32 val); | ||
187 | extern uint32 si_gpioevent(si_t *sih, uint regtype, uint32 mask, uint32 val); | ||
188 | extern uint32 si_gpio_int_enable(si_t *sih, bool enable); | ||
189 | |||
190 | |||
191 | extern void *si_gpio_handler_register(si_t *sih, uint32 e, bool lev, gpio_handler_t cb, void *arg); | ||
192 | extern void si_gpio_handler_unregister(si_t *sih, void* gpioh); | ||
193 | extern void si_gpio_handler_process(si_t *sih); | ||
194 | |||
195 | |||
196 | extern bool si_pci_pmecap(si_t *sih); | ||
197 | struct osl_info; | ||
198 | extern bool si_pci_fastpmecap(struct osl_info *osh); | ||
199 | extern bool si_pci_pmeclr(si_t *sih); | ||
200 | extern void si_pci_pmeen(si_t *sih); | ||
201 | extern uint si_pcie_readreg(void *sih, uint addrtype, uint offset); | ||
202 | |||
203 | extern void si_sdio_init(si_t *sih); | ||
204 | |||
205 | extern uint16 si_d11_devid(si_t *sih); | ||
206 | extern 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 | |||
214 | extern int si_devpath(si_t *sih, char *path, int size); | ||
215 | |||
216 | extern char *si_getdevpathvar(si_t *sih, const char *name); | ||
217 | extern int si_getdevpathintvar(si_t *sih, const char *name); | ||
218 | |||
219 | |||
220 | extern uint8 si_pcieclkreq(si_t *sih, uint32 mask, uint32 val); | ||
221 | extern void si_war42780_clkreq(si_t *sih, bool clkreq); | ||
222 | extern void si_pci_sleep(si_t *sih); | ||
223 | extern void si_pci_down(si_t *sih); | ||
224 | extern void si_pci_up(si_t *sih); | ||
225 | extern void si_pcie_war_ovr_disable(si_t *sih); | ||
226 | extern void si_pcie_extendL1timer(si_t *sih, bool extend); | ||
227 | extern 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 | |||
23 | typedef 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 | |||
37 | struct 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 */ | ||
46 | typedef 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 | ||
55 | typedef 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_) | ||
70 | typedef long unsigned int size_t; | ||
71 | #endif | ||
72 | |||
73 | #ifdef __DJGPP__ | ||
74 | typedef 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 | ||
143 | typedef unsigned char bool; | ||
144 | #endif | ||
145 | |||
146 | |||
147 | |||
148 | #ifndef TYPEDEF_UCHAR | ||
149 | typedef unsigned char uchar; | ||
150 | #endif | ||
151 | |||
152 | #ifndef TYPEDEF_USHORT | ||
153 | typedef unsigned short ushort; | ||
154 | #endif | ||
155 | |||
156 | #ifndef TYPEDEF_UINT | ||
157 | typedef unsigned int uint; | ||
158 | #endif | ||
159 | |||
160 | #ifndef TYPEDEF_ULONG | ||
161 | typedef unsigned long ulong; | ||
162 | #endif | ||
163 | |||
164 | |||
165 | |||
166 | #ifndef TYPEDEF_UINT8 | ||
167 | typedef unsigned char uint8; | ||
168 | #endif | ||
169 | |||
170 | #ifndef TYPEDEF_UINT16 | ||
171 | typedef unsigned short uint16; | ||
172 | #endif | ||
173 | |||
174 | #ifndef TYPEDEF_UINT32 | ||
175 | typedef unsigned int uint32; | ||
176 | #endif | ||
177 | |||
178 | #ifndef TYPEDEF_UINT64 | ||
179 | typedef unsigned long long uint64; | ||
180 | #endif | ||
181 | |||
182 | #ifndef TYPEDEF_UINTPTR | ||
183 | typedef unsigned int uintptr; | ||
184 | #endif | ||
185 | |||
186 | #ifndef TYPEDEF_INT8 | ||
187 | typedef signed char int8; | ||
188 | #endif | ||
189 | |||
190 | #ifndef TYPEDEF_INT16 | ||
191 | typedef signed short int16; | ||
192 | #endif | ||
193 | |||
194 | #ifndef TYPEDEF_INT32 | ||
195 | typedef signed int int32; | ||
196 | #endif | ||
197 | |||
198 | #ifndef TYPEDEF_INT64 | ||
199 | typedef signed long long int64; | ||
200 | #endif | ||
201 | |||
202 | |||
203 | |||
204 | #ifndef TYPEDEF_FLOAT32 | ||
205 | typedef float float32; | ||
206 | #endif | ||
207 | |||
208 | #ifndef TYPEDEF_FLOAT64 | ||
209 | typedef double float64; | ||
210 | #endif | ||
211 | |||
212 | |||
213 | |||
214 | #ifndef TYPEDEF_FLOAT_T | ||
215 | |||
216 | #if defined(FLOAT32) | ||
217 | typedef float32 float_t; | ||
218 | #else | ||
219 | typedef 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 | |||
45 | typedef 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 | |||
68 | typedef struct ssid_info | ||
69 | { | ||
70 | uint8 ssid_len; | ||
71 | uint8 ssid[32]; | ||
72 | } ssid_info_t; | ||
73 | |||
74 | typedef 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 | |||
94 | typedef 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 | |||
126 | typedef 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 | |||
140 | typedef 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 | |||
166 | typedef 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 | |||
175 | typedef 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 | |||
193 | typedef 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 | |||
202 | typedef 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 | |||
213 | typedef 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 | ||
222 | typedef struct wl_rateset { | ||
223 | uint32 count; | ||
224 | uint8 rates[WL_NUMRATES]; | ||
225 | } wl_rateset_t; | ||
226 | |||
227 | |||
228 | typedef struct wl_uint32_list { | ||
229 | |||
230 | uint32 count; | ||
231 | |||
232 | uint32 element[1]; | ||
233 | } wl_uint32_list_t; | ||
234 | |||
235 | |||
236 | typedef 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 | |||
245 | typedef wl_assoc_params_t wl_reassoc_params_t; | ||
246 | #define WL_REASSOC_PARAMS_FIXED_SIZE WL_ASSOC_PARAMS_FIXED_SIZE | ||
247 | |||
248 | |||
249 | typedef 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 | |||
257 | typedef 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 | |||
263 | typedef 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 | |||
308 | typedef 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 | |||
335 | typedef 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 | |||
366 | typedef struct _pmkid { | ||
367 | struct ether_addr BSSID; | ||
368 | uint8 PMKID[WPA2_PMKID_LEN]; | ||
369 | } pmkid_t; | ||
370 | |||
371 | typedef struct _pmkid_list { | ||
372 | uint32 npmkid; | ||
373 | pmkid_t pmkid[1]; | ||
374 | } pmkid_list_t; | ||
375 | |||
376 | typedef struct _pmkid_cand { | ||
377 | struct ether_addr BSSID; | ||
378 | uint8 preauth; | ||
379 | } pmkid_cand_t; | ||
380 | |||
381 | typedef struct _pmkid_cand_list { | ||
382 | uint32 npmkid_cand; | ||
383 | pmkid_cand_t pmkid_cand[1]; | ||
384 | } pmkid_cand_list_t; | ||
385 | |||
386 | |||
387 | |||
388 | |||
389 | typedef struct { | ||
390 | uint32 val; | ||
391 | struct ether_addr ea; | ||
392 | } scb_val_t; | ||
393 | |||
394 | |||
395 | |||
396 | typedef struct channel_info { | ||
397 | int hw_channel; | ||
398 | int target_channel; | ||
399 | int scan_channel; | ||
400 | } channel_info_t; | ||
401 | |||
402 | |||
403 | struct maclist { | ||
404 | uint count; | ||
405 | struct ether_addr ea[1]; | ||
406 | }; | ||
407 | |||
408 | |||
409 | typedef 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 | |||
418 | typedef 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 | |||
873 | typedef 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 | |||
981 | typedef struct { | ||
982 | uint32 pktflag; | ||
983 | vndr_ie_t vndr_ie_data; | ||
984 | } vndr_ie_info_t; | ||
985 | |||
986 | typedef struct { | ||
987 | int iecount; | ||
988 | vndr_ie_info_t vndr_ie_list[1]; | ||
989 | } vndr_ie_buf_t; | ||
990 | |||
991 | typedef 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 | |||
1009 | struct 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 | |||
1019 | typedef 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 | |||
1199 | typedef 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 | ||
1225 | typedef 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 | |||
1234 | typedef 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 | |||
1274 | typedef struct { | ||
1275 | uint32 packets; | ||
1276 | uint32 bytes; | ||
1277 | } wl_traffic_stats_t; | ||
1278 | |||
1279 | typedef 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 | |||
1302 | enum { | ||
1303 | PFN_LIST_ORDER, | ||
1304 | PFN_RSSI | ||
1305 | }; | ||
1306 | |||
1307 | enum { | ||
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 | |||
1333 | typedef 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 | |||
1343 | typedef 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 | |||
1365 | struct 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 | |||
1409 | struct 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 | |||
1431 | typedef 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 | |||
1443 | typedef 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 | |||
1450 | typedef 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 | |||
1457 | typedef 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 | |||
1470 | typedef struct wl_pkt_filter_enable { | ||
1471 | uint32 id; | ||
1472 | uint32 enable; | ||
1473 | } wl_pkt_filter_enable_t; | ||
1474 | |||
1475 | |||
1476 | typedef 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 | |||
1484 | typedef 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 | |||
1491 | typedef 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 | |||
1517 | typedef 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) | ||
1531 | typedef 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 | |||
1548 | typedef struct { | ||
1549 | uint masksize; | ||
1550 | uint offset; | ||
1551 | uint patternoffset; | ||
1552 | uint patternsize; | ||
1553 | |||
1554 | |||
1555 | } wl_wowl_pattern_t; | ||
1556 | |||
1557 | typedef struct { | ||
1558 | uint count; | ||
1559 | wl_wowl_pattern_t pattern[1]; | ||
1560 | } wl_wowl_pattern_list_t; | ||
1561 | |||
1562 | typedef struct { | ||
1563 | uint8 pci_wakeind; | ||
1564 | uint16 ucode_wakeind; | ||
1565 | } wl_wowl_wakeind_t; | ||
1566 | |||
1567 | |||
1568 | typedef 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 | |||
1600 | typedef 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 | |||
1617 | typedef 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 | |||
1627 | typedef 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 | |||
1655 | typedef 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 | |||
1660 | typedef 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 | |||
1665 | typedef 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) | ||
49 | typedef 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 | |||
55 | static bcm_static_buf_t *bcm_static_buf = 0; | ||
56 | |||
57 | #define MAX_STATIC_PKT_NUM 8 | ||
58 | typedef 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; | ||
64 | static bcm_static_pkt_t *bcm_static_skb = 0; | ||
65 | |||
66 | #endif | ||
67 | typedef 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 | |||
75 | struct 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 | |||
85 | static 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 | |||
138 | int | ||
139 | osl_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 | |||
150 | void * dhd_os_prealloc(int section, unsigned long size); | ||
151 | osl_t * | ||
152 | osl_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 | |||
227 | void | ||
228 | osl_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 | |||
246 | void* | ||
247 | osl_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 | |||
265 | void | ||
266 | osl_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 | ||
296 | void* | ||
297 | osl_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 | |||
359 | void | ||
360 | osl_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 | ||
379 | uint32 | ||
380 | osl_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 | |||
400 | void | ||
401 | osl_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 | |||
421 | uint | ||
422 | osl_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 | |||
430 | uint | ||
431 | osl_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 | |||
438 | static void | ||
439 | osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write) | ||
440 | { | ||
441 | } | ||
442 | |||
443 | void | ||
444 | osl_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 | |||
449 | void | ||
450 | osl_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 | |||
457 | void* | ||
458 | osl_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 | } | ||
497 | original: | ||
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 | |||
511 | void | ||
512 | osl_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 | |||
543 | uint | ||
544 | osl_malloced(osl_t *osh) | ||
545 | { | ||
546 | ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); | ||
547 | return (osh->malloced); | ||
548 | } | ||
549 | |||
550 | uint | ||
551 | osl_malloc_failed(osl_t *osh) | ||
552 | { | ||
553 | ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC))); | ||
554 | return (osh->failed); | ||
555 | } | ||
556 | |||
557 | void* | ||
558 | osl_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 | |||
565 | void | ||
566 | osl_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 | |||
573 | uint | ||
574 | osl_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 | |||
583 | void | ||
584 | osl_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 | |||
594 | void | ||
595 | osl_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 | |||
608 | void * | ||
609 | osl_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 | /* ----------------------------------------------------------------------- */ | ||
45 | void | ||
46 | miniopt_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 | /* ----------------------------------------------------------------------- */ | ||
61 | int | ||
62 | miniopt(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 | |||
158 | exit: | ||
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 */ | ||
42 | static uint _sb_coreidx(si_info_t *sii, uint32 sba); | ||
43 | static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus, uint32 sbba, | ||
44 | uint ncores); | ||
45 | static uint32 _sb_coresba(si_info_t *sii); | ||
46 | static 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 | |||
61 | static uint32 | ||
62 | sb_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 | |||
92 | static void | ||
93 | sb_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 | |||
135 | uint | ||
136 | sb_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 | |||
147 | uint | ||
148 | sb_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 | |||
159 | void | ||
160 | sb_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' */ | ||
177 | static 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 */ | ||
189 | static 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 | |||
231 | uint | ||
232 | sb_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 | |||
243 | uint | ||
244 | sb_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 */ | ||
258 | void | ||
259 | sb_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 */ | ||
277 | uint32 | ||
278 | sb_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 */ | ||
303 | uint32 | ||
304 | sb_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 | |||
327 | bool | ||
328 | sb_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 | */ | ||
350 | uint | ||
351 | sb_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 | ||
456 | static 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 */ | ||
547 | void | ||
548 | sb_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 | */ | ||
569 | void * | ||
570 | sb_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 | */ | ||
594 | static 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 */ | ||
647 | static volatile uint32 * | ||
648 | sb_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 */ | ||
681 | int | ||
682 | sb_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 */ | ||
695 | uint32 | ||
696 | sb_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 */ | ||
706 | uint32 | ||
707 | sb_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 */ | ||
718 | void | ||
719 | sb_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 | |||
747 | void | ||
748 | sb_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 | |||
793 | disable: | ||
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 | */ | ||
804 | void | ||
805 | sb_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 | |||
850 | void | ||
851 | sb_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 | |||
906 | uint32 | ||
907 | sb_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 | |||
958 | uint32 | ||
959 | sb_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 | |||
982 | uint32 | ||
983 | sb_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 */ | ||
50 | static 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); | ||
52 | static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid, void *sdh); | ||
53 | static 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 */ | ||
58 | static uint32 si_gpioreservation = 0; | ||
59 | static 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 | */ | ||
72 | si_t * | ||
73 | si_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 */ | ||
97 | static si_info_t ksii; | ||
98 | |||
99 | static uint32 wd_msticks; /* watchdog timer ticks normalized to ms */ | ||
100 | |||
101 | /* generic kernel variant of si_attach() */ | ||
102 | si_t * | ||
103 | si_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 | |||
139 | static bool | ||
140 | si_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 | |||
183 | static bool | ||
184 | si_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 | |||
291 | static si_info_t * | ||
292 | si_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 */ | ||
412 | void | ||
413 | si_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 | |||
442 | void * | ||
443 | si_osh(si_t *sih) | ||
444 | { | ||
445 | si_info_t *sii; | ||
446 | |||
447 | sii = SI_INFO(sih); | ||
448 | return sii->osh; | ||
449 | } | ||
450 | |||
451 | void | ||
452 | si_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 */ | ||
465 | void | ||
466 | si_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 | |||
482 | void | ||
483 | si_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 | |||
491 | uint | ||
492 | si_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 | |||
508 | uint | ||
509 | si_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 | |||
521 | void | ||
522 | si_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 | |||
532 | uint | ||
533 | si_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 | |||
541 | uint | ||
542 | si_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 */ | ||
551 | uint | ||
552 | si_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 | |||
576 | uint | ||
577 | si_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 | |||
589 | bool | ||
590 | si_backplane64(si_t *sih) | ||
591 | { | ||
592 | return ((sih->cccaps & CC_CAP_BKPLN64) != 0); | ||
593 | } | ||
594 | |||
595 | uint | ||
596 | si_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 */ | ||
609 | uint | ||
610 | si_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 */ | ||
631 | uint | ||
632 | si_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 */ | ||
643 | void * | ||
644 | si_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 | */ | ||
659 | void * | ||
660 | si_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 | |||
678 | void * | ||
679 | si_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 */ | ||
692 | void *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 */ | ||
708 | void 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 | |||
718 | int | ||
719 | si_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 | |||
731 | uint32 | ||
732 | si_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 | |||
744 | uint32 | ||
745 | si_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 | |||
757 | uint32 | ||
758 | si_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 | |||
770 | void | ||
771 | si_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 | |||
781 | uint32 | ||
782 | si_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 | |||
794 | bool | ||
795 | si_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 | |||
807 | void | ||
808 | si_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 | |||
820 | uint | ||
821 | si_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 | |||
833 | void | ||
834 | si_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 | |||
842 | void | ||
843 | si_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 | |||
851 | void | ||
852 | si_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 */ | ||
859 | int | ||
860 | si_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 | |||
883 | static uint32 | ||
884 | factor6(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 */ | ||
898 | uint32 | ||
899 | si_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' */ | ||
983 | void | ||
984 | si_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 */ | ||
1006 | void | ||
1007 | si_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 */ | ||
1020 | void | ||
1021 | si_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 */ | ||
1058 | void * | ||
1059 | si_gpiosetcore(si_t *sih) | ||
1060 | { | ||
1061 | return (si_setcoreidx(sih, SI_CC_IDX)); | ||
1062 | } | ||
1063 | |||
1064 | /* mask&set gpiocontrol bits */ | ||
1065 | uint32 | ||
1066 | si_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 */ | ||
1087 | uint32 | ||
1088 | si_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 */ | ||
1109 | uint32 | ||
1110 | si_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 */ | ||
1131 | uint32 | ||
1132 | si_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 | |||
1166 | uint32 | ||
1167 | si_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 */ | ||
1197 | uint32 | ||
1198 | si_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 */ | ||
1211 | uint32 | ||
1212 | si_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 */ | ||
1232 | uint32 | ||
1233 | si_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 */ | ||
1253 | uint32 | ||
1254 | si_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 */ | ||
1267 | uint32 | ||
1268 | si_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 | |||
1281 | uint32 | ||
1282 | si_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 | |||
1295 | uint32 | ||
1296 | si_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 | |||
1317 | void * | ||
1318 | si_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 | |||
1346 | void | ||
1347 | si_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 | |||
1378 | void | ||
1379 | si_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 | |||
1400 | uint32 | ||
1401 | si_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 */ | ||
1416 | uint32 | ||
1417 | si_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, ®s->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 | |||
1467 | done: | ||
1468 | INTR_RESTORE(sii, intr_val); | ||
1469 | |||
1470 | return memsize; | ||
1471 | } | ||
1472 | |||
1473 | |||
1474 | void | ||
1475 | si_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 */ | ||
1507 | bool | ||
1508 | si_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 | |||
37 | typedef uint32 (*si_intrsoff_t)(void *intr_arg); | ||
38 | typedef void (*si_intrsrestore_t)(void *intr_arg, uint32 arg); | ||
39 | typedef bool (*si_intrsenabled_t)(void *intr_arg); | ||
40 | |||
41 | typedef 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 */ | ||
50 | typedef 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 | |||
66 | typedef 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 */ | ||
154 | extern void sb_scan(si_t *sih, void *regs, uint devid); | ||
155 | extern uint sb_coreid(si_t *sih); | ||
156 | extern uint sb_flag(si_t *sih); | ||
157 | extern void sb_setint(si_t *sih, int siflag); | ||
158 | extern uint sb_corevendor(si_t *sih); | ||
159 | extern uint sb_corerev(si_t *sih); | ||
160 | extern uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); | ||
161 | extern bool sb_iscoreup(si_t *sih); | ||
162 | extern void *sb_setcoreidx(si_t *sih, uint coreidx); | ||
163 | extern uint32 sb_core_cflags(si_t *sih, uint32 mask, uint32 val); | ||
164 | extern void sb_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); | ||
165 | extern uint32 sb_core_sflags(si_t *sih, uint32 mask, uint32 val); | ||
166 | extern void sb_commit(si_t *sih); | ||
167 | extern uint32 sb_base(uint32 admatch); | ||
168 | extern uint32 sb_size(uint32 admatch); | ||
169 | extern void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits); | ||
170 | extern void sb_core_tofixup(si_t *sih); | ||
171 | extern void sb_core_disable(si_t *sih, uint32 bits); | ||
172 | extern uint32 sb_addrspace(si_t *sih, uint asidx); | ||
173 | extern uint32 sb_addrspacesize(si_t *sih, uint asidx); | ||
174 | extern int sb_numaddrspaces(si_t *sih); | ||
175 | |||
176 | extern uint32 sb_set_initiator_to(si_t *sih, uint32 to, uint idx); | ||
177 | |||
178 | |||
179 | |||
180 | /* Wake-on-wireless-LAN (WOWL) */ | ||
181 | extern bool sb_pci_pmecap(si_t *sih); | ||
182 | struct osl_info; | ||
183 | extern bool sb_pci_fastpmecap(struct osl_info *osh); | ||
184 | extern bool sb_pci_pmeclr(si_t *sih); | ||
185 | extern void sb_pci_pmeen(si_t *sih); | ||
186 | extern uint sb_pcie_readreg(void *sih, uint addrtype, uint offset); | ||
187 | |||
188 | /* AMBA Interconnect exported externs */ | ||
189 | extern si_t *ai_attach(uint pcidev, osl_t *osh, void *regs, uint bustype, | ||
190 | void *sdh, char **vars, uint *varsz); | ||
191 | extern si_t *ai_kattach(osl_t *osh); | ||
192 | extern void ai_scan(si_t *sih, void *regs, uint devid); | ||
193 | |||
194 | extern uint ai_flag(si_t *sih); | ||
195 | extern void ai_setint(si_t *sih, int siflag); | ||
196 | extern uint ai_coreidx(si_t *sih); | ||
197 | extern uint ai_corevendor(si_t *sih); | ||
198 | extern uint ai_corerev(si_t *sih); | ||
199 | extern bool ai_iscoreup(si_t *sih); | ||
200 | extern void *ai_setcoreidx(si_t *sih, uint coreidx); | ||
201 | extern uint32 ai_core_cflags(si_t *sih, uint32 mask, uint32 val); | ||
202 | extern void ai_core_cflags_wo(si_t *sih, uint32 mask, uint32 val); | ||
203 | extern uint32 ai_core_sflags(si_t *sih, uint32 mask, uint32 val); | ||
204 | extern uint ai_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val); | ||
205 | extern void ai_core_reset(si_t *sih, uint32 bits, uint32 resetbits); | ||
206 | extern void ai_core_disable(si_t *sih, uint32 bits); | ||
207 | extern int ai_numaddrspaces(si_t *sih); | ||
208 | extern uint32 ai_addrspace(si_t *sih, uint asidx); | ||
209 | extern uint32 ai_addrspacesize(si_t *sih, uint asidx); | ||
210 | extern 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 | |||
43 | typedef void wlc_info_t; | ||
44 | typedef void wl_info_t; | ||
45 | typedef 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 | ||
99 | static struct net_device *priv_dev; | ||
100 | static bool ap_cfg_running = FALSE; | ||
101 | bool ap_fw_loaded = FALSE; | ||
102 | static long ap_cfg_pid = -1; | ||
103 | struct net_device *ap_net_dev = NULL; | ||
104 | struct semaphore ap_eth_sema; | ||
105 | static struct completion ap_cfg_exited; | ||
106 | static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap); | ||
107 | static 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 | |||
115 | static int g_onoff = G_WLAN_SET_ON; | ||
116 | wl_iw_extra_params_t g_wl_iw_params; | ||
117 | static struct mutex wl_cache_lock; | ||
118 | |||
119 | extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status, | ||
120 | uint32 reason, char* stringBuf, uint buflen); | ||
121 | #include <bcmsdbus.h> | ||
122 | extern void dhd_customer_gpio_wlan_ctrl(int onoff); | ||
123 | extern uint dhd_dev_reset(struct net_device *dev, uint8 flag); | ||
124 | extern void dhd_dev_init_ioctl(struct net_device *dev); | ||
125 | int dev_iw_write_cfg1_bss_var(struct net_device *dev, int val); | ||
126 | |||
127 | uint 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 | |||
151 | extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); | ||
152 | extern 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 | |||
160 | static void *g_scan = NULL; | ||
161 | static volatile uint g_scan_specified_ssid; | ||
162 | static wlc_ssid_t g_specific_ssid; | ||
163 | |||
164 | static wlc_ssid_t g_ssid; | ||
165 | |||
166 | bool btcoex_is_sco_active(struct net_device *dev); | ||
167 | static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl; | ||
168 | #if defined(CONFIG_FIRST_SCAN) | ||
169 | static volatile uint g_first_broadcast_scan; | ||
170 | static 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) | ||
190 | static void wl_iw_free_ss_cache(void); | ||
191 | static int wl_iw_run_ss_cache_timer(int kick_off); | ||
192 | #endif | ||
193 | #if defined(CONFIG_FIRST_SCAN) | ||
194 | int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); | ||
195 | #endif | ||
196 | static 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 | ||
201 | typedef struct iscan_buf { | ||
202 | struct iscan_buf * next; | ||
203 | char iscan_buf[WLC_IW_ISCAN_MAXLEN]; | ||
204 | } iscan_buf_t; | ||
205 | |||
206 | typedef 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 | ||
235 | static void wl_iw_bt_flag_set(struct net_device *dev, bool set); | ||
236 | static void wl_iw_bt_release(void); | ||
237 | |||
238 | typedef 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 | |||
245 | typedef 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 | |||
258 | bt_info_t *g_bt = NULL; | ||
259 | static void wl_iw_bt_timerfunc(ulong data); | ||
260 | iscan_info_t *g_iscan = NULL; | ||
261 | static void wl_iw_timerfunc(ulong data); | ||
262 | static void wl_iw_set_event_mask(struct net_device *dev); | ||
263 | static int | ||
264 | wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action); | ||
265 | #endif | ||
266 | static int | ||
267 | wl_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 | ||
275 | static int | ||
276 | wl_iw_get_scan( | ||
277 | struct net_device *dev, | ||
278 | struct iw_request_info *info, | ||
279 | struct iw_point *dwrq, | ||
280 | char *extra | ||
281 | ); | ||
282 | |||
283 | static uint | ||
284 | wl_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 | |||
292 | static 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 | |||
305 | static 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 | |||
318 | static int | ||
319 | dev_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 | |||
376 | static int | ||
377 | dev_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 *)(®), 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 | |||
399 | static int | ||
400 | dev_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 *)®_addr[0], (char *)addr, 4); | ||
410 | memcpy((char *)®_addr[4], (char *)val, 4); | ||
411 | |||
412 | return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); | ||
413 | } | ||
414 | |||
415 | |||
416 | static int | ||
417 | dev_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) | ||
433 | static int | ||
434 | dev_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 | |||
453 | static int | ||
454 | dev_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 | ||
473 | static int | ||
474 | dev_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 | |||
490 | static int | ||
491 | dev_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 | |||
511 | static int | ||
512 | dev_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 | ||
537 | static int | ||
538 | wl_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 | |||
563 | static int | ||
564 | wl_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 | |||
596 | static int | ||
597 | wl_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 | |||
625 | static int | ||
626 | wl_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 | |||
651 | static int | ||
652 | wl_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 | |||
699 | exit: | ||
700 | wrqu->data.length = p - extra + 1; | ||
701 | return error; | ||
702 | } | ||
703 | |||
704 | #ifdef CUSTOMER_HW2 | ||
705 | static int | ||
706 | wl_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 | |||
758 | bool 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, ¶m27); | ||
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 | |||
797 | static 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 *)®addr, (char *)&saved_reg50); | ||
860 | regaddr = 51; | ||
861 | dev_wlc_intvar_set_reg(dev, "btc_params", | ||
862 | (char *)®addr, (char *)&saved_reg51); | ||
863 | regaddr = 64; | ||
864 | dev_wlc_intvar_set_reg(dev, "btc_params", | ||
865 | (char *)®addr, (char *)&saved_reg64); | ||
866 | regaddr = 65; | ||
867 | dev_wlc_intvar_set_reg(dev, "btc_params", | ||
868 | (char *)®addr, (char *)&saved_reg65); | ||
869 | regaddr = 71; | ||
870 | dev_wlc_intvar_set_reg(dev, "btc_params", | ||
871 | (char *)®addr, (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 | |||
887 | static int | ||
888 | wl_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 | |||
916 | static int | ||
917 | wl_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 *)®addr, (char *)&saved_reg66); | ||
1023 | regaddr = 41; | ||
1024 | dev_wlc_intvar_set_reg(dev, "btc_params", \ | ||
1025 | (char *)®addr, (char *)&saved_reg41); | ||
1026 | regaddr = 68; | ||
1027 | dev_wlc_intvar_set_reg(dev, "btc_params", \ | ||
1028 | (char *)®addr, (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 | |||
1047 | static int | ||
1048 | wl_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 | |||
1078 | int | ||
1079 | wl_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 | |||
1102 | static int | ||
1103 | wl_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 | |||
1129 | static int | ||
1130 | wl_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 | |||
1163 | static int | ||
1164 | wl_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 | |||
1206 | exit: | ||
1207 | wrqu->data.length = p - extra + 1; | ||
1208 | net_os_wake_unlock(dev); | ||
1209 | return error; | ||
1210 | } | ||
1211 | |||
1212 | |||
1213 | static int | ||
1214 | wl_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 | |||
1240 | static int | ||
1241 | wl_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 | |||
1274 | exit: | ||
1275 | wrqu->data.length = p - extra + 1; | ||
1276 | net_os_wake_unlock(dev); | ||
1277 | return error; | ||
1278 | } | ||
1279 | |||
1280 | #ifdef PNO_SUPPORT | ||
1281 | |||
1282 | static int | ||
1283 | wl_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 | |||
1306 | exit: | ||
1307 | wrqu->data.length = p - extra + 1; | ||
1308 | net_os_wake_unlock(dev); | ||
1309 | return error; | ||
1310 | } | ||
1311 | |||
1312 | |||
1313 | |||
1314 | static int | ||
1315 | wl_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 | |||
1341 | exit: | ||
1342 | wrqu->data.length = p - extra + 1; | ||
1343 | net_os_wake_unlock(dev); | ||
1344 | return error; | ||
1345 | } | ||
1346 | |||
1347 | |||
1348 | |||
1349 | static int | ||
1350 | wl_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 | |||
1478 | exit_proc: | ||
1479 | net_os_wake_unlock(dev); | ||
1480 | return res; | ||
1481 | } | ||
1482 | #endif | ||
1483 | |||
1484 | static int | ||
1485 | wl_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 | |||
1531 | int | ||
1532 | wl_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 | |||
1556 | int | ||
1557 | wl_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 | |||
1601 | static int | ||
1602 | wl_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 | |||
1669 | static int | ||
1670 | wl_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 | ||
1705 | static struct ap_profile my_ap; | ||
1706 | static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap); | ||
1707 | static int get_assoc_sta_list(struct net_device *dev, char *buf, int len); | ||
1708 | static 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 | ||
1714 | int get_parmeter_from_string( | ||
1715 | char **str_ptr, const char *token, int param_type, void *dst, int param_max_len); | ||
1716 | |||
1717 | #endif | ||
1718 | |||
1719 | int 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 | |||
1730 | int 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 | |||
1744 | int 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 | |||
1765 | static 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 | ||
1779 | char 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 | ||
1837 | int 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 | ||
1877 | static 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 | ||
1932 | static 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 | |||
2018 | func_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 | ||
2029 | static 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 | ||
2118 | static 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 | ||
2155 | struct iw_request_info | ||
2156 | { | ||
2157 | __u16 cmd; | ||
2158 | __u16 flags; | ||
2159 | }; | ||
2160 | |||
2161 | typedef int (*iw_handler)(struct net_device *dev, | ||
2162 | struct iw_request_info *info, | ||
2163 | void *wrqu, | ||
2164 | char *extra); | ||
2165 | #endif | ||
2166 | |||
2167 | static int | ||
2168 | wl_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 | |||
2198 | static int | ||
2199 | wl_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 | |||
2213 | static int | ||
2214 | wl_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 | |||
2264 | static int | ||
2265 | wl_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 | |||
2285 | static int | ||
2286 | wl_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 | |||
2321 | static int | ||
2322 | wl_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 | |||
2344 | static int | ||
2345 | wl_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 | |||
2536 | static int | ||
2537 | rssi_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 | |||
2553 | static int | ||
2554 | wl_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 | |||
2578 | static int | ||
2579 | wl_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 | |||
2608 | static int | ||
2609 | wl_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 | |||
2642 | static int | ||
2643 | wl_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 | |||
2699 | static int | ||
2700 | wl_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 | ||
2719 | static int | ||
2720 | wl_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 | ||
2761 | static int | ||
2762 | wl_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 | ||
2841 | static int | ||
2842 | wl_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 | |||
2916 | static int | ||
2917 | wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid) | ||
2918 | { | ||
2919 | int err = 0; | ||
2920 | |||
2921 | memcpy(¶ms->bssid, ðer_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(¶ms->ssid, ssid, sizeof(wlc_ssid_t)); | ||
2939 | |||
2940 | return err; | ||
2941 | } | ||
2942 | |||
2943 | static int | ||
2944 | wl_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 | |||
2968 | static void | ||
2969 | wl_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 | } | ||
2980 | static 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 | |||
2992 | static uint32 | ||
2993 | wl_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 | |||
3059 | static 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 | |||
3071 | static 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 | |||
3087 | static 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 | |||
3188 | static void | ||
3189 | wl_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 | |||
3195 | static int | ||
3196 | wl_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 | |||
3218 | static void | ||
3219 | wl_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 | |||
3242 | static int | ||
3243 | wl_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 | |||
3264 | void | ||
3265 | wl_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 | |||
3277 | static void | ||
3278 | wl_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 | |||
3314 | static int | ||
3315 | wl_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 | |||
3378 | static int | ||
3379 | wl_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 | |||
3405 | static int | ||
3406 | wl_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 | |||
3442 | static int | ||
3443 | wl_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 | ||
3514 | int | ||
3515 | wl_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 | |||
3562 | static int | ||
3563 | wl_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 | |||
3659 | set_scan_end: | ||
3660 | net_os_wake_unlock(dev); | ||
3661 | return ret; | ||
3662 | } | ||
3663 | #endif | ||
3664 | |||
3665 | #if WIRELESS_EXT > 17 | ||
3666 | static bool | ||
3667 | ie_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 | |||
3684 | static bool | ||
3685 | ie_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 | |||
3703 | static 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 | |||
3725 | int 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 | |||
3730 | static int | ||
3731 | wl_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 | ||
3815 | static uint | ||
3816 | wl_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 | |||
3913 | static int | ||
3914 | wl_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) | ||
4091 | static int | ||
4092 | wl_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 | |||
4273 | static int | ||
4274 | wl_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, ðer_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 | |||
4326 | static int | ||
4327 | wl_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 | |||
4358 | static int | ||
4359 | wl_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 | |||
4382 | static int | ||
4383 | wl_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 | |||
4403 | static 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 | |||
4463 | static 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 | |||
4483 | static int | ||
4484 | wl_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 | |||
4508 | static int | ||
4509 | wl_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 | |||
4530 | static int | ||
4531 | wl_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 | |||
4555 | static int | ||
4556 | wl_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 | |||
4577 | static int | ||
4578 | wl_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 | |||
4617 | static int | ||
4618 | wl_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 | ||
4645 | static int | ||
4646 | wl_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 | |||
4691 | static int | ||
4692 | wl_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 | |||
4732 | static int | ||
4733 | wl_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 | |||
4827 | static int | ||
4828 | wl_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 | |||
4890 | static int | ||
4891 | wl_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 | |||
4911 | static int | ||
4912 | wl_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 | ||
4934 | static int | ||
4935 | wl_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 | |||
4962 | static int | ||
4963 | wl_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 | |||
4976 | static int | ||
4977 | wl_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 | ||
5095 | struct { | ||
5096 | pmkid_list_t pmkids; | ||
5097 | pmkid_t foo[MAXPMKID-1]; | ||
5098 | } pmkid_list; | ||
5099 | |||
5100 | static int | ||
5101 | wl_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 | |||
5210 | static int | ||
5211 | wl_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 | |||
5222 | static int | ||
5223 | wl_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 *)¶mval, 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 *)¶mval, 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 *)¶mval, 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 | |||
5464 | static int | ||
5465 | wl_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 *)¶mval, 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 *)¶mval, 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 *)¶mval, 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 | |||
5581 | static int ap_macmode = MACLIST_MODE_DISABLED; | ||
5582 | static struct mflist ap_black_list; | ||
5583 | static int | ||
5584 | wl_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 | ||
5643 | extern 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 | ||
5649 | int 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 | |||
5659 | int 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 | |||
5681 | int 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 | ||
5698 | static 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 | |||
5743 | int 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 | |||
5763 | static int | ||
5764 | wl_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 | |||
5860 | exit: | ||
5861 | |||
5862 | return err; | ||
5863 | } | ||
5864 | |||
5865 | |||
5866 | static 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 | |||
5968 | exit_proc: | ||
5969 | |||
5970 | kfree(extra); | ||
5971 | |||
5972 | return res; | ||
5973 | } | ||
5974 | |||
5975 | |||
5976 | static int | ||
5977 | wl_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 | |||
6167 | exit_proc: | ||
6168 | net_os_wake_unlock(dev); | ||
6169 | return res; | ||
6170 | } | ||
6171 | |||
6172 | #endif | ||
6173 | |||
6174 | #ifdef SOFTAP | ||
6175 | #ifndef AP_ONLY | ||
6176 | |||
6177 | static 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 | |||
6223 | fail: | ||
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 | ||
6233 | static int last_auto_channel = 6; | ||
6234 | #endif | ||
6235 | static 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 | |||
6303 | fail : | ||
6304 | return res; | ||
6305 | } | ||
6306 | |||
6307 | |||
6308 | static 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 | ||
6505 | fail: | ||
6506 | WL_SOFTAP(("%s exit with %d\n", __FUNCTION__, res)); | ||
6507 | |||
6508 | net_os_wake_unlock(dev); | ||
6509 | |||
6510 | return res; | ||
6511 | } | ||
6512 | |||
6513 | |||
6514 | static 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 | |||
6682 | int 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 | |||
6753 | static 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 | |||
6805 | static 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 | |||
6847 | static 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 | |||
6895 | exit_proc: | ||
6896 | return ret; | ||
6897 | } | ||
6898 | #endif | ||
6899 | |||
6900 | #ifdef SOFTAP | ||
6901 | static 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 | |||
6939 | static int | ||
6940 | iwpriv_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 | |||
6981 | static int | ||
6982 | get_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 | |||
6992 | void 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 | |||
6998 | static int | ||
6999 | set_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 | ||
7091 | int 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 | |||
7101 | int 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 | |||
7160 | static 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 | |||
7301 | static 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 | ||
7385 | static 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 | |||
7432 | static 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 | |||
7543 | const 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 | |||
7559 | int 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 | |||
7673 | wl_iw_ioctl_done: | ||
7674 | |||
7675 | net_os_wake_unlock(dev); | ||
7676 | |||
7677 | return ret; | ||
7678 | } | ||
7679 | |||
7680 | |||
7681 | bool | ||
7682 | wl_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 | |||
7762 | static bool | ||
7763 | wl_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 | |||
7781 | void | ||
7782 | wl_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 | ||
8085 | wl_iw_event_end: | ||
8086 | net_os_wake_unlock(dev); | ||
8087 | #endif | ||
8088 | } | ||
8089 | |||
8090 | int 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 | |||
8170 | done: | ||
8171 | return res; | ||
8172 | } | ||
8173 | static void | ||
8174 | wl_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 | |||
8208 | static void | ||
8209 | wl_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 | |||
8218 | static 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 | |||
8291 | static void | ||
8292 | wl_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 | |||
8308 | static int | ||
8309 | wl_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 | |||
8340 | int 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 | |||
8417 | void 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 | |||
65 | typedef struct wl_iw_extra_params { | ||
66 | int target_channel; | ||
67 | } wl_iw_extra_params_t; | ||
68 | |||
69 | struct 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) \ | ||
110 | if (!extra) { \ | ||
111 | WL_ERROR(("%s: error : extra is null pointer\n", __FUNCTION__)); \ | ||
112 | return -EINVAL; \ | ||
113 | } | ||
114 | |||
115 | typedef 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 | |||
136 | typedef 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 | |||
145 | typedef 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 | |||
155 | typedef 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 | ||
166 | struct 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 | ||
181 | struct mflist { | ||
182 | uint count; | ||
183 | struct ether_addr ea[16]; | ||
184 | }; | ||
185 | |||
186 | struct 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> | ||
194 | extern const struct iw_handler_def wl_iw_handler_def; | ||
195 | #endif | ||
196 | |||
197 | extern int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | ||
198 | extern void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data); | ||
199 | extern int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats); | ||
200 | int wl_iw_attach(struct net_device *dev, void * dhdp); | ||
201 | void wl_iw_detach(void); | ||
202 | int wl_control_wl_start(struct net_device *dev); | ||
203 | |||
204 | extern int net_os_wake_lock(struct net_device *dev); | ||
205 | extern int net_os_wake_unlock(struct net_device *dev); | ||
206 | extern int net_os_wake_lock_timeout(struct net_device *dev); | ||
207 | extern int net_os_wake_lock_timeout_enable(struct net_device *dev); | ||
208 | extern int net_os_set_suspend_disable(struct net_device *dev, int val); | ||
209 | extern int net_os_set_suspend(struct net_device *dev, int val); | ||
210 | extern int net_os_set_dtim_skip(struct net_device *dev, int val); | ||
211 | extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec); | ||
212 | extern char *dhd_bus_country_get(struct net_device *dev); | ||
213 | extern 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 | |||
231 | extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); | ||
232 | extern int dhd_pno_clean(dhd_pub_t *dhd); | ||
233 | extern 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); | ||
235 | extern int dhd_pno_get_status(dhd_pub_t *dhd); | ||
236 | extern int dhd_dev_pno_reset(struct net_device *dev); | ||
237 | extern 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); | ||
239 | extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); | ||
240 | extern int dhd_dev_get_pno_status(struct net_device *dev); | ||
241 | extern 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 | |||
253 | typedef 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 | |||
275 | typedef 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 | |||
294 | extern int wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, \ | ||
295 | int channel_num, int *bytes_left); | ||
296 | |||
297 | extern 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 | |||
300 | extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, \ | ||
301 | int max, int *bytes_left); | ||
302 | |||
303 | extern int wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max); | ||
304 | |||
305 | extern int wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num); | ||
306 | |||
307 | #endif | ||
308 | |||
309 | #endif | ||