staging: brcm80211: add fullmac driver

This patch to the existing bcm80211 directory in the staging tree adds fullmac
driver support for the BCM4329 SDIO chip from Broadcom.  Configuration of the
mac80211 driver or the fullmac driver can be done through menuconfig.

Signed-off-by: Henry Ptasinski <henryp@broadcom.com>
Signed-off-by: Nohee Ko <noheek@broadcom.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Henry Ptasinski 2010-09-20 22:33:12 -07:00 committed by Greg Kroah-Hartman
parent c7fcf25525
commit cf2b448852
47 changed files with 27755 additions and 30 deletions

View File

@ -12,3 +12,4 @@ config BRCM80211_PCI
depends on BRCM80211
default y
source "drivers/staging/brcm80211/brcmfmac/Kconfig"

View File

@ -63,3 +63,4 @@ EXTRA_CFLAGS += $(PCI_CFLAGS)
$(MODULEPFX)-objs = $(BRCM80211_OFILES) $(PCIFILES)
endif
obj-$(CONFIG_BRCMFMAC) += brcmfmac/

View File

@ -32,6 +32,8 @@ Other
=====
- wlc_mac80211.[ch], wl_mac80211.[ch] and linux_osl.c all need to be refactored
and combined.
- Merge files that are partially duplicated between the softmac and fullmac
drivers
- Replace driver's proprietary ssb interface with generic kernel ssb module
(only used when compiling for SDIO).
- PCI and SDIO support are currently #ifdef'ed exclusive of each other, which

View File

@ -0,0 +1,15 @@
menuconfig BRCMFMAC
tristate "Broadcom fullmac wireless cards support"
depends on MMC
depends on CFG80211
select FW_LOADER
select WIRELESS_EXT
select WEXT_PRIV
---help---
This module adds support for wireless adapters based on
Broadcom fullmac chipsets.
This driver uses the kernel's wireless extensions subsystem.
If you choose to build a module, it'll be called brcmfmac.ko. Say M if
unsure.

View File

@ -0,0 +1,38 @@
#
# Makefile fragment for Broadcom 802.11n Networking Device Driver
#
# Copyright (c) 2010 Broadcom Corporation
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
DHDCFLAGS = -DLINUX -DBCMDRIVER -DBCMDONGLEHOST -DDHDTHREAD -DBCMWPA2 \
-DUNRELEASEDCHIP -Dlinux -DDHD_SDALIGN=64 -DMAX_HDR_READ=64 \
-DDHD_FIRSTREAD=64 -DDHD_GPL -DDHD_SCHED -DBDC -DTOE -DDHD_BCMEVENTS \
-DSHOW_EVENTS -DBCMSDIO -DDHD_GPL -DBCMLXSDMMC -DBCMPLATFORM_BUS \
-Wall -Wstrict-prototypes -Werror -DOEM_CHROMIUMOS -DEMBEDDED_PLATFORM \
-DARP_OFFLOAD_SUPPORT -DPKT_FILTER_SUPPORT -DBRCM_FULLMAC \
-DCONFIG_CFG80211 -DMMC_SDIO_ABORT -DDHD_DEBUG_TRAP -DBCMDBG -DDHD_DEBUG \
-Idrivers/staging/brcm80211/brcmfmac \
-Idrivers/staging/brcm80211/brcmfmac/include \
-Idrivers/staging/brcm80211/include \
-Idrivers/staging/brcm80211/util
DHDOFILES = dhd_linux.o linux_osl.o bcmutils.o dhd_common.o dhd_custom_gpio.o \
wl_iw.o wl_cfg80211.o ../util/siutils.o ../util/sbutils.o ../util/aiutils.o ../util/hndpmu.o bcmwifi.o dhd_sdio.o \
dhd_linux_sched.o dhd_cdc.o bcmsdh_sdmmc.o bcmsdh.o bcmsdh_linux.o \
bcmsdh_sdmmc_linux.o
obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
brcmfmac-objs += $(DHDOFILES)
EXTRA_CFLAGS = $(DHDCFLAGS)
EXTRA_LDFLAGS += --strip-debug

View File

@ -0,0 +1,36 @@
Broadcom fullmac driver
This is production driver.
What's here
===========
- Completely open source host driver, no binary object files
- Features Broadcom's OneDriver architecture (single source base for
supported chips and architectures)
- On-chip firmware loaded using standard request_firmware()
- Support for BCM4329(SDIO)
What's done
==========
- Integration with cfg80211 stack
- Most of Mac functionality is performed in dongle
- A-MPDU single stream rates
- BCM4329: Dualband, Single stream, 20MHz channels
Firmware installation
======================
Firmware is available from the Linux firmware repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/dwmw2/linux-firmware.git
http://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git
https://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git
For 4329 chip, copy brcm/bcm4329-fullmac-4-218-248-5.bin and
bcm4329-fullmac-4-218-248-5.txt to /lib/firmware/brcm
Contact Info:
=============
Brett Rudley brudley@broadcom.com
Henry Ptasinski henryp@broadcom.com
Nohee Ko noheek@broadcom.com

View File

@ -0,0 +1,628 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* ****************** BCMSDH Interface Functions *************************** */
#include <typedefs.h>
#include <bcmdevs.h>
#include <bcmendian.h>
#include <bcmutils.h>
#include <hndsoc.h>
#include <siutils.h>
#include <osl.h>
#include <bcmsdh.h> /* BRCM API for SDIO
clients (such as wl, dhd) */
#include <bcmsdbus.h> /* common SDIO/controller interface */
#include <sbsdio.h> /* BRCM sdio device core */
#include <sdio.h> /* sdio spec */
#define SDIOH_API_ACCESS_RETRY_LIMIT 2
const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL;
struct bcmsdh_info {
bool init_success; /* underlying driver successfully attached */
void *sdioh; /* handler for sdioh */
uint32 vendevid; /* Target Vendor and Device ID on SD bus */
osl_t *osh;
bool regfail; /* Save status of last
reg_read/reg_write call */
uint32 sbwad; /* Save backplane window address */
};
/* local copy of bcm sd handler */
bcmsdh_info_t *l_bcmsdh = NULL;
#if defined(OOB_INTR_ONLY) && defined(HW_OOB)
extern int sdioh_enable_hw_oob_intr(void *sdioh, bool enable);
void bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable)
{
sdioh_enable_hw_oob_intr(sdh->sdioh, enable);
}
#endif
bcmsdh_info_t *bcmsdh_attach(osl_t *osh, void *cfghdl, void **regsva, uint irq)
{
bcmsdh_info_t *bcmsdh;
if ((bcmsdh =
(bcmsdh_info_t *) MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) {
BCMSDH_ERROR(("bcmsdh_attach: out of memory, "
"malloced %d bytes\n", MALLOCED(osh)));
return NULL;
}
bzero((char *)bcmsdh, sizeof(bcmsdh_info_t));
/* save the handler locally */
l_bcmsdh = bcmsdh;
if (!(bcmsdh->sdioh = sdioh_attach(osh, cfghdl, irq))) {
bcmsdh_detach(osh, bcmsdh);
return NULL;
}
bcmsdh->osh = osh;
bcmsdh->init_success = TRUE;
*regsva = (uint32 *) SI_ENUM_BASE;
/* Report the BAR, to fix if needed */
bcmsdh->sbwad = SI_ENUM_BASE;
return bcmsdh;
}
int bcmsdh_detach(osl_t *osh, void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
if (bcmsdh != NULL) {
if (bcmsdh->sdioh) {
sdioh_detach(osh, bcmsdh->sdioh);
bcmsdh->sdioh = NULL;
}
MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t));
}
l_bcmsdh = NULL;
return 0;
}
int
bcmsdh_iovar_op(void *sdh, const char *name,
void *params, int plen, void *arg, int len, bool set)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set);
}
bool bcmsdh_intr_query(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
bool on;
ASSERT(bcmsdh);
status = sdioh_interrupt_query(bcmsdh->sdioh, &on);
if (SDIOH_API_SUCCESS(status))
return FALSE;
else
return on;
}
int bcmsdh_intr_enable(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
ASSERT(bcmsdh);
status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE);
return SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR;
}
int bcmsdh_intr_disable(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
ASSERT(bcmsdh);
status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE);
return SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR;
}
int bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
ASSERT(bcmsdh);
status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh);
return SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR;
}
int bcmsdh_intr_dereg(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
ASSERT(bcmsdh);
status = sdioh_interrupt_deregister(bcmsdh->sdioh);
return SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR;
}
#if defined(DHD_DEBUG)
bool bcmsdh_intr_pending(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
ASSERT(sdh);
return sdioh_interrupt_pending(bcmsdh->sdioh);
}
#endif
int bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
{
ASSERT(sdh);
/* don't support yet */
return BCME_UNSUPPORTED;
}
uint8 bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
int32 retry = 0;
#endif
uint8 data = 0;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
do {
if (retry) /* wait for 1 ms till bus get settled down */
OSL_DELAY(1000);
#endif
status =
sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr,
(uint8 *) &data);
#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
} while (!SDIOH_API_SUCCESS(status)
&& (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
#endif
if (err)
*err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n",
__func__, fnc_num, addr, data));
return data;
}
void
bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
int32 retry = 0;
#endif
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
do {
if (retry) /* wait for 1 ms till bus get settled down */
OSL_DELAY(1000);
#endif
status =
sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr,
(uint8 *) &data);
#ifdef SDIOH_API_ACCESS_RETRY_LIMIT
} while (!SDIOH_API_SUCCESS(status)
&& (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
#endif
if (err)
*err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR;
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n",
__func__, fnc_num, addr, data));
}
uint32 bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
uint32 data = 0;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
status =
sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ,
fnc_num, addr, &data, 4);
if (err)
*err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n",
__func__, fnc_num, addr, data));
return data;
}
void
bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data,
int *err)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
status =
sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL,
SDIOH_WRITE, fnc_num, addr, &data, 4);
if (err)
*err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n",
__func__, fnc_num, addr, data));
}
int bcmsdh_cis_read(void *sdh, uint func, uint8 * cis, uint length)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
uint8 *tmp_buf, *tmp_ptr;
uint8 *ptr;
bool ascii = func & ~0xf;
func &= 0x7;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
ASSERT(cis);
ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT);
status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length);
if (ascii) {
/* Move binary bits to tmp and format them
into the provided buffer. */
if ((tmp_buf = (uint8 *) MALLOC(bcmsdh->osh, length)) == NULL) {
BCMSDH_ERROR(("%s: out of memory\n", __func__));
return BCME_NOMEM;
}
bcopy(cis, tmp_buf, length);
for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4);
tmp_ptr++) {
ptr += sprintf((char *)ptr, "%.2x ", *tmp_ptr & 0xff);
if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0)
ptr += sprintf((char *)ptr, "\n");
}
MFREE(bcmsdh->osh, tmp_buf, length);
}
return SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR;
}
static int bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address)
{
int err = 0;
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
(address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
if (!err)
bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
(address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
if (!err)
bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
(address >> 24) & SBSDIO_SBADDRHIGH_MASK,
&err);
return err;
}
uint32 bcmsdh_reg_read(void *sdh, uint32 addr, uint size)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
uint32 word = 0;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, ", __func__, addr));
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
if (bar0 != bcmsdh->sbwad) {
if (bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0))
return 0xFFFFFFFF;
bcmsdh->sbwad = bar0;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (size == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL,
SDIOH_READ, SDIO_FUNC_1, addr, &word, size);
bcmsdh->regfail = !(SDIOH_API_SUCCESS(status));
BCMSDH_INFO(("uint32data = 0x%x\n", word));
/* if ok, return appropriately masked word */
if (SDIOH_API_SUCCESS(status)) {
switch (size) {
case sizeof(uint8):
return word & 0xff;
case sizeof(uint16):
return word & 0xffff;
case sizeof(uint32):
return word;
default:
bcmsdh->regfail = TRUE;
}
}
/* otherwise, bad sdio access or invalid size */
BCMSDH_ERROR(("%s: error reading addr 0x%04x size %d\n", __func__,
addr, size));
return 0xFFFFFFFF;
}
uint32 bcmsdh_reg_write(void *sdh, uint32 addr, uint size, uint32 data)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
__func__, addr, size * 8, data));
if (!bcmsdh)
bcmsdh = l_bcmsdh;
ASSERT(bcmsdh->init_success);
if (bar0 != bcmsdh->sbwad) {
if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0)))
return err;
bcmsdh->sbwad = bar0;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (size == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status =
sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL,
SDIOH_WRITE, SDIO_FUNC_1, addr, &data, size);
bcmsdh->regfail = !(SDIOH_API_SUCCESS(status));
if (SDIOH_API_SUCCESS(status))
return 0;
BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n",
__func__, data, addr, size));
return 0xFFFFFFFF;
}
bool bcmsdh_regfail(void *sdh)
{
return ((bcmsdh_info_t *) sdh)->regfail;
}
int
bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags,
uint8 *buf, uint nbytes, void *pkt,
bcmsdh_cmplt_fn_t complete, void *handle)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
uint incr_fix;
uint width;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
ASSERT(bcmsdh);
ASSERT(bcmsdh->init_success);
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
__func__, fn, addr, nbytes));
/* Async not implemented yet */
ASSERT(!(flags & SDIO_REQ_ASYNC));
if (flags & SDIO_REQ_ASYNC)
return BCME_UNSUPPORTED;
if (bar0 != bcmsdh->sbwad) {
if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0)))
return err;
bcmsdh->sbwad = bar0;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
if (width == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
SDIOH_READ, fn, addr, width, nbytes, buf,
pkt);
return SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR;
}
int
bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags,
uint8 *buf, uint nbytes, void *pkt,
bcmsdh_cmplt_fn_t complete, void *handle)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
uint incr_fix;
uint width;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
ASSERT(bcmsdh);
ASSERT(bcmsdh->init_success);
BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
__func__, fn, addr, nbytes));
/* Async not implemented yet */
ASSERT(!(flags & SDIO_REQ_ASYNC));
if (flags & SDIO_REQ_ASYNC)
return BCME_UNSUPPORTED;
if (bar0 != bcmsdh->sbwad) {
if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, bar0)))
return err;
bcmsdh->sbwad = bar0;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
if (width == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
SDIOH_WRITE, fn, addr, width, nbytes, buf,
pkt);
return SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR;
}
int bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
SDIOH_API_RC status;
ASSERT(bcmsdh);
ASSERT(bcmsdh->init_success);
ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0);
addr &= SBSDIO_SB_OFT_ADDR_MASK;
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status =
sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC,
(rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1,
addr, 4, nbytes, buf, NULL);
return SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR;
}
int bcmsdh_abort(void *sdh, uint fn)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
return sdioh_abort(bcmsdh->sdioh, fn);
}
int bcmsdh_start(void *sdh, int stage)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
return sdioh_start(bcmsdh->sdioh, stage);
}
int bcmsdh_stop(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
return sdioh_stop(bcmsdh->sdioh);
}
int bcmsdh_query_device(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0;
return bcmsdh->vendevid;
}
uint bcmsdh_query_iofnum(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
return sdioh_query_iofnum(bcmsdh->sdioh);
}
int bcmsdh_reset(bcmsdh_info_t *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
return sdioh_sdio_reset(bcmsdh->sdioh);
}
void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh)
{
ASSERT(sdh);
return sdh->sdioh;
}
/* Function to pass device-status bits to DHD. */
uint32 bcmsdh_get_dstatus(void *sdh)
{
return 0;
}
uint32 bcmsdh_cur_sbwad(void *sdh)
{
bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *) sdh;
if (!bcmsdh)
bcmsdh = l_bcmsdh;
return bcmsdh->sbwad;
}
void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev)
{
return;
}

View File

@ -0,0 +1,657 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
* @file bcmsdh_linux.c
*/
#define __UNDEF_NO_VERSION__
#include <typedefs.h>
#include <linuxver.h>
#include <linux/pci.h>
#include <linux/completion.h>
#include <osl.h>
#include <pcicfg.h>
#include <bcmdefs.h>
#include <bcmdevs.h>
#if defined(OOB_INTR_ONLY)
#include <linux/irq.h>
extern void dhdsdio_isr(void *args);
#include <bcmutils.h>
#include <dngl_stats.h>
#include <dhd.h>
#endif /* defined(OOB_INTR_ONLY) */
#if defined(CONFIG_MACH_SANDGATE2G) || defined(CONFIG_MACH_LOGICPD_PXA270)
#if !defined(BCMPLATFORM_BUS)
#define BCMPLATFORM_BUS
#endif /* !defined(BCMPLATFORM_BUS) */
#include <linux/platform_device.h>
#endif /* CONFIG_MACH_SANDGATE2G */
/**
* SDIO Host Controller info
*/
typedef struct bcmsdh_hc bcmsdh_hc_t;
struct bcmsdh_hc {
bcmsdh_hc_t *next;
#ifdef BCMPLATFORM_BUS
struct device *dev; /* platform device handle */
#else
struct pci_dev *dev; /* pci device handle */
#endif /* BCMPLATFORM_BUS */
osl_t *osh;
void *regs; /* SDIO Host Controller address */
bcmsdh_info_t *sdh; /* SDIO Host Controller handle */
void *ch;
unsigned int oob_irq;
unsigned long oob_flags; /* OOB Host specifiction
as edge and etc */
bool oob_irq_registered;
#if defined(OOB_INTR_ONLY)
spinlock_t irq_lock;
#endif
};
static bcmsdh_hc_t *sdhcinfo = NULL;
/* driver info, initialized when bcmsdh_register is called */
static bcmsdh_driver_t drvinfo = { NULL, NULL };
/* debugging macros */
#define SDLX_MSG(x)
/**
* Checks to see if vendor and device IDs match a supported SDIO Host Controller.
*/
bool bcmsdh_chipmatch(uint16 vendor, uint16 device)
{
/* Add other vendors and devices as required */
#ifdef BCMSDIOH_STD
/* Check for Arasan host controller */
if (vendor == VENDOR_SI_IMAGE)
return TRUE;
/* Check for BRCM 27XX Standard host controller */
if (device == BCM27XX_SDIOH_ID && vendor == VENDOR_BROADCOM)
return TRUE;
/* Check for BRCM Standard host controller */
if (device == SDIOH_FPGA_ID && vendor == VENDOR_BROADCOM)
return TRUE;
/* Check for TI PCIxx21 Standard host controller */
if (device == PCIXX21_SDIOH_ID && vendor == VENDOR_TI)
return TRUE;
if (device == PCIXX21_SDIOH0_ID && vendor == VENDOR_TI)
return TRUE;
/* Ricoh R5C822 Standard SDIO Host */
if (device == R5C822_SDIOH_ID && vendor == VENDOR_RICOH)
return TRUE;
/* JMicron Standard SDIO Host */
if (device == JMICRON_SDIOH_ID && vendor == VENDOR_JMICRON)
return TRUE;
#endif /* BCMSDIOH_STD */
#ifdef BCMSDIOH_SPI
/* This is the PciSpiHost. */
if (device == SPIH_FPGA_ID && vendor == VENDOR_BROADCOM) {
printf("Found PCI SPI Host Controller\n");
return TRUE;
}
#endif /* BCMSDIOH_SPI */
return FALSE;
}
#if defined(BCMPLATFORM_BUS)
#if defined(BCMLXSDMMC)
/* forward declarations */
int bcmsdh_probe(struct device *dev);
EXPORT_SYMBOL(bcmsdh_probe);
int bcmsdh_remove(struct device *dev);
EXPORT_SYMBOL(bcmsdh_remove);
#else
/* forward declarations */
static int __devinit bcmsdh_probe(struct device *dev);
static int __devexit bcmsdh_remove(struct device *dev);
#endif /* BCMLXSDMMC */
#ifndef BCMLXSDMMC
static struct device_driver bcmsdh_driver = {
.name = "pxa2xx-mci",
.bus = &platform_bus_type,
.probe = bcmsdh_probe,
.remove = bcmsdh_remove,
.suspend = NULL,
.resume = NULL,
};
#endif /* BCMLXSDMMC */
#ifndef BCMLXSDMMC
static
#endif /* BCMLXSDMMC */
int bcmsdh_probe(struct device *dev)
{
osl_t *osh = NULL;
bcmsdh_hc_t *sdhc = NULL;
ulong regs = 0;
bcmsdh_info_t *sdh = NULL;
#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
struct platform_device *pdev;
struct resource *r;
#endif /* BCMLXSDMMC */
int irq = 0;
uint32 vendevid;
unsigned long irq_flags = 0;
#if !defined(BCMLXSDMMC) && defined(BCMPLATFORM_BUS)
pdev = to_platform_device(dev);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!r || irq == NO_IRQ)
return -ENXIO;
#endif /* BCMLXSDMMC */
#if defined(OOB_INTR_ONLY)
#ifdef HW_OOB
irq_flags =
IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL |
IORESOURCE_IRQ_SHAREABLE;
#else
irq_flags = IRQF_TRIGGER_FALLING;
#endif /* HW_OOB */
irq = dhd_customer_oob_irq_map(&irq_flags);
if (irq < 0) {
SDLX_MSG(("%s: Host irq is not defined\n", __func__));
return 1;
}
#endif /* defined(OOB_INTR_ONLY) */
/* allocate SDIO Host Controller state info */
if (!(osh = osl_attach(dev, PCI_BUS, FALSE))) {
SDLX_MSG(("%s: osl_attach failed\n", __func__));
goto err;
}
if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
__func__, MALLOCED(osh)));
goto err;
}
bzero(sdhc, sizeof(bcmsdh_hc_t));
sdhc->osh = osh;
sdhc->dev = (void *)dev;
#ifdef BCMLXSDMMC
if (!(sdh = bcmsdh_attach(osh, (void *)0,
(void **)&regs, irq))) {
SDLX_MSG(("%s: bcmsdh_attach failed\n", __func__));
goto err;
}
#else
if (!(sdh = bcmsdh_attach(osh, (void *)r->start,
(void **)&regs, irq))) {
SDLX_MSG(("%s: bcmsdh_attach failed\n", __func__));
goto err;
}
#endif /* BCMLXSDMMC */
sdhc->sdh = sdh;
sdhc->oob_irq = irq;
sdhc->oob_flags = irq_flags;
sdhc->oob_irq_registered = FALSE; /* to make sure.. */
#if defined(OOB_INTR_ONLY)
spin_lock_init(&sdhc->irq_lock);
#endif
/* chain SDIO Host Controller info together */
sdhc->next = sdhcinfo;
sdhcinfo = sdhc;
/* Read the vendor/device ID from the CIS */
vendevid = bcmsdh_query_device(sdh);
/* try to attach to the target device */
if (!(sdhc->ch = drvinfo.attach((vendevid >> 16),
(vendevid & 0xFFFF), 0, 0, 0, 0,
(void *)regs, NULL, sdh))) {
SDLX_MSG(("%s: device attach failed\n", __func__));
goto err;
}
return 0;
/* error handling */
err:
if (sdhc) {
if (sdhc->sdh)
bcmsdh_detach(sdhc->osh, sdhc->sdh);
MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
}
if (osh)
osl_detach(osh);
return -ENODEV;
}
#ifndef BCMLXSDMMC
static
#endif /* BCMLXSDMMC */
int bcmsdh_remove(struct device *dev)
{
bcmsdh_hc_t *sdhc, *prev;
osl_t *osh;
sdhc = sdhcinfo;
drvinfo.detach(sdhc->ch);
bcmsdh_detach(sdhc->osh, sdhc->sdh);
/* find the SDIO Host Controller state for this pdev
and take it out from the list */
for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
if (sdhc->dev == (void *)dev) {
if (prev)
prev->next = sdhc->next;
else
sdhcinfo = NULL;
break;
}
prev = sdhc;
}
if (!sdhc) {
SDLX_MSG(("%s: failed\n", __func__));
return 0;
}
/* release SDIO Host Controller info */
osh = sdhc->osh;
MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
osl_detach(osh);
#if !defined(BCMLXSDMMC)
dev_set_drvdata(dev, NULL);
#endif /* !defined(BCMLXSDMMC) */
return 0;
}
#else /* BCMPLATFORM_BUS */
#if !defined(BCMLXSDMMC)
/* forward declarations for PCI probe and remove functions. */
static int __devinit bcmsdh_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent);
static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev);
/**
* pci id table
*/
static struct pci_device_id bcmsdh_pci_devid[] __devinitdata = {
{
.vendor = PCI_ANY_ID,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.class = 0,
.class_mask = 0,
.driver_data = 0,
},
{0,}
};
MODULE_DEVICE_TABLE(pci, bcmsdh_pci_devid);
/**
* SDIO Host Controller pci driver info
*/
static struct pci_driver bcmsdh_pci_driver = {
.node = {},
.name = "bcmsdh",
.id_table = bcmsdh_pci_devid,
.probe = bcmsdh_pci_probe,
.remove = bcmsdh_pci_remove,
.suspend = NULL,
.resume = NULL,
};
extern uint sd_pci_slot; /* Force detection to a particular PCI */
/* slot only . Allows for having multiple */
/* WL devices at once in a PC */
/* Only one instance of dhd will be */
/* usable at a time */
/* Upper word is bus number, */
/* lower word is slot number */
/* Default value of 0xFFFFffff turns this */
/* off */
module_param(sd_pci_slot, uint, 0);
/**
* Detect supported SDIO Host Controller and attach if found.
*
* Determine if the device described by pdev is a supported SDIO Host
* Controller. If so, attach to it and attach to the target device.
*/
static int __devinit
bcmsdh_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
osl_t *osh = NULL;
bcmsdh_hc_t *sdhc = NULL;
ulong regs;
bcmsdh_info_t *sdh = NULL;
int rc;
if (sd_pci_slot != 0xFFFFffff) {
if (pdev->bus->number != (sd_pci_slot >> 16) ||
PCI_SLOT(pdev->devfn) != (sd_pci_slot & 0xffff)) {
SDLX_MSG(("%s: %s: bus %X, slot %X, vend %X, dev %X\n",
__func__,
bcmsdh_chipmatch(pdev->vendor, pdev->device) ?
"Found compatible SDIOHC" :
"Probing unknown device",
pdev->bus->number, PCI_SLOT(pdev->devfn),
pdev->vendor, pdev->device));
return -ENODEV;
}
SDLX_MSG(("%s: %s: bus %X, slot %X, vendor %X, device %X "
"(good PCI location)\n", __func__,
bcmsdh_chipmatch(pdev->vendor, pdev->device) ?
"Using compatible SDIOHC" : "WARNING, forced use "
"of unkown device",
pdev->bus->number, PCI_SLOT(pdev->devfn), pdev->vendor,
pdev->device));
}
if ((pdev->vendor == VENDOR_TI)
&& ((pdev->device == PCIXX21_FLASHMEDIA_ID)
|| (pdev->device == PCIXX21_FLASHMEDIA0_ID))) {
uint32 config_reg;
SDLX_MSG(("%s: Disabling TI FlashMedia Controller.\n",
__func__));
if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
SDLX_MSG(("%s: osl_attach failed\n", __func__));
goto err;
}
config_reg = OSL_PCI_READ_CONFIG(osh, 0x4c, 4);
/*
* Set MMC_SD_DIS bit in FlashMedia Controller.
* Disbling the SD/MMC Controller in the FlashMedia Controller
* allows the Standard SD Host Controller to take over control
* of the SD Slot.
*/
config_reg |= 0x02;
OSL_PCI_WRITE_CONFIG(osh, 0x4c, 4, config_reg);
osl_detach(osh);
}
/* match this pci device with what we support */
/* we can't solely rely on this to believe it is
our SDIO Host Controller! */
if (!bcmsdh_chipmatch(pdev->vendor, pdev->device))
return -ENODEV;
/* this is a pci device we might support */
SDLX_MSG(("%s: Found possible SDIO Host Controller: "
"bus %d slot %d func %d irq %d\n", __func__,
pdev->bus->number, PCI_SLOT(pdev->devfn),
PCI_FUNC(pdev->devfn), pdev->irq));
/* use bcmsdh_query_device() to get the vendor ID of the target device
* so it will eventually appear in the Broadcom string on the console
*/
/* allocate SDIO Host Controller state info */
if (!(osh = osl_attach(pdev, PCI_BUS, FALSE))) {
SDLX_MSG(("%s: osl_attach failed\n", __func__));
goto err;
}
if (!(sdhc = MALLOC(osh, sizeof(bcmsdh_hc_t)))) {
SDLX_MSG(("%s: out of memory, allocated %d bytes\n",
__func__, MALLOCED(osh)));
goto err;
}
bzero(sdhc, sizeof(bcmsdh_hc_t));
sdhc->osh = osh;
sdhc->dev = pdev;
/* map to address where host can access */
pci_set_master(pdev);
rc = pci_enable_device(pdev);
if (rc) {
SDLX_MSG(("%s: Cannot enable PCI device\n", __func__));
goto err;
}
if (!
(sdh =
bcmsdh_attach(osh, (void *)(uintptr) pci_resource_start(pdev, 0),
(void **)&regs, pdev->irq))) {
SDLX_MSG(("%s: bcmsdh_attach failed\n", __func__));
goto err;
}
sdhc->sdh = sdh;
/* try to attach to the target device */
if (!(sdhc->ch = drvinfo.attach(VENDOR_BROADCOM, /* pdev->vendor, */
bcmsdh_query_device(sdh) & 0xFFFF, 0, 0,
0, 0, (void *)regs, NULL, sdh))) {
SDLX_MSG(("%s: device attach failed\n", __func__));
goto err;
}
/* chain SDIO Host Controller info together */
sdhc->next = sdhcinfo;
sdhcinfo = sdhc;
return 0;
/* error handling */
err:
if (sdhc->sdh)
bcmsdh_detach(sdhc->osh, sdhc->sdh);
if (sdhc)
MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
if (osh)
osl_detach(osh);
return -ENODEV;
}
/**
* Detach from target devices and SDIO Host Controller
*/
static void __devexit bcmsdh_pci_remove(struct pci_dev *pdev)
{
bcmsdh_hc_t *sdhc, *prev;
osl_t *osh;
/* find the SDIO Host Controller state for this
pdev and take it out from the list */
for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) {
if (sdhc->dev == pdev) {
if (prev)
prev->next = sdhc->next;
else
sdhcinfo = NULL;
break;
}
prev = sdhc;
}
if (!sdhc)
return;
drvinfo.detach(sdhc->ch);
bcmsdh_detach(sdhc->osh, sdhc->sdh);
/* release SDIO Host Controller info */
osh = sdhc->osh;
MFREE(osh, sdhc, sizeof(bcmsdh_hc_t));
osl_detach(osh);
}
#endif /* BCMLXSDMMC */
#endif /* BCMPLATFORM_BUS */
extern int sdio_function_init(void);
int bcmsdh_register(bcmsdh_driver_t *driver)
{
int error = 0;
drvinfo = *driver;
#if defined(BCMPLATFORM_BUS)
#if defined(BCMLXSDMMC)
SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n"));
error = sdio_function_init();
#else
SDLX_MSG(("Intel PXA270 SDIO Driver\n"));
error = driver_register(&bcmsdh_driver);
#endif /* defined(BCMLXSDMMC) */
return error;
#endif /* defined(BCMPLATFORM_BUS) */
#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
if (!(error = pci_register_driver(&bcmsdh_pci_driver)))
return 0;
SDLX_MSG(("%s: pci_module_init failed 0x%x\n", __func__, error));
#endif /* BCMPLATFORM_BUS */
return error;
}
extern void sdio_function_cleanup(void);
void bcmsdh_unregister(void)
{
#if defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
driver_unregister(&bcmsdh_driver);
#endif
#if defined(BCMLXSDMMC)
sdio_function_cleanup();
#endif /* BCMLXSDMMC */
#if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC)
pci_unregister_driver(&bcmsdh_pci_driver);
#endif /* BCMPLATFORM_BUS */
}
#if defined(OOB_INTR_ONLY)
void bcmsdh_oob_intr_set(bool enable)
{
static bool curstate = 1;
unsigned long flags;
spin_lock_irqsave(&sdhcinfo->irq_lock, flags);
if (curstate != enable) {
if (enable)
enable_irq(sdhcinfo->oob_irq);
else
disable_irq_nosync(sdhcinfo->oob_irq);
curstate = enable;
}
spin_unlock_irqrestore(&sdhcinfo->irq_lock, flags);
}
static irqreturn_t wlan_oob_irq(int irq, void *dev_id)
{
dhd_pub_t *dhdp;
dhdp = (dhd_pub_t *) dev_get_drvdata(sdhcinfo->dev);
bcmsdh_oob_intr_set(0);
if (dhdp == NULL) {
SDLX_MSG(("Out of band GPIO interrupt fired way too early\n"));
return IRQ_HANDLED;
}
WAKE_LOCK_TIMEOUT(dhdp, WAKE_LOCK_TMOUT, 25);
dhdsdio_isr((void *)dhdp->bus);
return IRQ_HANDLED;
}
int bcmsdh_register_oob_intr(void *dhdp)
{
int error = 0;
SDLX_MSG(("%s Enter\n", __func__));
sdhcinfo->oob_flags =
IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL |
IORESOURCE_IRQ_SHAREABLE;
dev_set_drvdata(sdhcinfo->dev, dhdp);
if (!sdhcinfo->oob_irq_registered) {
SDLX_MSG(("%s IRQ=%d Type=%X\n", __func__,
(int)sdhcinfo->oob_irq, (int)sdhcinfo->oob_flags));
/* Refer to customer Host IRQ docs about
proper irqflags definition */
error =
request_irq(sdhcinfo->oob_irq, wlan_oob_irq,
sdhcinfo->oob_flags, "bcmsdh_sdmmc", NULL);
if (error)
return -ENODEV;
set_irq_wake(sdhcinfo->oob_irq, 1);
sdhcinfo->oob_irq_registered = TRUE;
}
return 0;
}
void bcmsdh_unregister_oob_intr(void)
{
SDLX_MSG(("%s: Enter\n", __func__));
set_irq_wake(sdhcinfo->oob_irq, 0);
disable_irq(sdhcinfo->oob_irq); /* just in case.. */
free_irq(sdhcinfo->oob_irq, NULL);
sdhcinfo->oob_irq_registered = FALSE;
}
#endif /* defined(OOB_INTR_ONLY) */
/* Module parameters specific to each host-controller driver */
extern uint sd_msglevel; /* Debug message level */
module_param(sd_msglevel, uint, 0);
extern uint sd_power; /* 0 = SD Power OFF,
1 = SD Power ON. */
module_param(sd_power, uint, 0);
extern uint sd_clock; /* SD Clock Control, 0 = SD Clock OFF,
1 = SD Clock ON */
module_param(sd_clock, uint, 0);
extern uint sd_divisor; /* Divisor (-1 means external clock) */
module_param(sd_divisor, uint, 0);
extern uint sd_sdmode; /* Default is SD4, 0=SPI, 1=SD1, 2=SD4 */
module_param(sd_sdmode, uint, 0);
extern uint sd_hiok; /* Ok to use hi-speed mode */
module_param(sd_hiok, uint, 0);
extern uint sd_f2_blocksize;
module_param(sd_f2_blocksize, int, 0);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,236 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <typedefs.h>
#include <bcmutils.h>
#include <sdio.h> /* SDIO Specs */
#include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
#include <sdiovar.h> /* to get msglevel bit values */
#include <linux/sched.h> /* request_irq() */
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#if !defined(SDIO_VENDOR_ID_BROADCOM)
#define SDIO_VENDOR_ID_BROADCOM 0x02d0
#endif /* !defined(SDIO_VENDOR_ID_BROADCOM) */
#define SDIO_DEVICE_ID_BROADCOM_DEFAULT 0x0000
#if !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB)
#define SDIO_DEVICE_ID_BROADCOM_4325_SDGWB 0x0492 /* BCM94325SDGWB */
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325_SDGWB) */
#if !defined(SDIO_DEVICE_ID_BROADCOM_4325)
#define SDIO_DEVICE_ID_BROADCOM_4325 0x0493
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4325) */
#if !defined(SDIO_DEVICE_ID_BROADCOM_4329)
#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */
#if !defined(SDIO_DEVICE_ID_BROADCOM_4319)
#define SDIO_DEVICE_ID_BROADCOM_4319 0x4319
#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4329) */
#include <bcmsdh_sdmmc.h>
#include <dhd_dbg.h>
#ifdef CONFIG_CFG80211
#include <wl_cfg80211.h>
#endif
extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd);
extern void sdioh_sdmmc_devintr_on(sdioh_info_t *sd);
int sdio_function_init(void);
void sdio_function_cleanup(void);
/* module param defaults */
static int clockoverride = 0;
module_param(clockoverride, int, 0644);
MODULE_PARM_DESC(clockoverride, "SDIO card clock override");
PBCMSDH_SDMMC_INSTANCE gInstance;
/* Maximum number of bcmsdh_sdmmc devices supported by driver */
#define BCMSDH_SDMMC_MAX_DEVICES 1
extern int bcmsdh_probe(struct device *dev);
extern int bcmsdh_remove(struct device *dev);
struct device sdmmc_dev;
static int bcmsdh_sdmmc_probe(struct sdio_func *func,
const struct sdio_device_id *id)
{
int ret = 0;
static struct sdio_func sdio_func_0;
sd_trace(("bcmsdh_sdmmc: %s Enter\n", __func__));
sd_trace(("sdio_bcmsdh: func->class=%x\n", func->class));
sd_trace(("sdio_vendor: 0x%04x\n", func->vendor));
sd_trace(("sdio_device: 0x%04x\n", func->device));
sd_trace(("Function#: 0x%04x\n", func->num));
if (func->num == 1) {
sdio_func_0.num = 0;
sdio_func_0.card = func->card;
gInstance->func[0] = &sdio_func_0;
if (func->device == 0x4) { /* 4318 */
gInstance->func[2] = NULL;
sd_trace(("NIC found, calling bcmsdh_probe...\n"));
ret = bcmsdh_probe(&sdmmc_dev);
}
}
gInstance->func[func->num] = func;
if (func->num == 2) {
#ifdef CONFIG_CFG80211
wl_cfg80211_sdio_func(func);
#endif
sd_trace(("F2 found, calling bcmsdh_probe...\n"));
ret = bcmsdh_probe(&sdmmc_dev);
}
return ret;
}
static void bcmsdh_sdmmc_remove(struct sdio_func *func)
{
sd_trace(("bcmsdh_sdmmc: %s Enter\n", __func__));
sd_info(("sdio_bcmsdh: func->class=%x\n", func->class));
sd_info(("sdio_vendor: 0x%04x\n", func->vendor));
sd_info(("sdio_device: 0x%04x\n", func->device));
sd_info(("Function#: 0x%04x\n", func->num));
if (func->num == 2) {
sd_trace(("F2 found, calling bcmsdh_remove...\n"));
bcmsdh_remove(&sdmmc_dev);
}
}
/* devices we support, null terminated */
static const struct sdio_device_id bcmsdh_sdmmc_ids[] = {
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_DEFAULT)},
{SDIO_DEVICE
(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325_SDGWB)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
{SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319)},
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(sdio, bcmsdh_sdmmc_ids);
static struct sdio_driver bcmsdh_sdmmc_driver = {
.probe = bcmsdh_sdmmc_probe,
.remove = bcmsdh_sdmmc_remove,
.name = "brcmfmac",
.id_table = bcmsdh_sdmmc_ids,
};
struct sdos_info {
sdioh_info_t *sd;
spinlock_t lock;
};
int sdioh_sdmmc_osinit(sdioh_info_t *sd)
{
struct sdos_info *sdos;
sdos = (struct sdos_info *)MALLOC(sd->osh, sizeof(struct sdos_info));
sd->sdos_info = (void *)sdos;
if (sdos == NULL)
return BCME_NOMEM;
sdos->sd = sd;
spin_lock_init(&sdos->lock);
return BCME_OK;
}
void sdioh_sdmmc_osfree(sdioh_info_t *sd)
{
struct sdos_info *sdos;
ASSERT(sd && sd->sdos_info);
sdos = (struct sdos_info *)sd->sdos_info;
MFREE(sd->osh, sdos, sizeof(struct sdos_info));
}
/* Interrupt enable/disable */
SDIOH_API_RC sdioh_interrupt_set(sdioh_info_t *sd, bool enable)
{
ulong flags;
struct sdos_info *sdos;
sd_trace(("%s: %s\n", __func__, enable ? "Enabling" : "Disabling"));
sdos = (struct sdos_info *)sd->sdos_info;
ASSERT(sdos);
#if !defined(OOB_INTR_ONLY)
if (enable && !(sd->intr_handler && sd->intr_handler_arg)) {
sd_err(("%s: no handler registered, will not enable\n",
__func__));
return SDIOH_API_RC_FAIL;
}
#endif /* !defined(OOB_INTR_ONLY) */
/* Ensure atomicity for enable/disable calls */
spin_lock_irqsave(&sdos->lock, flags);
sd->client_intr_enabled = enable;
if (enable)
sdioh_sdmmc_devintr_on(sd);
else
sdioh_sdmmc_devintr_off(sd);
spin_unlock_irqrestore(&sdos->lock, flags);
return SDIOH_API_RC_SUCCESS;
}
/*
* module init
*/
int sdio_function_init(void)
{
int error = 0;
sd_trace(("bcmsdh_sdmmc: %s Enter\n", __func__));
gInstance = kzalloc(sizeof(BCMSDH_SDMMC_INSTANCE), GFP_KERNEL);
if (!gInstance)
return -ENOMEM;
bzero(&sdmmc_dev, sizeof(sdmmc_dev));
error = sdio_register_driver(&bcmsdh_sdmmc_driver);
return error;
}
/*
* module cleanup
*/
extern int bcmsdh_remove(struct device *dev);
void sdio_function_cleanup(void)
{
sd_trace(("%s Enter\n", __func__));
sdio_unregister_driver(&bcmsdh_sdmmc_driver);
kfree(gInstance);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,170 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <typedefs.h>
#ifdef BCMDRIVER
#include <osl.h>
#include <bcmutils.h>
#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
#define tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
#else
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#endif
#include <bcmwifi.h>
#if defined(WIN32) && (defined(BCMDLL) || defined(WLMDLL))
#include <bcmstdlib.h>
#endif
char *wf_chspec_ntoa(chanspec_t chspec, char *buf)
{
const char *band, *bw, *sb;
uint channel;
band = "";
bw = "";
sb = "";
channel = CHSPEC_CHANNEL(chspec);
if ((CHSPEC_IS2G(chspec) && channel > CH_MAX_2G_CHANNEL) ||
(CHSPEC_IS5G(chspec) && channel <= CH_MAX_2G_CHANNEL))
band = (CHSPEC_IS2G(chspec)) ? "b" : "a";
if (CHSPEC_IS40(chspec)) {
if (CHSPEC_SB_UPPER(chspec)) {
sb = "u";
channel += CH_10MHZ_APART;
} else {
sb = "l";
channel -= CH_10MHZ_APART;
}
} else if (CHSPEC_IS10(chspec)) {
bw = "n";
}
snprintf(buf, 6, "%d%s%s%s", channel, band, bw, sb);
return buf;
}
chanspec_t wf_chspec_aton(char *a)
{
char *endp = NULL;
uint channel, band, bw, ctl_sb;
char c;
channel = strtoul(a, &endp, 10);
if (endp == a)
return 0;
if (channel > MAXCHANNEL)
return 0;
band =
((channel <=
CH_MAX_2G_CHANNEL) ? WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G);
bw = WL_CHANSPEC_BW_20;
ctl_sb = WL_CHANSPEC_CTL_SB_NONE;
a = endp;
c = tolower(a[0]);
if (c == '\0')
goto done;
if (c == 'a' || c == 'b') {
band = (c == 'a') ? WL_CHANSPEC_BAND_5G : WL_CHANSPEC_BAND_2G;
a++;
c = tolower(a[0]);
if (c == '\0')
goto done;
}
if (c == 'n') {
bw = WL_CHANSPEC_BW_10;
} else if (c == 'l') {
bw = WL_CHANSPEC_BW_40;
ctl_sb = WL_CHANSPEC_CTL_SB_LOWER;
if (channel <= (MAXCHANNEL - CH_20MHZ_APART))
channel += CH_10MHZ_APART;
else
return 0;
} else if (c == 'u') {
bw = WL_CHANSPEC_BW_40;
ctl_sb = WL_CHANSPEC_CTL_SB_UPPER;
if (channel > CH_20MHZ_APART)
channel -= CH_10MHZ_APART;
else
return 0;
} else {
return 0;
}
done:
return channel | band | bw | ctl_sb;
}
int wf_mhz2channel(uint freq, uint start_factor)
{
int ch = -1;
uint base;
int offset;
if (start_factor == 0) {
if (freq >= 2400 && freq <= 2500)
start_factor = WF_CHAN_FACTOR_2_4_G;
else if (freq >= 5000 && freq <= 6000)
start_factor = WF_CHAN_FACTOR_5_G;
}
if (freq == 2484 && start_factor == WF_CHAN_FACTOR_2_4_G)
return 14;
base = start_factor / 2;
if ((freq < base) || (freq > base + 1000))
return -1;
offset = freq - base;
ch = offset / 5;
if (offset != (ch * 5))
return -1;
if (start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 13))
return -1;
return ch;
}
int wf_channel2mhz(uint ch, uint start_factor)
{
int freq;
if ((start_factor == WF_CHAN_FACTOR_2_4_G && (ch < 1 || ch > 14)) ||
(ch <= 200))
freq = -1;
if ((start_factor == WF_CHAN_FACTOR_2_4_G) && (ch == 14))
freq = 2484;
else
freq = ch * 5 + start_factor / 2;
return freq;
}

View File

@ -0,0 +1,479 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/****************
* Common types *
*/
#ifndef _dhd_h_
#define _dhd_h_
#if defined(LINUX)
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/random.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
#if defined(CONFIG_HAS_WAKELOCK)
#include <linux/wakelock.h>
#endif /* defined (CONFIG_HAS_WAKELOCK) */
/* The kernel threading is sdio-specific */
#else /* LINUX */
#define ENOMEM 1
#define EFAULT 2
#define EINVAL 3
#define EIO 4
#define ETIMEDOUT 5
#define ERESTARTSYS 6
#endif /* LINUX */
#include <wlioctl.h>
/* Forward decls */
struct dhd_bus;
struct dhd_prot;
struct dhd_info;
/* The level of bus communication with the dongle */
enum dhd_bus_state {
DHD_BUS_DOWN, /* Not ready for frame transfers */
DHD_BUS_LOAD, /* Download access only (CPU reset) */
DHD_BUS_DATA /* Ready for frame transfers */
};
enum dhd_bus_wake_state {
WAKE_LOCK_OFF,
WAKE_LOCK_PRIV,
WAKE_LOCK_DPC,
WAKE_LOCK_IOCTL,
WAKE_LOCK_DOWNLOAD,
WAKE_LOCK_TMOUT,
WAKE_LOCK_WATCHDOG,
WAKE_LOCK_LINK_DOWN_TMOUT,
WAKE_LOCK_PNO_FIND_TMOUT,
WAKE_LOCK_SOFTAP_SET,
WAKE_LOCK_SOFTAP_STOP,
WAKE_LOCK_SOFTAP_START,
WAKE_LOCK_MAX
};
enum dhd_prealloc_index {
DHD_PREALLOC_PROT = 0,
DHD_PREALLOC_RXBUF,
DHD_PREALLOC_DATABUF,
DHD_PREALLOC_OSL_BUF
};
#ifdef DHD_USE_STATIC_BUF
extern void *dhd_os_prealloc(int section, unsigned long size);
#endif
/* Common structure for module and instance linkage */
typedef struct dhd_pub {
/* Linkage ponters */
osl_t *osh; /* OSL handle */
struct dhd_bus *bus; /* Bus module handle */
struct dhd_prot *prot; /* Protocol module handle */
struct dhd_info *info; /* Info module handle */
/* Internal dhd items */
bool up; /* Driver up/down (to OS) */
bool txoff; /* Transmit flow-controlled */
bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */
enum dhd_bus_state busstate;
uint hdrlen; /* Total DHD header length (proto + bus) */
uint maxctl; /* Max size rxctl request from proto to bus */
uint rxsz; /* Rx buffer size bus module should use */
uint8 wme_dp; /* wme discard priority */
/* Dongle media info */
bool iswl; /* Dongle-resident driver is wl */
ulong drv_version; /* Version of dongle-resident driver */
struct ether_addr mac; /* MAC address obtained from dongle */
dngl_stats_t dstats; /* Stats for dongle-based data */
/* Additional stats for the bus level */
ulong tx_packets; /* Data packets sent to dongle */
ulong tx_multicast; /* Multicast data packets sent to dongle */
ulong tx_errors; /* Errors in sending data to dongle */
ulong tx_ctlpkts; /* Control packets sent to dongle */
ulong tx_ctlerrs; /* Errors sending control frames to dongle */
ulong rx_packets; /* Packets sent up the network interface */
ulong rx_multicast; /* Multicast packets sent up the network
interface */
ulong rx_errors; /* Errors processing rx data packets */
ulong rx_ctlpkts; /* Control frames processed from dongle */
ulong rx_ctlerrs; /* Errors in processing rx control frames */
ulong rx_dropped; /* Packets dropped locally (no memory) */
ulong rx_flushed; /* Packets flushed due to
unscheduled sendup thread */
ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by
watchdog timer */
ulong rx_readahead_cnt; /* Number of packets where header read-ahead
was used. */
ulong tx_realloc; /* Number of tx packets we had to realloc for
headroom */
ulong fc_packets; /* Number of flow control pkts recvd */
/* Last error return */
int bcmerror;
uint tickcnt;
/* Last error from dongle */
int dongle_error;
/* Suspend disable flag flag */
int suspend_disable_flag; /* "1" to disable all extra powersaving
during suspend */
int in_suspend; /* flag set to 1 when early suspend called */
#ifdef PNO_SUPPORT
int pno_enable; /* pno status : "1" is pno enable */
#endif /* PNO_SUPPORT */
int dtim_skip; /* dtim skip , default 0 means wake each dtim */
/* Pkt filter defination */
char *pktfilter[100];
int pktfilter_count;
uint8 country_code[WLC_CNTRY_BUF_SZ];
char eventmask[WL_EVENTING_MASK_LEN];
#if defined(CONFIG_HAS_WAKELOCK)
struct wake_lock wakelock[WAKE_LOCK_MAX];
#endif /* defined (CONFIG_HAS_WAKELOCK) */
} dhd_pub_t;
#if defined(CONFIG_PM_SLEEP)
#define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
#define _DHD_PM_RESUME_WAIT(a, b) do {\
int retry = 0; \
while (dhd_mmc_suspend && retry++ != b) { \
wait_event_timeout(a, FALSE, HZ/100); \
} \
} while (0)
#define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 30)
#define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0)
#define DHD_PM_RESUME_RETURN_ERROR(a) \
do { if (dhd_mmc_suspend) return a; } while (0)
#define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0)
#define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a);
#define SPINWAIT_SLEEP(a, exp, us) do { \
uint countdown = (us) + 9999; \
while ((exp) && (countdown >= 10000)) { \
wait_event_timeout(a, FALSE, HZ/100); \
countdown -= 10000; \
} \
} while (0)
#else
#define DHD_PM_RESUME_WAIT_INIT(a)
#define DHD_PM_RESUME_WAIT(a)
#define DHD_PM_RESUME_WAIT_FOREVER(a)
#define DHD_PM_RESUME_RETURN_ERROR(a)
#define DHD_PM_RESUME_RETURN
#define DHD_SPINWAIT_SLEEP_INIT(a)
#define SPINWAIT_SLEEP(a, exp, us) do { \
uint countdown = (us) + 9; \
while ((exp) && (countdown >= 10)) { \
OSL_DELAY(10); \
countdown -= 10; \
} \
} while (0)
#endif /* defined(CONFIG_PM_SLEEP) */
#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */
static inline void MUTEX_LOCK_INIT(dhd_pub_t *dhdp)
{
}
static inline void MUTEX_LOCK(dhd_pub_t *dhdp)
{
}
static inline void MUTEX_UNLOCK(dhd_pub_t *dhdp)
{
}
static inline void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t *dhdp)
{
}
static inline void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t *dhdp)
{
}
static inline void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t *dhdp)
{
}
static inline void MUTEX_LOCK_WL_SCAN_SET_INIT(void)
{
}
static inline void MUTEX_LOCK_WL_SCAN_SET(void)
{
}
static inline void MUTEX_UNLOCK_WL_SCAN_SET(void)
{
}
static inline void WAKE_LOCK_INIT(dhd_pub_t *dhdp, int index, char *y)
{
#if defined(CONFIG_HAS_WAKELOCK)
wake_lock_init(&dhdp->wakelock[index], WAKE_LOCK_SUSPEND, y);
#endif /* defined (CONFIG_HAS_WAKELOCK) */
}
static inline void WAKE_LOCK(dhd_pub_t *dhdp, int index)
{
#if defined(CONFIG_HAS_WAKELOCK)
wake_lock(&dhdp->wakelock[index]);
#endif /* defined (CONFIG_HAS_WAKELOCK) */
}
static inline void WAKE_UNLOCK(dhd_pub_t *dhdp, int index)
{
#if defined(CONFIG_HAS_WAKELOCK)
wake_unlock(&dhdp->wakelock[index]);
#endif /* defined (CONFIG_HAS_WAKELOCK) */
}
static inline void WAKE_LOCK_TIMEOUT(dhd_pub_t *dhdp, int index, long time)
{
#if defined(CONFIG_HAS_WAKELOCK)
wake_lock_timeout(&dhdp->wakelock[index], time);
#endif /* defined (CONFIG_HAS_WAKELOCK) */
}
static inline void WAKE_LOCK_DESTROY(dhd_pub_t *dhdp, int index)
{
#if defined(CONFIG_HAS_WAKELOCK)
wake_lock_destroy(&dhdp->wakelock[index]);
#endif /* defined (CONFIG_HAS_WAKELOCK) */
}
typedef struct dhd_if_event {
uint8 ifidx;
uint8 action;
uint8 flags;
uint8 bssidx;
} dhd_if_event_t;
/*
* Exported from dhd OS modules (dhd_linux/dhd_ndis)
*/
/* To allow osl_attach/detach calls from os-independent modules */
osl_t *dhd_osl_attach(void *pdev, uint bustype);
void dhd_osl_detach(osl_t *osh);
/* Indication from bus module regarding presence/insertion of dongle.
* Return dhd_pub_t pointer, used as handle to OS module in later calls.
* Returned structure should have bus and prot pointers filled in.
* bus_hdrlen specifies required headroom for bus module header.
*/
extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen);
extern int dhd_net_attach(dhd_pub_t *dhdp, int idx);
/* Indication from bus module regarding removal/absence of dongle */
extern void dhd_detach(dhd_pub_t *dhdp);
/* Indication from bus module to change flow-control state */
extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on);
extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec);
/* Receive frame for delivery to OS. Callee disposes of rxp. */
extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt);
/* Return pointer to interface name */
extern char *dhd_ifname(dhd_pub_t *dhdp, int idx);
/* Request scheduling of the bus dpc */
extern void dhd_sched_dpc(dhd_pub_t *dhdp);
/* Notify tx completion */
extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success);
/* Query ioctl */
extern int dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf,
uint len);
/* OS independent layer functions */
extern int dhd_os_proto_block(dhd_pub_t *pub);
extern int dhd_os_proto_unblock(dhd_pub_t *pub);
extern int dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition,
bool *pending);
extern int dhd_os_ioctl_resp_wake(dhd_pub_t *pub);
extern unsigned int dhd_os_get_ioctl_resp_timeout(void);
extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec);
extern void *dhd_os_open_image(char *filename);
extern int dhd_os_get_image_block(char *buf, int len, void *image);
extern void dhd_os_close_image(void *image);
extern void dhd_os_wd_timer(void *bus, uint wdtick);
extern void dhd_os_sdlock(dhd_pub_t *pub);
extern void dhd_os_sdunlock(dhd_pub_t *pub);
extern void dhd_os_sdlock_txq(dhd_pub_t *pub);
extern void dhd_os_sdunlock_txq(dhd_pub_t *pub);
extern void dhd_os_sdlock_rxq(dhd_pub_t *pub);
extern void dhd_os_sdunlock_rxq(dhd_pub_t *pub);
extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t *pub);
extern void dhd_customer_gpio_wlan_ctrl(int onoff);
extern int dhd_custom_get_mac_address(unsigned char *buf);
extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t *pub);
extern void dhd_os_sdlock_eventq(dhd_pub_t *pub);
extern void dhd_os_sdunlock_eventq(dhd_pub_t *pub);
#ifdef DHD_DEBUG
extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size);
#endif /* DHD_DEBUG */
#if defined(OOB_INTR_ONLY)
extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr);
#endif /* defined(OOB_INTR_ONLY) */
extern void dhd_os_sdtxlock(dhd_pub_t *pub);
extern void dhd_os_sdtxunlock(dhd_pub_t *pub);
int setScheduler(struct task_struct *p, int policy, struct sched_param *param);
typedef struct {
uint32 limit; /* Expiration time (usec) */
uint32 increment; /* Current expiration increment (usec) */
uint32 elapsed; /* Current elapsed time (usec) */
uint32 tick; /* O/S tick time (usec) */
} dhd_timeout_t;
extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec);
extern int dhd_timeout_expired(dhd_timeout_t *tmo);
extern int dhd_ifname2idx(struct dhd_info *dhd, char *name);
extern uint8 *dhd_bssidx2bssid(dhd_pub_t *dhd, int idx);
extern int wl_host_event(struct dhd_info *dhd, int *idx, void *pktdata,
wl_event_msg_t *, void **data_ptr);
extern void wl_event_to_host_order(wl_event_msg_t *evt);
extern void dhd_common_init(void);
extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle,
char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx);
extern void dhd_del_if(struct dhd_info *dhd, int ifidx);
extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char *name);
extern void dhd_vif_del(struct dhd_info *dhd, int ifidx);
extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx);
extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar * cp,
int len);
/* Send packet to dongle via data channel */
extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt);
/* Send event to host */
extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event,
void *data);
extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag);
extern uint dhd_bus_status(dhd_pub_t *dhdp);
extern int dhd_bus_start(dhd_pub_t *dhdp);
extern void print_buf(void *pbuf, int len, int bytes_per_line);
typedef enum cust_gpio_modes {
WLAN_RESET_ON,
WLAN_RESET_OFF,
WLAN_POWER_ON,
WLAN_POWER_OFF
} cust_gpio_modes_t;
/*
* Insmod parameters for debug/test
*/
/* Watchdog timer interval */
extern uint dhd_watchdog_ms;
#if defined(DHD_DEBUG)
/* Console output poll interval */
extern uint dhd_console_ms;
#endif /* defined(DHD_DEBUG) */
/* Use interrupts */
extern uint dhd_intr;
/* Use polling */
extern uint dhd_poll;
/* ARP offload agent mode */
extern uint dhd_arp_mode;
/* ARP offload enable */
extern uint dhd_arp_enable;
/* Pkt filte enable control */
extern uint dhd_pkt_filter_enable;
/* Pkt filter init setup */
extern uint dhd_pkt_filter_init;
/* Pkt filter mode control */
extern uint dhd_master_mode;
/* Roaming mode control */
extern uint dhd_roam;
/* Roaming mode control */
extern uint dhd_radio_up;
/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */
extern int dhd_idletime;
#define DHD_IDLETIME_TICKS 1
/* SDIO Drive Strength */
extern uint dhd_sdiod_drive_strength;
/* Override to force tx queueing all the time */
extern uint dhd_force_tx_queueing;
#ifdef SDTEST
/* Echo packet generator (SDIO), pkts/s */
extern uint dhd_pktgen;
/* Echo packet len (0 => sawtooth, max 1800) */
extern uint dhd_pktgen_len;
#define MAX_PKTGEN_LEN 1800
#endif
/* optionally set by a module_param_string() */
#define MOD_PARAM_PATHLEN 2048
extern char fw_path[MOD_PARAM_PATHLEN];
extern char nv_path[MOD_PARAM_PATHLEN];
/* For supporting multiple interfaces */
#define DHD_MAX_IFS 16
#define DHD_DEL_IF -0xe
#define DHD_BAD_IF -0xf
extern void dhd_wait_for_event(dhd_pub_t *dhd, bool * lockvar);
extern void dhd_wait_event_wakeup(dhd_pub_t *dhd);
#endif /* _dhd_h_ */

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _dhd_bus_h_
#define _dhd_bus_h_
/*
* Exported from dhd bus module (dhd_usb, dhd_sdio)
*/
/* Indicate (dis)interest in finding dongles. */
extern int dhd_bus_register(void);
extern void dhd_bus_unregister(void);
/* Download firmware image and nvram image */
extern bool dhd_bus_download_firmware(struct dhd_bus *bus, osl_t * osh,
char *fw_path, char *nv_path);
/* Stop bus module: clear pending frames, disable data flow */
extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex);
/* Initialize bus module: prepare for communication w/dongle */
extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex);
/* Send a data frame to the dongle. Callee disposes of txp. */
extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp);
/* Send/receive a control message to/from the dongle.
* Expects caller to enforce a single outstanding transaction.
*/
extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen);
extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen);
/* Watchdog timer function */
extern bool dhd_bus_watchdog(dhd_pub_t *dhd);
#ifdef DHD_DEBUG
/* Device console input function */
extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen);
#endif /* DHD_DEBUG */
/* Deferred processing for the bus, return TRUE requests reschedule */
extern bool dhd_bus_dpc(struct dhd_bus *bus);
extern void dhd_bus_isr(bool *InterruptRecognized,
bool *QueueMiniportHandleInterrupt, void *arg);
/* Check for and handle local prot-specific iovar commands */
extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name,
void *params, int plen, void *arg, int len,
bool set);
/* Add bus dump output to a buffer */
extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
/* Clear any bus counters */
extern void dhd_bus_clearcounts(dhd_pub_t *dhdp);
/* return the dongle chipid */
extern uint dhd_bus_chip(struct dhd_bus *bus);
/* Set user-specified nvram parameters. */
extern void dhd_bus_set_nvram_params(struct dhd_bus *bus,
const char *nvram_params);
extern void *dhd_bus_pub(struct dhd_bus *bus);
extern void *dhd_bus_txq(struct dhd_bus *bus);
extern uint dhd_bus_hdrlen(struct dhd_bus *bus);
#endif /* _dhd_bus_h_ */

View File

@ -0,0 +1,495 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <typedefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <bcmcdc.h>
#include <bcmendian.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <dhd_proto.h>
#include <dhd_bus.h>
#include <dhd_dbg.h>
#ifdef CUSTOMER_HW2
int wifi_get_mac_addr(unsigned char *buf);
#endif
extern int dhd_preinit_ioctls(dhd_pub_t *dhd);
/* Packet alignment for most efficient SDIO (can change based on platform) */
#ifndef DHD_SDALIGN
#define DHD_SDALIGN 32
#endif
#if !ISPOWEROF2(DHD_SDALIGN)
#error DHD_SDALIGN is not a power of 2!
#endif
#define RETRIES 2 /* # of retries to retrieve matching ioctl response */
#define BUS_HEADER_LEN (16+DHD_SDALIGN) /* Must be atleast SDPCM_RESERVE
* defined in dhd_sdio.c
* (amount of header tha might be added)
* plus any space that might be needed
* for alignment padding.
*/
#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for
* round off at the end of buffer
*/
typedef struct dhd_prot {
uint16 reqid;
uint8 pending;
uint32 lastcmd;
uint8 bus_header[BUS_HEADER_LEN];
cdc_ioctl_t msg;
unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN];
} dhd_prot_t;
static int dhdcdc_msg(dhd_pub_t *dhd)
{
dhd_prot_t *prot = dhd->prot;
int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t);
DHD_TRACE(("%s: Enter\n", __func__));
/* NOTE : cdc->msg.len holds the desired length of the buffer to be
* returned. Only up to CDC_MAX_MSG_SIZE of this buffer area
* is actually sent to the dongle
*/
if (len > CDC_MAX_MSG_SIZE)
len = CDC_MAX_MSG_SIZE;
/* Send request */
return dhd_bus_txctl(dhd->bus, (uchar *)&prot->msg, len);
}
static int dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len)
{
int ret;
dhd_prot_t *prot = dhd->prot;
DHD_TRACE(("%s: Enter\n", __func__));
do {
ret =
dhd_bus_rxctl(dhd->bus, (uchar *)&prot->msg,
len + sizeof(cdc_ioctl_t));
if (ret < 0)
break;
} while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id);
return ret;
}
int
dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len)
{
dhd_prot_t *prot = dhd->prot;
cdc_ioctl_t *msg = &prot->msg;
void *info;
int ret = 0, retries = 0;
uint32 id, flags = 0;
DHD_TRACE(("%s: Enter\n", __func__));
DHD_CTL(("%s: cmd %d len %d\n", __func__, cmd, len));
/* Respond "bcmerror" and "bcmerrorstr" with local cache */
if (cmd == WLC_GET_VAR && buf) {
if (!strcmp((char *)buf, "bcmerrorstr")) {
strncpy((char *)buf, bcmerrorstr(dhd->dongle_error),
BCME_STRLEN);
goto done;
} else if (!strcmp((char *)buf, "bcmerror")) {
*(int *)buf = dhd->dongle_error;
goto done;
}
}
memset(msg, 0, sizeof(cdc_ioctl_t));
msg->cmd = htol32(cmd);
msg->len = htol32(len);
msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT);
CDC_SET_IF_IDX(msg, ifidx);
msg->flags = htol32(msg->flags);
if (buf)
memcpy(prot->buf, buf, len);
if ((ret = dhdcdc_msg(dhd)) < 0) {
DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status "
"%d\n", ret));
goto done;
}
retry:
/* wait for interrupt and get first fragment */
if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
goto done;
flags = ltoh32(msg->flags);
id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
if ((id < prot->reqid) && (++retries < RETRIES))
goto retry;
if (id != prot->reqid) {
DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
dhd_ifname(dhd, ifidx), __func__, id, prot->reqid));
ret = -EINVAL;
goto done;
}
/* Check info buffer */
info = (void *)&msg[1];
/* Copy info buffer */
if (buf) {
if (ret < (int)len)
len = ret;
memcpy(buf, info, len);
}
/* Check the ERROR flag */
if (flags & CDCF_IOC_ERROR) {
ret = ltoh32(msg->status);
/* Cache error from dongle */
dhd->dongle_error = ret;
}
done:
return ret;
}
int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len)
{
dhd_prot_t *prot = dhd->prot;
cdc_ioctl_t *msg = &prot->msg;
int ret = 0;
uint32 flags, id;
DHD_TRACE(("%s: Enter\n", __func__));
DHD_CTL(("%s: cmd %d len %d\n", __func__, cmd, len));
memset(msg, 0, sizeof(cdc_ioctl_t));
msg->cmd = htol32(cmd);
msg->len = htol32(len);
msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT) | CDCF_IOC_SET;
CDC_SET_IF_IDX(msg, ifidx);
msg->flags = htol32(msg->flags);
if (buf)
memcpy(prot->buf, buf, len);
if ((ret = dhdcdc_msg(dhd)) < 0)
goto done;
if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0)
goto done;
flags = ltoh32(msg->flags);
id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT;
if (id != prot->reqid) {
DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n",
dhd_ifname(dhd, ifidx), __func__, id, prot->reqid));
ret = -EINVAL;
goto done;
}
/* Check the ERROR flag */
if (flags & CDCF_IOC_ERROR) {
ret = ltoh32(msg->status);
/* Cache error from dongle */
dhd->dongle_error = ret;
}
done:
return ret;
}
extern int dhd_bus_interface(struct dhd_bus *bus, uint arg, void *arg2);
int
dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t *ioc, void *buf, int len)
{
dhd_prot_t *prot = dhd->prot;
int ret = -1;
if (dhd->busstate == DHD_BUS_DOWN) {
DHD_ERROR(("%s : bus is down. we have nothing to do\n",
__func__));
return ret;
}
dhd_os_proto_block(dhd);
DHD_TRACE(("%s: Enter\n", __func__));
ASSERT(len <= WLC_IOCTL_MAXLEN);
if (len > WLC_IOCTL_MAXLEN)
goto done;
if (prot->pending == TRUE) {
DHD_TRACE(("CDC packet is pending!!!! cmd=0x%x (%lu) "
"lastcmd=0x%x (%lu)\n",
ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd,
(unsigned long)prot->lastcmd));
if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) {
DHD_TRACE(("iovar cmd=%s\n", (char *)buf));
}
goto done;
}
prot->pending = TRUE;
prot->lastcmd = ioc->cmd;
if (ioc->set)
ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len);
else {
ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len);
if (ret > 0)
ioc->used = ret - sizeof(cdc_ioctl_t);
}
/* Too many programs assume ioctl() returns 0 on success */
if (ret >= 0)
ret = 0;
else {
cdc_ioctl_t *msg = &prot->msg;
ioc->needed = ltoh32(msg->len); /* len == needed when set/query
fails from dongle */
}
/* Intercept the wme_dp ioctl here */
if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) {
int slen, val = 0;
slen = strlen("wme_dp") + 1;
if (len >= (int)(slen + sizeof(int)))
bcopy(((char *)buf + slen), &val, sizeof(int));
dhd->wme_dp = (uint8) ltoh32(val);
}
prot->pending = FALSE;
done:
dhd_os_proto_unblock(dhd);
return ret;
}
int
dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
void *params, int plen, void *arg, int len, bool set)
{
return BCME_UNSUPPORTED;
}
void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf)
{
bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid);
}
void dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf)
{
#ifdef BDC
struct bdc_header *h;
#endif /* BDC */
DHD_TRACE(("%s: Enter\n", __func__));
#ifdef BDC
/* Push BDC header used to convey priority for buses that don't */
PKTPUSH(pktbuf, BDC_HEADER_LEN);
h = (struct bdc_header *)PKTDATA(pktbuf);
h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);
if (PKTSUMNEEDED(pktbuf))
h->flags |= BDC_FLAG_SUM_NEEDED;
h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK);
h->flags2 = 0;
h->rssi = 0;
#endif /* BDC */
BDC_SET_IF_IDX(h, ifidx);
}
bool dhd_proto_fcinfo(dhd_pub_t *dhd, void *pktbuf, uint8 * fcbits)
{
#ifdef BDC
struct bdc_header *h;
if (PKTLEN(pktbuf) < BDC_HEADER_LEN) {
DHD_ERROR(("%s: rx data too short (%d < %d)\n",
__func__, PKTLEN(pktbuf), BDC_HEADER_LEN));
return BCME_ERROR;
}
h = (struct bdc_header *)PKTDATA(pktbuf);
*fcbits = h->priority >> BDC_PRIORITY_FC_SHIFT;
if ((h->flags2 & BDC_FLAG2_FC_FLAG) == BDC_FLAG2_FC_FLAG)
return TRUE;
#endif
return FALSE;
}
int dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf)
{
#ifdef BDC
struct bdc_header *h;
#endif
DHD_TRACE(("%s: Enter\n", __func__));
#ifdef BDC
/* Pop BDC header used to convey priority for buses that don't */
if (PKTLEN(pktbuf) < BDC_HEADER_LEN) {
DHD_ERROR(("%s: rx data too short (%d < %d)\n", __func__,
PKTLEN(pktbuf), BDC_HEADER_LEN));
return BCME_ERROR;
}
h = (struct bdc_header *)PKTDATA(pktbuf);
if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) {
DHD_ERROR(("%s: rx data ifnum out of range (%d)\n",
__func__, *ifidx));
return BCME_ERROR;
}
if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) !=
BDC_PROTO_VER) {
DHD_ERROR(("%s: non-BDC packet received, flags 0x%x\n",
dhd_ifname(dhd, *ifidx), h->flags));
return BCME_ERROR;
}
if (h->flags & BDC_FLAG_SUM_GOOD) {
DHD_INFO(("%s: BDC packet received with good rx-csum, "
"flags 0x%x\n",
dhd_ifname(dhd, *ifidx), h->flags));
PKTSETSUMGOOD(pktbuf, TRUE);
}
PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK));
PKTPULL(pktbuf, BDC_HEADER_LEN);
#endif /* BDC */
return 0;
}
int dhd_prot_attach(dhd_pub_t *dhd)
{
dhd_prot_t *cdc;
#ifndef DHD_USE_STATIC_BUF
if (!(cdc = (dhd_prot_t *) MALLOC(dhd->osh, sizeof(dhd_prot_t)))) {
DHD_ERROR(("%s: kmalloc failed\n", __func__));
goto fail;
}
#else
if (!
(cdc =
(dhd_prot_t *) dhd_os_prealloc(DHD_PREALLOC_PROT,
sizeof(dhd_prot_t)))) {
DHD_ERROR(("%s: kmalloc failed\n", __func__));
goto fail;
}
#endif /* DHD_USE_STATIC_BUF */
memset(cdc, 0, sizeof(dhd_prot_t));
/* ensure that the msg buf directly follows the cdc msg struct */
if ((uintptr) (&cdc->msg + 1) != (uintptr) cdc->buf) {
DHD_ERROR(("dhd_prot_t is not correctly defined\n"));
goto fail;
}
dhd->prot = cdc;
#ifdef BDC
dhd->hdrlen += BDC_HEADER_LEN;
#endif
dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN;
return 0;
fail:
#ifndef DHD_USE_STATIC_BUF
if (cdc != NULL)
MFREE(dhd->osh, cdc, sizeof(dhd_prot_t));
#endif
return BCME_NOMEM;
}
/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */
void dhd_prot_detach(dhd_pub_t *dhd)
{
#ifndef DHD_USE_STATIC_BUF
MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t));
#endif
dhd->prot = NULL;
}
void dhd_prot_dstats(dhd_pub_t *dhd)
{
/* No stats from dongle added yet, copy bus stats */
dhd->dstats.tx_packets = dhd->tx_packets;
dhd->dstats.tx_errors = dhd->tx_errors;
dhd->dstats.rx_packets = dhd->rx_packets;
dhd->dstats.rx_errors = dhd->rx_errors;
dhd->dstats.rx_dropped = dhd->rx_dropped;
dhd->dstats.multicast = dhd->rx_multicast;
return;
}
int dhd_prot_init(dhd_pub_t *dhd)
{
int ret = 0;
char buf[128];
DHD_TRACE(("%s: Enter\n", __func__));
dhd_os_proto_block(dhd);
/* Get the device MAC address */
strcpy(buf, "cur_etheraddr");
ret = dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf));
if (ret < 0) {
dhd_os_proto_unblock(dhd);
return ret;
}
memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN);
dhd_os_proto_unblock(dhd);
#ifdef EMBEDDED_PLATFORM
ret = dhd_preinit_ioctls(dhd);
#endif /* EMBEDDED_PLATFORM */
/* Always assumes wl for now */
dhd->iswl = TRUE;
return ret;
}
void dhd_prot_stop(dhd_pub_t *dhd)
{
/* Nothing to do for CDC */
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <typedefs.h>
#include <linuxver.h>
#include <osl.h>
#include <bcmutils.h>
#include <dngl_stats.h>
#include <dhd.h>
#include <wlioctl.h>
#include <wl_iw.h>
#define WL_ERROR(x) printf x
#define WL_TRACE(x)
#ifdef CUSTOMER_HW
extern void bcm_wlan_power_off(int);
extern void bcm_wlan_power_on(int);
#endif /* CUSTOMER_HW */
#ifdef CUSTOMER_HW2
int wifi_set_carddetect(int on);
int wifi_set_power(int on, unsigned long msec);
int wifi_get_irq_number(unsigned long *irq_flags_ptr);
#endif
#if defined(OOB_INTR_ONLY)
#if defined(BCMLXSDMMC)
extern int sdioh_mmc_irq(int irq);
#endif /* (BCMLXSDMMC) */
#ifdef CUSTOMER_HW3
#include <mach/gpio.h>
#endif
/* Customer specific Host GPIO defintion */
static int dhd_oob_gpio_num = -1; /* GG 19 */
module_param(dhd_oob_gpio_num, int, 0644);
MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number");
int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr)
{
int host_oob_irq = 0;
#ifdef CUSTOMER_HW2
host_oob_irq = wifi_get_irq_number(irq_flags_ptr);
#else /* for NOT CUSTOMER_HW2 */
#if defined(CUSTOM_OOB_GPIO_NUM)
if (dhd_oob_gpio_num < 0)
dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM;
#endif
if (dhd_oob_gpio_num < 0) {
WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined\n",
__func__));
return dhd_oob_gpio_num;
}
WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n",
__func__, dhd_oob_gpio_num));
#if defined CUSTOMER_HW
host_oob_irq = MSM_GPIO_TO_INT(dhd_oob_gpio_num);
#elif defined CUSTOMER_HW3
gpio_request(dhd_oob_gpio_num, "oob irq");
host_oob_irq = gpio_to_irq(dhd_oob_gpio_num);
gpio_direction_input(dhd_oob_gpio_num);
#endif /* CUSTOMER_HW */
#endif /* CUSTOMER_HW2 */
return host_oob_irq;
}
#endif /* defined(OOB_INTR_ONLY) */
/* Customer function to control hw specific wlan gpios */
void dhd_customer_gpio_wlan_ctrl(int onoff)
{
switch (onoff) {
case WLAN_RESET_OFF:
WL_TRACE(("%s: call customer specific GPIO to insert WLAN RESET\n",
__func__));
#ifdef CUSTOMER_HW
bcm_wlan_power_off(2);
#endif /* CUSTOMER_HW */
#ifdef CUSTOMER_HW2
wifi_set_power(0, 0);
#endif
WL_ERROR(("=========== WLAN placed in RESET ========\n"));
break;
case WLAN_RESET_ON:
WL_TRACE(("%s: callc customer specific GPIO to remove WLAN RESET\n",
__func__));
#ifdef CUSTOMER_HW
bcm_wlan_power_on(2);
#endif /* CUSTOMER_HW */
#ifdef CUSTOMER_HW2
wifi_set_power(1, 0);
#endif
WL_ERROR(("=========== WLAN going back to live ========\n"));
break;
case WLAN_POWER_OFF:
WL_TRACE(("%s: call customer specific GPIO to turn off WL_REG_ON\n",
__func__));
#ifdef CUSTOMER_HW
bcm_wlan_power_off(1);
#endif /* CUSTOMER_HW */
break;
case WLAN_POWER_ON:
WL_TRACE(("%s: call customer specific GPIO to turn on WL_REG_ON\n",
__func__));
#ifdef CUSTOMER_HW
bcm_wlan_power_on(1);
#endif /* CUSTOMER_HW */
/* Lets customer power to get stable */
OSL_DELAY(200);
break;
}
}
#ifdef GET_CUSTOM_MAC_ENABLE
/* Function to get custom MAC address */
int dhd_custom_get_mac_address(unsigned char *buf)
{
WL_TRACE(("%s Enter\n", __func__));
if (!buf)
return -EINVAL;
/* Customer access to MAC address stored outside of DHD driver */
#ifdef EXAMPLE_GET_MAC
/* EXAMPLE code */
{
struct ether_addr ea_example = {
{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}};
bcopy((char *)&ea_example, buf, sizeof(struct ether_addr));
}
#endif /* EXAMPLE_GET_MAC */
return 0;
}
#endif /* GET_CUSTOM_MAC_ENABLE */

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _dhd_dbg_
#define _dhd_dbg_
#if defined(DHD_DEBUG)
#define DHD_ERROR(args) \
do {if ((dhd_msg_level & DHD_ERROR_VAL) && (net_ratelimit())) \
printf args; } while (0)
#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) \
printf args; } while (0)
#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) \
printf args; } while (0)
#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) \
printf args; } while (0)
#define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) \
printf args; } while (0)
#define DHD_TIMER(args) do {if (dhd_msg_level & DHD_TIMER_VAL) \
printf args; } while (0)
#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) \
printf args; } while (0)
#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) \
printf args; } while (0)
#define DHD_INTR(args) do {if (dhd_msg_level & DHD_INTR_VAL) \
printf args; } while (0)
#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) \
printf args; } while (0)
#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) \
printf args; } while (0)
#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) \
printf args; } while (0)
#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) \
printf args; } while (0)
#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL)
#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL)
#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL)
#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL)
#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL)
#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL)
#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL)
#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL)
#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL)
#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL)
#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL)
#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL)
#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL)
#else /* (defined BCMDBG) || (defined DHD_DEBUG) */
#define DHD_ERROR(args) do {if (net_ratelimit()) printf args; } while (0)
#define DHD_TRACE(args)
#define DHD_INFO(args)
#define DHD_DATA(args)
#define DHD_CTL(args)
#define DHD_TIMER(args)
#define DHD_HDRS(args)
#define DHD_BYTES(args)
#define DHD_INTR(args)
#define DHD_GLOM(args)
#define DHD_EVENT(args)
#define DHD_BTA(args)
#define DHD_ISCAN(args)
#define DHD_ERROR_ON() 0
#define DHD_TRACE_ON() 0
#define DHD_INFO_ON() 0
#define DHD_DATA_ON() 0
#define DHD_CTL_ON() 0
#define DHD_TIMER_ON() 0
#define DHD_HDRS_ON() 0
#define DHD_BYTES_ON() 0
#define DHD_INTR_ON() 0
#define DHD_GLOM_ON() 0
#define DHD_EVENT_ON() 0
#define DHD_BTA_ON() 0
#define DHD_ISCAN_ON() 0
#endif /* defined(DHD_DEBUG) */
#define DHD_LOG(args)
#define DHD_NONE(args)
extern int dhd_msg_level;
/* Defines msg bits */
#include <dhdioctl.h>
#endif /* _dhd_dbg_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linuxver.h>
int setScheduler(struct task_struct *p, int policy, struct sched_param *param)
{
int rc = 0;
rc = sched_setscheduler(p, policy, param);
return rc;
}

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _dhd_proto_h_
#define _dhd_proto_h_
#include <dhdioctl.h>
#include <wlioctl.h>
#ifndef IOCTL_RESP_TIMEOUT
#define IOCTL_RESP_TIMEOUT 2000 /* In milli second */
#endif
#ifndef IOCTL_CHIP_ACTIVE_TIMEOUT
#define IOCTL_CHIP_ACTIVE_TIMEOUT 10 /* In milli second */
#endif
/*
* Exported from the dhd protocol module (dhd_cdc, dhd_rndis)
*/
/* Linkage, sets prot link and updates hdrlen in pub */
extern int dhd_prot_attach(dhd_pub_t *dhdp);
/* Unlink, frees allocated protocol memory (including dhd_prot) */
extern void dhd_prot_detach(dhd_pub_t *dhdp);
/* Initialize protocol: sync w/dongle state.
* Sets dongle media info (iswl, drv_version, mac address).
*/
extern int dhd_prot_init(dhd_pub_t *dhdp);
/* Stop protocol: sync w/dongle state. */
extern void dhd_prot_stop(dhd_pub_t *dhdp);
extern bool dhd_proto_fcinfo(dhd_pub_t *dhd, void *pktbuf, uint8 *fcbits);
/* Add any protocol-specific data header.
* Caller must reserve prot_hdrlen prepend space.
*/
extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp);
/* Remove any protocol-specific data header. */
extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp);
/* Use protocol to issue ioctl to dongle */
extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t *ioc,
void *buf, int len);
/* Check for and handle local prot-specific iovar commands */
extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name,
void *params, int plen, void *arg, int len,
bool set);
/* Add prot dump output to a buffer */
extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf);
/* Update local copy of dongle statistics */
extern void dhd_prot_dstats(dhd_pub_t *dhdp);
extern int dhd_ioctl(dhd_pub_t *dhd_pub, dhd_ioctl_t *ioc, void *buf,
uint buflen);
extern int dhd_preinit_ioctls(dhd_pub_t *dhd);
/********************************
* For version-string expansion *
*/
#if defined(BDC)
#define DHD_PROTOCOL "bdc"
#elif defined(CDC)
#define DHD_PROTOCOL "cdc"
#elif defined(RNDIS)
#define DHD_PROTOCOL "rndis"
#else
#define DHD_PROTOCOL "unknown"
#endif /* proto */
#endif /* _dhd_proto_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _dngl_stats_h_
#define _dngl_stats_h_
typedef struct {
unsigned long rx_packets; /* total packets received */
unsigned long tx_packets; /* total packets transmitted */
unsigned long rx_bytes; /* total bytes received */
unsigned long tx_bytes; /* total bytes transmitted */
unsigned long rx_errors; /* bad packets received */
unsigned long tx_errors; /* packet transmit problems */
unsigned long rx_dropped; /* packets dropped by dongle */
unsigned long tx_dropped; /* packets dropped by dongle */
unsigned long multicast; /* multicast packets received */
} dngl_stats_t;
#endif /* _dngl_stats_h_ */

View File

@ -0,0 +1,588 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/version.h>
#define LINUX_OSL
#include <linux/sched.h>
#include <typedefs.h>
#include <bcmendian.h>
#include <linuxver.h>
#include <bcmdefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <linux/delay.h>
#include <pcicfg.h>
#define PCI_CFG_RETRY 10
#define OS_HANDLE_MAGIC 0x1234abcd
#define BCM_MEM_FILENAME_LEN 24
#ifdef DHD_USE_STATIC_BUF
#define MAX_STATIC_BUF_NUM 16
#define STATIC_BUF_SIZE (PAGE_SIZE*2)
#define STATIC_BUF_TOTAL_LEN (MAX_STATIC_BUF_NUM*STATIC_BUF_SIZE)
typedef struct bcm_static_buf {
struct semaphore static_sem;
unsigned char *buf_ptr;
unsigned char buf_use[MAX_STATIC_BUF_NUM];
} bcm_static_buf_t;
static bcm_static_buf_t *bcm_static_buf = 0;
#define MAX_STATIC_PKT_NUM 8
typedef struct bcm_static_pkt {
struct sk_buff *skb_4k[MAX_STATIC_PKT_NUM];
struct sk_buff *skb_8k[MAX_STATIC_PKT_NUM];
struct semaphore osl_pkt_sem;
unsigned char pkt_use[MAX_STATIC_PKT_NUM * 2];
} bcm_static_pkt_t;
static bcm_static_pkt_t *bcm_static_skb = 0;
#endif /* DHD_USE_STATIC_BUF */
typedef struct bcm_mem_link {
struct bcm_mem_link *prev;
struct bcm_mem_link *next;
uint size;
int line;
char file[BCM_MEM_FILENAME_LEN];
} bcm_mem_link_t;
struct osl_info {
osl_pubinfo_t pub;
uint magic;
void *pdev;
uint malloced;
uint failed;
uint bustype;
bcm_mem_link_t *dbgmem_list;
};
static int16 linuxbcmerrormap[] = { 0,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-E2BIG,
-E2BIG,
-EBUSY,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-EFAULT,
-ENOMEM,
-EOPNOTSUPP,
-EMSGSIZE,
-EINVAL,
-EPERM,
-ENOMEM,
-EINVAL,
-ERANGE,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-EINVAL,
-EIO,
-ENODEV,
-EINVAL,
-EIO,
-EIO,
-EINVAL,
-EINVAL,
-ENODATA,
#if BCME_LAST != BCME_NONRESIDENT
#error "You need to add a OS error translation in the linuxbcmerrormap \
for new error code defined in bcmutils.h"
#endif
};
/* Global ASSERT type flag */
uint32 g_assert_type = 0;
int osl_error(int bcmerror)
{
if (bcmerror > 0)
bcmerror = 0;
else if (bcmerror < BCME_LAST)
bcmerror = BCME_ERROR;
return linuxbcmerrormap[-bcmerror];
}
void *dhd_os_prealloc(int section, unsigned long size);
osl_t *osl_attach(void *pdev, uint bustype, bool pkttag)
{
osl_t *osh;
osh = kmalloc(sizeof(osl_t), GFP_ATOMIC);
ASSERT(osh);
bzero(osh, sizeof(osl_t));
ASSERT(ABS(BCME_LAST) == (ARRAYSIZE(linuxbcmerrormap) - 1));
osh->magic = OS_HANDLE_MAGIC;
osh->malloced = 0;
osh->failed = 0;
osh->dbgmem_list = NULL;
osh->pdev = pdev;
osh->pub.pkttag = pkttag;
osh->bustype = bustype;
switch (bustype) {
case PCI_BUS:
case SI_BUS:
case PCMCIA_BUS:
osh->pub.mmbus = TRUE;
break;
case JTAG_BUS:
case SDIO_BUS:
case USB_BUS:
case SPI_BUS:
osh->pub.mmbus = FALSE;
break;
default:
ASSERT(FALSE);
break;
}
#ifdef DHD_USE_STATIC_BUF
if (!bcm_static_buf) {
if (!(bcm_static_buf =
(bcm_static_buf_t *) dhd_os_prealloc(3,
STATIC_BUF_SIZE + STATIC_BUF_TOTAL_LEN))) {
printk(KERN_ERR "can not alloc static buf!\n");
} else
printk(KERN_ERR "alloc static buf at %x!\n",
(unsigned int)bcm_static_buf);
init_MUTEX(&bcm_static_buf->static_sem);
bcm_static_buf->buf_ptr =
(unsigned char *)bcm_static_buf + STATIC_BUF_SIZE;
}
if (!bcm_static_skb) {
int i;
void *skb_buff_ptr = 0;
bcm_static_skb =
(bcm_static_pkt_t *) ((char *)bcm_static_buf + 2048);
skb_buff_ptr = dhd_os_prealloc(4, 0);
bcopy(skb_buff_ptr, bcm_static_skb,
sizeof(struct sk_buff *) * 16);
for (i = 0; i < MAX_STATIC_PKT_NUM * 2; i++)
bcm_static_skb->pkt_use[i] = 0;
init_MUTEX(&bcm_static_skb->osl_pkt_sem);
}
#endif /* DHD_USE_STATIC_BUF */
return osh;
}
void osl_detach(osl_t *osh)
{
if (osh == NULL)
return;
#ifdef DHD_USE_STATIC_BUF
if (bcm_static_buf)
bcm_static_buf = 0;
if (bcm_static_skb)
bcm_static_skb = 0;
#endif
ASSERT(osh->magic == OS_HANDLE_MAGIC);
kfree(osh);
}
void *osl_pktget(osl_t *osh, uint len)
{
struct sk_buff *skb;
if ((skb = dev_alloc_skb(len))) {
skb_put(skb, len);
skb->priority = 0;
osh->pub.pktalloced++;
}
return (void *)skb;
}
void osl_pktfree(osl_t *osh, void *p, bool send)
{
struct sk_buff *skb, *nskb;
skb = (struct sk_buff *)p;
if (send && osh->pub.tx_fn)
osh->pub.tx_fn(osh->pub.tx_ctx, p, 0);
while (skb) {
nskb = skb->next;
skb->next = NULL;
if (skb->destructor)
dev_kfree_skb_any(skb);
else
dev_kfree_skb(skb);
osh->pub.pktalloced--;
skb = nskb;
}
}
#ifdef DHD_USE_STATIC_BUF
void *osl_pktget_static(osl_t *osh, uint len)
{
int i = 0;
struct sk_buff *skb;
if (len > (PAGE_SIZE * 2)) {
printk(KERN_ERR "Do we really need this big skb??\n");
return osl_pktget(osh, len);
}
down(&bcm_static_skb->osl_pkt_sem);
if (len <= PAGE_SIZE) {
for (i = 0; i < MAX_STATIC_PKT_NUM; i++) {
if (bcm_static_skb->pkt_use[i] == 0)
break;
}
if (i != MAX_STATIC_PKT_NUM) {
bcm_static_skb->pkt_use[i] = 1;
up(&bcm_static_skb->osl_pkt_sem);
skb = bcm_static_skb->skb_4k[i];
skb->tail = skb->data + len;
skb->len = len;
return skb;
}
}
for (i = 0; i < MAX_STATIC_PKT_NUM; i++) {
if (bcm_static_skb->pkt_use[i + MAX_STATIC_PKT_NUM] == 0)
break;
}
if (i != MAX_STATIC_PKT_NUM) {
bcm_static_skb->pkt_use[i + MAX_STATIC_PKT_NUM] = 1;
up(&bcm_static_skb->osl_pkt_sem);
skb = bcm_static_skb->skb_8k[i];
skb->tail = skb->data + len;
skb->len = len;
return skb;
}
up(&bcm_static_skb->osl_pkt_sem);
printk(KERN_ERR "all static pkt in use!\n");
return osl_pktget(osh, len);
}
void osl_pktfree_static(osl_t *osh, void *p, bool send)
{
int i;
for (i = 0; i < MAX_STATIC_PKT_NUM * 2; i++) {
if (p == bcm_static_skb->skb_4k[i]) {
down(&bcm_static_skb->osl_pkt_sem);
bcm_static_skb->pkt_use[i] = 0;
up(&bcm_static_skb->osl_pkt_sem);
return;
}
}
return osl_pktfree(osh, p, send);
}
#endif /* DHD_USE_STATIC_BUF */
uint32 osl_pci_read_config(osl_t *osh, uint offset, uint size)
{
uint val = 0;
uint retry = PCI_CFG_RETRY;
ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
ASSERT(size == 4);
do {
pci_read_config_dword(osh->pdev, offset, &val);
if (val != 0xffffffff)
break;
} while (retry--);
return val;
}
void osl_pci_write_config(osl_t *osh, uint offset, uint size, uint val)
{
uint retry = PCI_CFG_RETRY;
ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
ASSERT(size == 4);
do {
pci_write_config_dword(osh->pdev, offset, val);
if (offset != PCI_BAR0_WIN)
break;
if (osl_pci_read_config(osh, offset, size) == val)
break;
} while (retry--);
}
uint osl_pci_bus(osl_t *osh)
{
ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
return ((struct pci_dev *)osh->pdev)->bus->number;
}
uint osl_pci_slot(osl_t *osh)
{
ASSERT(osh && (osh->magic == OS_HANDLE_MAGIC) && osh->pdev);
return PCI_SLOT(((struct pci_dev *)osh->pdev)->devfn);
}
static void
osl_pcmcia_attr(osl_t *osh, uint offset, char *buf, int size, bool write)
{
}
void osl_pcmcia_read_attr(osl_t *osh, uint offset, void *buf, int size)
{
osl_pcmcia_attr(osh, offset, (char *)buf, size, FALSE);
}
void osl_pcmcia_write_attr(osl_t *osh, uint offset, void *buf, int size)
{
osl_pcmcia_attr(osh, offset, (char *)buf, size, TRUE);
}
void *osl_malloc(osl_t *osh, uint size)
{
void *addr;
if (osh)
ASSERT(osh->magic == OS_HANDLE_MAGIC);
#ifdef DHD_USE_STATIC_BUF
if (bcm_static_buf) {
int i = 0;
if ((size >= PAGE_SIZE) && (size <= STATIC_BUF_SIZE)) {
down(&bcm_static_buf->static_sem);
for (i = 0; i < MAX_STATIC_BUF_NUM; i++) {
if (bcm_static_buf->buf_use[i] == 0)
break;
}
if (i == MAX_STATIC_BUF_NUM) {
up(&bcm_static_buf->static_sem);
printk(KERN_ERR "all static buff in use!\n");
goto original;
}
bcm_static_buf->buf_use[i] = 1;
up(&bcm_static_buf->static_sem);
bzero(bcm_static_buf->buf_ptr + STATIC_BUF_SIZE * i,
size);
if (osh)
osh->malloced += size;
return (void *)(bcm_static_buf->buf_ptr +
STATIC_BUF_SIZE * i);
}
}
original:
#endif /* DHD_USE_STATIC_BUF */
if ((addr = kmalloc(size, GFP_ATOMIC)) == NULL) {
if (osh)
osh->failed++;
return NULL;
}
if (osh)
osh->malloced += size;
return addr;
}
void osl_mfree(osl_t *osh, void *addr, uint size)
{
#ifdef DHD_USE_STATIC_BUF
if (bcm_static_buf) {
if ((addr > (void *)bcm_static_buf) && ((unsigned char *)addr
<= ((unsigned char *)
bcm_static_buf +
STATIC_BUF_TOTAL_LEN))) {
int buf_idx = 0;
buf_idx =
((unsigned char *)addr -
bcm_static_buf->buf_ptr) / STATIC_BUF_SIZE;
down(&bcm_static_buf->static_sem);
bcm_static_buf->buf_use[buf_idx] = 0;
up(&bcm_static_buf->static_sem);
if (osh) {
ASSERT(osh->magic == OS_HANDLE_MAGIC);
osh->malloced -= size;
}
return;
}
}
#endif /* DHD_USE_STATIC_BUF */
if (osh) {
ASSERT(osh->magic == OS_HANDLE_MAGIC);
osh->malloced -= size;
}
kfree(addr);
}
uint osl_malloced(osl_t *osh)
{
ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
return osh->malloced;
}
uint osl_malloc_failed(osl_t *osh)
{
ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
return osh->failed;
}
void *osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap)
{
ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
return pci_alloc_consistent(osh->pdev, size, (dma_addr_t *) pap);
}
void osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa)
{
ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
pci_free_consistent(osh->pdev, size, va, (dma_addr_t) pa);
}
uint osl_dma_map(osl_t *osh, void *va, uint size, int direction)
{
int dir;
ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
return pci_map_single(osh->pdev, va, size, dir);
}
void osl_dma_unmap(osl_t *osh, uint pa, uint size, int direction)
{
int dir;
ASSERT((osh && (osh->magic == OS_HANDLE_MAGIC)));
dir = (direction == DMA_TX) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE;
pci_unmap_single(osh->pdev, (uint32) pa, size, dir);
}
#if defined(BCMDBG_ASSERT)
void osl_assert(char *exp, char *file, int line)
{
char tempbuf[256];
char *basename;
basename = strrchr(file, '/');
/* skip the '/' */
if (basename)
basename++;
if (!basename)
basename = file;
#ifdef BCMDBG_ASSERT
snprintf(tempbuf, 256,
"assertion \"%s\" failed: file \"%s\", line %d\n", exp,
basename, line);
/* Print assert message and give it time to be written
to /var/log/messages */
if (!in_interrupt()) {
const int delay = 3;
printk(KERN_ERR "%s", tempbuf);
printk(KERN_ERR "panic in %d seconds\n", delay);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(delay * HZ);
}
switch (g_assert_type) {
case 0:
panic(KERN_ERR "%s", tempbuf);
break;
case 1:
printk(KERN_ERR "%s", tempbuf);
BUG();
break;
case 2:
printk(KERN_ERR "%s", tempbuf);
break;
default:
break;
}
#endif /* BCMDBG_ASSERT */
}
#endif /* defined(BCMDBG_ASSERT) */
void osl_delay(uint usec)
{
uint d;
while (usec > 0) {
d = MIN(usec, 1000);
udelay(d);
usec -= d;
}
}
void *osl_pktdup(osl_t *osh, void *skb)
{
void *p;
if ((p = skb_clone((struct sk_buff *)skb, GFP_ATOMIC)) == NULL)
return NULL;
if (osh->pub.pkttag)
bzero((void *)((struct sk_buff *)p)->cb, OSL_PKTTAG_SZ);
osh->pub.pktalloced++;
return p;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,383 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _wl_cfg80211_h_
#define _wl_cfg80211_h_
#include <linux/wireless.h>
#include <typedefs.h>
#include <proto/ethernet.h>
#include <wlioctl.h>
#include <linux/wireless.h>
#include <net/cfg80211.h>
struct wl_conf;
struct wl_iface;
struct wl_priv;
struct wl_security;
struct wl_ibss;
#if defined(IL_BIGENDIAN)
#include <bcmendian.h>
#define htod32(i) (bcmswap32(i))
#define htod16(i) (bcmswap16(i))
#define dtoh32(i) (bcmswap32(i))
#define dtoh16(i) (bcmswap16(i))
#define htodchanspec(i) htod16(i)
#define dtohchanspec(i) dtoh16(i)
#else
#define htod32(i) i
#define htod16(i) i
#define dtoh32(i) i
#define dtoh16(i) i
#define htodchanspec(i) i
#define dtohchanspec(i) i
#endif
#define WL_DBG_NONE 0
#define WL_DBG_DBG (1 << 2)
#define WL_DBG_INFO (1 << 1)
#define WL_DBG_ERR (1 << 0)
#define WL_DBG_MASK ((WL_DBG_DBG | WL_DBG_INFO | WL_DBG_ERR) << 1)
#define WL_DBG_LEVEL 1 /* 0 invalidates all debug messages.
default is 1 */
#define WL_ERR(args) \
do { \
if (wl_dbg_level & WL_DBG_ERR) { \
if (net_ratelimit()) { \
printk(KERN_ERR "ERROR @%s : ", __func__); \
printk args; \
} \
} \
} while (0)
#define WL_INFO(args) \
do { \
if (wl_dbg_level & WL_DBG_INFO) { \
if (net_ratelimit()) { \
printk(KERN_ERR "INFO @%s : ", __func__); \
printk args; \
} \
} \
} while (0)
#if (WL_DBG_LEVEL > 0)
#define WL_DBG(args) \
do { \
if (wl_dbg_level & WL_DBG_DBG) { \
printk(KERN_ERR "DEBUG @%s :", __func__); \
printk args; \
} \
} while (0)
#else /* !(WL_DBG_LEVEL > 0) */
#define WL_DBG(args)
#endif /* (WL_DBG_LEVEL > 0) */
#define WL_SCAN_RETRY_MAX 3 /* used for ibss scan */
#define WL_NUM_SCAN_MAX 1
#define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used
* for 2.6.33 kernel
* or later
*/
#define WL_SCAN_BUF_MAX (1024 * 8)
#define WL_TLV_INFO_MAX 1024
#define WL_BSS_INFO_MAX 2048
#define WL_ASSOC_INFO_MAX 512 /*
* needs to grab assoc info from dongle to
* report it to cfg80211 through "connect"
* event
*/
#define WL_IOCTL_LEN_MAX 1024
#define WL_EXTRA_BUF_MAX 2048
#define WL_ISCAN_BUF_MAX 2048 /*
* the buf lengh can be WLC_IOCTL_MAXLEN (8K)
* to reduce iteration
*/
#define WL_ISCAN_TIMER_INTERVAL_MS 3000
#define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1)
#define WL_AP_MAX 256 /* virtually unlimitted as long
* as kernel memory allows
*/
#define WL_FILE_NAME_MAX 256
/* dongle status */
enum wl_status {
WL_STATUS_READY,
WL_STATUS_SCANNING,
WL_STATUS_SCAN_ABORTING,
WL_STATUS_CONNECTING,
WL_STATUS_CONNECTED
};
/* wi-fi mode */
enum wl_mode {
WL_MODE_BSS,
WL_MODE_IBSS,
WL_MODE_AP
};
/* dongle profile list */
enum wl_prof_list {
WL_PROF_MODE,
WL_PROF_SSID,
WL_PROF_SEC,
WL_PROF_IBSS,
WL_PROF_BAND,
WL_PROF_BSSID,
WL_PROF_ACT
};
/* dongle iscan state */
enum wl_iscan_state {
WL_ISCAN_STATE_IDLE,
WL_ISCAN_STATE_SCANING
};
/* fw downloading status */
enum wl_fw_status {
WL_FW_LOADING_DONE,
WL_NVRAM_LOADING_DONE
};
/* dongle configuration */
struct wl_conf {
uint32 mode; /* adhoc , infrastructure or ap */
uint32 frag_threshold;
uint32 rts_threshold;
uint32 retry_short;
uint32 retry_long;
int32 tx_power;
struct ieee80211_channel channel;
};
/* cfg80211 main event loop */
struct wl_event_loop {
int32(*handler[WLC_E_LAST]) (struct wl_priv *wl,
struct net_device *ndev,
const wl_event_msg_t *e, void *data);
};
/* representing interface of cfg80211 plane */
struct wl_iface {
struct wl_priv *wl;
};
struct wl_dev {
void *driver_data; /* to store cfg80211 object information */
};
/* bss inform structure for cfg80211 interface */
struct wl_cfg80211_bss_info {
uint16 band;
uint16 channel;
int16 rssi;
uint16 frame_len;
uint8 frame_buf[1];
};
/* basic structure of scan request */
struct wl_scan_req {
struct wlc_ssid ssid;
};
/* basic structure of information element */
struct wl_ie {
uint16 offset;
uint8 buf[WL_TLV_INFO_MAX];
};
/* event queue for cfg80211 main event */
struct wl_event_q {
struct list_head eq_list;
uint32 etype;
wl_event_msg_t emsg;
int8 edata[1];
};
/* security information with currently associated ap */
struct wl_security {
uint32 wpa_versions;
uint32 auth_type;
uint32 cipher_pairwise;
uint32 cipher_group;
uint32 wpa_auth;
};
/* ibss information for currently joined ibss network */
struct wl_ibss {
uint8 beacon_interval; /* in millisecond */
uint8 atim; /* in millisecond */
int8 join_only;
uint8 band;
uint8 channel;
};
/* dongle profile */
struct wl_profile {
uint32 mode;
struct wlc_ssid ssid;
uint8 bssid[ETHER_ADDR_LEN];
struct wl_security sec;
struct wl_ibss ibss;
int32 band;
bool active;
};
/* dongle iscan event loop */
struct wl_iscan_eloop {
int32(*handler[WL_SCAN_ERSULTS_LAST]) (struct wl_priv *wl);
};
/* dongle iscan controller */
struct wl_iscan_ctrl {
struct net_device *dev;
struct timer_list timer;
uint32 timer_ms;
uint32 timer_on;
int32 state;
int32 pid;
struct semaphore sync;
struct completion exited;
struct wl_iscan_eloop el;
void *data;
int8 ioctl_buf[WLC_IOCTL_SMLEN];
int8 scan_buf[WL_ISCAN_BUF_MAX];
};
/* association inform */
struct wl_connect_info {
uint8 *req_ie;
int32 req_ie_len;
uint8 *resp_ie;
int32 resp_ie_len;
};
/* firmware /nvram downloading controller */
struct wl_fw_ctrl {
const struct firmware *fw_entry;
ulong status;
uint32 ptr;
int8 fw_name[WL_FILE_NAME_MAX];
int8 nvram_name[WL_FILE_NAME_MAX];
};
/* assoc ie length */
struct wl_assoc_ielen {
uint32 req_len;
uint32 resp_len;
};
/* wpa2 pmk list */
struct wl_pmk_list {
pmkid_list_t pmkids;
pmkid_t foo[MAXPMKID - 1];
};
/* dongle private data of cfg80211 interface */
struct wl_priv {
struct wireless_dev *wdev; /* representing wl cfg80211 device */
struct wl_conf *conf; /* dongle configuration */
struct cfg80211_scan_request *scan_request; /* scan request
object */
struct wl_event_loop el; /* main event loop */
struct list_head eq_list; /* used for event queue */
spinlock_t eq_lock; /* for event queue synchronization */
struct mutex usr_sync; /* maily for dongle up/down synchronization */
struct wl_scan_results *bss_list; /* bss_list holding scanned
ap information */
struct wl_scan_results *scan_results;
struct wl_scan_req *scan_req_int; /* scan request object for
internal purpose */
struct wl_cfg80211_bss_info *bss_info; /* bss information for
cfg80211 layer */
struct wl_ie ie; /* information element object for
internal purpose */
struct ether_addr bssid; /* bssid of currently engaged network */
struct semaphore event_sync; /* for synchronization of main event
thread */
struct completion event_exit;
struct wl_profile *profile; /* holding dongle profile */
struct wl_iscan_ctrl *iscan; /* iscan controller */
struct wl_connect_info conn_info; /* association information
container */
struct wl_fw_ctrl *fw; /* control firwmare / nvram paramter
downloading */
struct wl_pmk_list *pmk_list; /* wpa2 pmk list */
int32 event_pid; /* pid of main event handler thread */
ulong status; /* current dongle status */
void *pub;
uint32 channel; /* current channel */
bool iscan_on; /* iscan on/off switch */
bool iscan_kickstart; /* indicate iscan already started */
bool active_scan; /* current scan mode */
bool ibss_starter; /* indicates this sta is ibss starter */
bool link_up; /* link/connection up flag */
bool pwr_save; /* indicate whether dongle to support
power save mode */
bool dongle_up; /* indicate whether dongle up or not */
bool roam_on; /* on/off switch for dongle self-roaming */
bool scan_tried; /* indicates if first scan attempted */
uint8 *ioctl_buf; /* ioctl buffer */
uint8 *extra_buf; /* maily to grab assoc information */
uint8 ci[0] __attribute__ ((__aligned__(NETDEV_ALIGN)));
};
#define wl_to_dev(w) (wiphy_dev(wl->wdev->wiphy))
#define wl_to_wiphy(w) (w->wdev->wiphy)
#define wiphy_to_wl(w) ((struct wl_priv *)(wiphy_priv(w)))
#define wl_to_wdev(w) (w->wdev)
#define wdev_to_wl(w) ((struct wl_priv *)(wdev_priv(w)))
#define wl_to_ndev(w) (w->wdev->netdev)
#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr))
#define ci_to_wl(c) (ci->wl)
#define wl_to_ci(w) (&w->ci)
#define wl_to_sr(w) (w->scan_req_int)
#define wl_to_ie(w) (&w->ie)
#define iscan_to_wl(i) ((struct wl_priv *)(i->data))
#define wl_to_iscan(w) (w->iscan)
#define wl_to_conn(w) (&w->conn_info)
static inline struct wl_bss_info *next_bss(struct wl_scan_results *list,
struct wl_bss_info *bss)
{
return bss = bss ?
(struct wl_bss_info *)((uintptr) bss +
dtoh32(bss->length)) : list->bss_info;
}
#define for_each_bss(list, bss, __i) \
for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss))
extern int32 wl_cfg80211_attach(struct net_device *ndev, void *data);
extern void wl_cfg80211_detach(void);
/* event handler from dongle */
extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e,
void *data);
extern void wl_cfg80211_sdio_func(void *func); /* set sdio function info */
extern int32 wl_cfg80211_up(void); /* dongle up */
extern int32 wl_cfg80211_down(void); /* dongle down */
extern void wl_cfg80211_dbg_level(uint32 level); /* set dongle
debugging level */
extern void *wl_cfg80211_request_fw(int8 *file_name); /* request fw /nvram
downloading */
extern int32 wl_cfg80211_read_fw(int8 *buf, uint32 size); /* read fw
image */
extern void wl_cfg80211_release_fw(void); /* release fw */
extern int8 *wl_cfg80211_get_fwname(void); /* get firmware name for
the dongle */
extern int8 *wl_cfg80211_get_nvramname(void); /* get nvram name for
the dongle */
#endif /* _wl_cfg80211_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,154 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _wl_iw_h_
#define _wl_iw_h_
#include <linux/wireless.h>
#include <typedefs.h>
#include <proto/ethernet.h>
#include <wlioctl.h>
#define WL_SCAN_PARAMS_SSID_MAX 10
#define GET_SSID "SSID="
#define GET_CHANNEL "CH="
#define GET_NPROBE "NPROBE="
#define GET_ACTIVE_ASSOC_DWELL "ACTIVE="
#define GET_PASSIVE_ASSOC_DWELL "PASSIVE="
#define GET_HOME_DWELL "HOME="
#define GET_SCAN_TYPE "TYPE="
#define BAND_GET_CMD "BANDGET"
#define BAND_SET_CMD "BANDSET"
#define DTIM_SKIP_GET_CMD "DTIMSKIPGET"
#define DTIM_SKIP_SET_CMD "DTIMSKIPSET"
#define SETSUSPEND_CMD "SETSUSPENDOPT"
#define PNOSSIDCLR_SET_CMD "PNOSSIDCLR"
#define PNOSETUP_SET_CMD "PNOSETUP"
#define PNOENABLE_SET_CMD "PNOFORCE"
#define PNODEBUG_SET_CMD "PNODEBUG"
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
typedef struct wl_iw_extra_params {
int target_channel;
} wl_iw_extra_params_t;
#define WL_IW_RSSI_MINVAL -200
#define WL_IW_RSSI_NO_SIGNAL -91
#define WL_IW_RSSI_VERY_LOW -80
#define WL_IW_RSSI_LOW -70
#define WL_IW_RSSI_GOOD -68
#define WL_IW_RSSI_VERY_GOOD -58
#define WL_IW_RSSI_EXCELLENT -57
#define WL_IW_RSSI_INVALID 0
#define MAX_WX_STRING 80
#define isprint(c) bcm_isprint(c)
#define WL_IW_SET_ACTIVE_SCAN (SIOCIWFIRSTPRIV+1)
#define WL_IW_GET_RSSI (SIOCIWFIRSTPRIV+3)
#define WL_IW_SET_PASSIVE_SCAN (SIOCIWFIRSTPRIV+5)
#define WL_IW_GET_LINK_SPEED (SIOCIWFIRSTPRIV+7)
#define WL_IW_GET_CURR_MACADDR (SIOCIWFIRSTPRIV+9)
#define WL_IW_SET_STOP (SIOCIWFIRSTPRIV+11)
#define WL_IW_SET_START (SIOCIWFIRSTPRIV+13)
#define WL_SET_AP_CFG (SIOCIWFIRSTPRIV+15)
#define WL_AP_STA_LIST (SIOCIWFIRSTPRIV+17)
#define WL_AP_MAC_FLTR (SIOCIWFIRSTPRIV+19)
#define WL_AP_BSS_START (SIOCIWFIRSTPRIV+21)
#define AP_LPB_CMD (SIOCIWFIRSTPRIV+23)
#define WL_AP_STOP (SIOCIWFIRSTPRIV+25)
#define WL_FW_RELOAD (SIOCIWFIRSTPRIV+27)
#define WL_COMBO_SCAN (SIOCIWFIRSTPRIV+29)
#define WL_AP_SPARE3 (SIOCIWFIRSTPRIV+31)
#define G_SCAN_RESULTS 8*1024
#define WE_ADD_EVENT_FIX 0x80
#define G_WLAN_SET_ON 0
#define G_WLAN_SET_OFF 1
#define CHECK_EXTRA_FOR_NULL(extra) \
if (!extra) { \
WL_ERROR(("%s: error : extra is null pointer\n", __func__)); \
return -EINVAL; \
}
typedef struct wl_iw {
char nickname[IW_ESSID_MAX_SIZE];
struct iw_statistics wstats;
int spy_num;
uint32 pwsec;
uint32 gwsec;
bool privacy_invoked;
struct ether_addr spy_addr[IW_MAX_SPY];
struct iw_quality spy_qual[IW_MAX_SPY];
void *wlinfo;
dhd_pub_t *pub;
} wl_iw_t;
#if WIRELESS_EXT > 12
#include <net/iw_handler.h>
extern const struct iw_handler_def wl_iw_handler_def;
#endif
extern int wl_iw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
extern void wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void *data);
extern int wl_iw_get_wireless_stats(struct net_device *dev,
struct iw_statistics *wstats);
int wl_iw_attach(struct net_device *dev, void *dhdp);
void wl_iw_detach(void);
extern int net_os_set_suspend_disable(struct net_device *dev, int val);
extern int net_os_set_suspend(struct net_device *dev, int val);
extern int net_os_set_dtim_skip(struct net_device *dev, int val);
extern int net_os_set_packet_filter(struct net_device *dev, int val);
#define IWE_STREAM_ADD_EVENT(info, stream, ends, iwe, extra) \
iwe_stream_add_event(info, stream, ends, iwe, extra)
#define IWE_STREAM_ADD_VALUE(info, event, value, ends, iwe, event_len) \
iwe_stream_add_value(info, event, value, ends, iwe, event_len)
#define IWE_STREAM_ADD_POINT(info, stream, ends, iwe, extra) \
iwe_stream_add_point(info, stream, ends, iwe, extra)
extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled);
extern int dhd_pno_clean(dhd_pub_t *dhd);
extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t *ssids_local, int nssid,
uchar scan_fr);
extern int dhd_pno_get_status(dhd_pub_t *dhd);
extern int dhd_dev_pno_reset(struct net_device *dev);
extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t *ssids_local,
int nssid, uchar scan_fr);
extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled);
extern int dhd_dev_get_pno_status(struct net_device *dev);
#define PNO_TLV_PREFIX 'S'
#define PNO_TLV_VERSION 1
#define PNO_TLV_SUBVERSION 0
#define PNO_TLV_RESERVED 0
#define PNO_TLV_TYPE_SSID_IE 'S'
#define PNO_TLV_TYPE_TIME 'T'
#define PNO_EVENT_UP "PNO_EVENT"
typedef struct cmd_tlv {
char prefix;
char version;
char subver;
char reserved;
} cmd_tlv_t;
#endif /* _wl_iw_h_ */

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <proto/ethernet.h>
typedef struct cdc_ioctl {
uint32 cmd; /* ioctl command value */
uint32 len; /* lower 16: output buflen; upper 16:
input buflen (excludes header) */
uint32 flags; /* flag defns given below */
uint32 status; /* status code returned from the device */
} cdc_ioctl_t;
/* Max valid buffer size that can be sent to the dongle */
#define CDC_MAX_MSG_SIZE ETHER_MAX_LEN
/* len field is divided into input and output buffer lengths */
#define CDCL_IOC_OUTLEN_MASK 0x0000FFFF /* maximum or expected
response length, */
/* excluding IOCTL header */
#define CDCL_IOC_OUTLEN_SHIFT 0
#define CDCL_IOC_INLEN_MASK 0xFFFF0000 /* input buffer length,
excluding IOCTL header */
#define CDCL_IOC_INLEN_SHIFT 16
/* CDC flag definitions */
#define CDCF_IOC_ERROR 0x01 /* 0=success, 1=ioctl cmd failed */
#define CDCF_IOC_SET 0x02 /* 0=get, 1=set cmd */
#define CDCF_IOC_IF_MASK 0xF000 /* I/F index */
#define CDCF_IOC_IF_SHIFT 12
#define CDCF_IOC_ID_MASK 0xFFFF0000 /* used to uniquely id an ioctl
req/resp pairing */
#define CDCF_IOC_ID_SHIFT 16 /* # of bits of shift for ID Mask */
#define CDC_IOC_IF_IDX(flags) \
(((flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT)
#define CDC_IOC_ID(flags) \
(((flags) & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT)
#define CDC_GET_IF_IDX(hdr) \
((int)((((hdr)->flags) & CDCF_IOC_IF_MASK) >> CDCF_IOC_IF_SHIFT))
#define CDC_SET_IF_IDX(hdr, idx) \
((hdr)->flags = (((hdr)->flags & ~CDCF_IOC_IF_MASK) | \
((idx) << CDCF_IOC_IF_SHIFT)))
/*
* BDC header
*
* The BDC header is used on data packets to convey priority across USB.
*/
#define BDC_HEADER_LEN 4
#define BDC_PROTO_VER 1 /* Protocol version */
#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */
#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */
#define BDC_FLAG__UNUSED 0x03 /* Unassigned */
#define BDC_FLAG_SUM_GOOD 0x04 /* Dongle has verified good
RX checksums */
#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */
#define BDC_PRIORITY_MASK 0x7
#define BDC_FLAG2_FC_FLAG 0x10 /* flag to indicate if pkt contains */
/* FLOW CONTROL info only */
#define BDC_PRIORITY_FC_SHIFT 4 /* flow control info shift */
#define BDC_FLAG2_IF_MASK 0x0f /* APSTA: interface on which the
packet was received */
#define BDC_FLAG2_IF_SHIFT 0
#define BDC_GET_IF_IDX(hdr) \
((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT))
#define BDC_SET_IF_IDX(hdr, idx) \
((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \
((idx) << BDC_FLAG2_IF_SHIFT)))
struct bdc_header {
uint8 flags; /* Flags */
uint8 priority; /* 802.1d Priority 0:2 bits, 4:7 flow
control info for usb */
uint8 flags2;
uint8 rssi;
};

View File

@ -17,6 +17,13 @@
#ifndef _bcmdefs_h_
#define _bcmdefs_h_
#define SI_BUS 0
#define PCI_BUS 1
#define PCMCIA_BUS 2
#define SDIO_BUS 3
#define JTAG_BUS 4
#define USB_BUS 5
#define SPI_BUS 6
/*
* One doesn't need to include this file explicitly, gets included automatically if
* typedefs.h is included.

View File

@ -24,9 +24,13 @@
#define BCM_DNGL_VID 0x0a5c
#define BCM_DNGL_BDC_PID 0x0bdc
#define BCM4325_D11DUAL_ID 0x431b
#define BCM4325_D11G_ID 0x431c
#define BCM4325_D11A_ID 0x431d
#define BCM4329_D11N_ID 0x432e /* 4329 802.11n dualband device */
#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */
#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */
#define BCM4329_D11NDUAL_ID 0x432e
#define BCM4319_D11N_ID 0x4337 /* 4319 802.11n dualband device */
#define BCM4319_D11N2G_ID 0x4338 /* 4319 802.11n 2.4G device */
@ -62,6 +66,7 @@
#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */
#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */
#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */
#define BCM4325_CHIP_ID 0x4325 /* 4325 chipcommon chipid */
#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */
#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */
#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */

View File

@ -39,6 +39,8 @@ extern void sdioh_sdmmc_osfree(sdioh_info_t *sd);
#define BLOCK_SIZE_64 64
#define BLOCK_SIZE_512 512
#define BLOCK_SIZE_4318 64
#define BLOCK_SIZE_4328 512
/* internal return code */
#define SUCCESS 0

View File

@ -21,6 +21,36 @@
extern "C" {
#endif
#ifdef BRCM_FULLMAC
/* ctype replacement */
#define _BCM_U 0x01 /* upper */
#define _BCM_L 0x02 /* lower */
#define _BCM_D 0x04 /* digit */
#define _BCM_C 0x08 /* cntrl */
#define _BCM_P 0x10 /* punct */
#define _BCM_S 0x20 /* white space (space/lf/tab) */
#define _BCM_X 0x40 /* hex digit */
#define _BCM_SP 0x80 /* hard space (0x20) */
extern const unsigned char bcm_ctype[];
#define bcm_ismask(x) (bcm_ctype[(int)(unsigned char)(x)])
#define bcm_isalnum(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L|_BCM_D)) != 0)
#define bcm_isalpha(c) ((bcm_ismask(c)&(_BCM_U|_BCM_L)) != 0)
#define bcm_iscntrl(c) ((bcm_ismask(c)&(_BCM_C)) != 0)
#define bcm_isdigit(c) ((bcm_ismask(c)&(_BCM_D)) != 0)
#define bcm_isgraph(c) ((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D)) != 0)
#define bcm_islower(c) ((bcm_ismask(c)&(_BCM_L)) != 0)
#define bcm_isprint(c) \
((bcm_ismask(c)&(_BCM_P|_BCM_U|_BCM_L|_BCM_D|_BCM_SP)) != 0)
#define bcm_ispunct(c) ((bcm_ismask(c)&(_BCM_P)) != 0)
#define bcm_isspace(c) ((bcm_ismask(c)&(_BCM_S)) != 0)
#define bcm_isupper(c) ((bcm_ismask(c)&(_BCM_U)) != 0)
#define bcm_isxdigit(c) ((bcm_ismask(c)&(_BCM_D|_BCM_X)) != 0)
#define bcm_tolower(c) (bcm_isupper((c)) ? ((c) + 'a' - 'A') : (c))
#define bcm_toupper(c) (bcm_islower((c)) ? ((c) + 'A' - 'a') : (c))
#endif /* BRCM_FULLMAC */
/* Buffer structure for collecting string-formatted data
* using bcm_bprintf() API.
* Use bcm_binit() to initialize before use
@ -114,8 +144,13 @@ extern "C" {
extern void *pktq_pdeq(struct pktq *pq, int prec);
extern void *pktq_pdeq_tail(struct pktq *pq, int prec);
/* Empty the queue at particular precedence level */
#ifdef BRCM_FULLMAC
extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec,
bool dir, ifpkt_cb_t fn, int arg);
bool dir);
#else
extern void pktq_pflush(osl_t *osh, struct pktq *pq, int prec,
bool dir, ifpkt_cb_t fn, int arg);
#endif
/* Remove a specified packet from its queue */
extern bool pktq_pdel(struct pktq *pq, void *p, int prec);
@ -145,8 +180,12 @@ extern "C" {
extern void *pktq_deq_tail(struct pktq *pq, int *prec_out);
extern void *pktq_peek(struct pktq *pq, int *prec_out);
extern void *pktq_peek_tail(struct pktq *pq, int *prec_out);
#ifdef BRCM_FULLMAC
extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir);
#else
extern void pktq_flush(osl_t *osh, struct pktq *pq, bool dir,
ifpkt_cb_t fn, int arg);
ifpkt_cb_t fn, int arg);
#endif
/* externs */
/* packet */
@ -165,6 +204,20 @@ extern "C" {
#define PKTPRIO_UPD 0x400 /* DSCP used to update VLAN prio */
#define PKTPRIO_DSCP 0x800 /* DSCP prio found */
#ifdef BRCM_FULLMAC
/* string */
extern int BCMROMFN(bcm_atoi) (char *s);
extern ulong BCMROMFN(bcm_strtoul) (char *cp, char **endp, uint base);
extern char *BCMROMFN(bcmstrstr) (char *haystack, char *needle);
extern char *BCMROMFN(bcmstrcat) (char *dest, const char *src);
extern char *BCMROMFN(bcmstrncat) (char *dest, const char *src,
uint size);
extern ulong wchar2ascii(char *abuf, ushort *wbuf, ushort wbuflen,
ulong abuflen);
char *bcmstrtok(char **string, const char *delimiters, char *tokdelim);
int bcmstricmp(const char *s1, const char *s2);
int bcmstrnicmp(const char *s1, const char *s2, int cnt);
#endif
/* ethernet address */
extern char *bcm_ether_ntoa(const struct ether_addr *ea, char *buf);
extern int BCMROMFN(bcm_ether_atoe) (char *p, struct ether_addr *ea);

View File

@ -0,0 +1,109 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _dhdioctl_h_
#define _dhdioctl_h_
#include <typedefs.h>
/* require default structure packing */
#define BWL_DEFAULT_PACKING
#include <packed_section_start.h>
/* Linux network driver ioctl encoding */
typedef struct dhd_ioctl {
uint cmd; /* common ioctl definition */
void *buf; /* pointer to user buffer */
uint len; /* length of user buffer */
bool set; /* get or set request (optional) */
uint used; /* bytes read or written (optional) */
uint needed; /* bytes needed (optional) */
uint driver; /* to identify target driver */
} dhd_ioctl_t;
/* per-driver magic numbers */
#define DHD_IOCTL_MAGIC 0x00444944
/* bump this number if you change the ioctl interface */
#define DHD_IOCTL_VERSION 1
#define DHD_IOCTL_MAXLEN 8192 /* max length ioctl buffer required */
#define DHD_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */
/* common ioctl definitions */
#define DHD_GET_MAGIC 0
#define DHD_GET_VERSION 1
#define DHD_GET_VAR 2
#define DHD_SET_VAR 3
/* message levels */
#define DHD_ERROR_VAL 0x0001
#define DHD_TRACE_VAL 0x0002
#define DHD_INFO_VAL 0x0004
#define DHD_DATA_VAL 0x0008
#define DHD_CTL_VAL 0x0010
#define DHD_TIMER_VAL 0x0020
#define DHD_HDRS_VAL 0x0040
#define DHD_BYTES_VAL 0x0080
#define DHD_INTR_VAL 0x0100
#define DHD_LOG_VAL 0x0200
#define DHD_GLOM_VAL 0x0400
#define DHD_EVENT_VAL 0x0800
#define DHD_BTA_VAL 0x1000
#define DHD_ISCAN_VAL 0x2000
#ifdef SDTEST
/* For pktgen iovar */
typedef struct dhd_pktgen {
uint version; /* To allow structure change tracking */
uint freq; /* Max ticks between tx/rx attempts */
uint count; /* Test packets to send/rcv each attempt */
uint print; /* Print counts every <print> attempts */
uint total; /* Total packets (or bursts) */
uint minlen; /* Minimum length of packets to send */
uint maxlen; /* Maximum length of packets to send */
uint numsent; /* Count of test packets sent */
uint numrcvd; /* Count of test packets received */
uint numfail; /* Count of test send failures */
uint mode; /* Test mode (type of test packets) */
uint stop; /* Stop after this many tx failures */
} dhd_pktgen_t;
/* Version in case structure changes */
#define DHD_PKTGEN_VERSION 2
/* Type of test packets to use */
#define DHD_PKTGEN_ECHO 1 /* Send echo requests */
#define DHD_PKTGEN_SEND 2 /* Send discard packets */
#define DHD_PKTGEN_RXBURST 3 /* Request dongle send N packets */
#define DHD_PKTGEN_RECV 4 /* Continuous rx from continuous
tx dongle */
#endif /* SDTEST */
/* Enter idle immediately (no timeout) */
#define DHD_IDLE_IMMEDIATE (-1)
/* Values for idleclock iovar: other values are the sd_divisor to use
when idle */
#define DHD_IDLE_ACTIVE 0 /* Do not request any SD clock change
when idle */
#define DHD_IDLE_STOP (-1) /* Request SD clock be stopped
(and use SD1 mode) */
/* require default structure packing */
#include <packed_section_end.h>
#endif /* _dhdioctl_h_ */

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _hndrte_armtrap_h
#define _hndrte_armtrap_h
/* ARM trap handling */
/* Trap types defined by ARM (see arminc.h) */
/* Trap locations in lo memory */
#define TRAP_STRIDE 4
#define FIRST_TRAP TR_RST
#define LAST_TRAP (TR_FIQ * TRAP_STRIDE)
#if defined(__ARM_ARCH_4T__)
#define MAX_TRAP_TYPE (TR_FIQ + 1)
#elif defined(__ARM_ARCH_7M__)
#define MAX_TRAP_TYPE (TR_ISR + ARMCM3_NUMINTS)
#endif /* __ARM_ARCH_7M__ */
/* The trap structure is defined here as offsets for assembly */
#define TR_TYPE 0x00
#define TR_EPC 0x04
#define TR_CPSR 0x08
#define TR_SPSR 0x0c
#define TR_REGS 0x10
#define TR_REG(n) (TR_REGS + (n) * 4)
#define TR_SP TR_REG(13)
#define TR_LR TR_REG(14)
#define TR_PC TR_REG(15)
#define TRAP_T_SIZE 80
#ifndef _LANGUAGE_ASSEMBLY
#include <typedefs.h>
typedef struct _trap_struct {
uint32 type;
uint32 epc;
uint32 cpsr;
uint32 spsr;
uint32 r0;
uint32 r1;
uint32 r2;
uint32 r3;
uint32 r4;
uint32 r5;
uint32 r6;
uint32 r7;
uint32 r8;
uint32 r9;
uint32 r10;
uint32 r11;
uint32 r12;
uint32 r13;
uint32 r14;
uint32 pc;
} trap_t;
#endif /* !_LANGUAGE_ASSEMBLY */
#endif /* _hndrte_armtrap_h */

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <typedefs.h>
#define CBUF_LEN (128)
#define LOG_BUF_LEN 1024
typedef struct {
uint32 buf; /* Can't be pointer on (64-bit) hosts */
uint buf_size;
uint idx;
char *_buf_compat; /* Redundant pointer for backward compat. */
} hndrte_log_t;
typedef struct {
/* Virtual UART
* When there is no UART (e.g. Quickturn),
* the host should write a complete
* input line directly into cbuf and then write
* the length into vcons_in.
* This may also be used when there is a real UART
* (at risk of conflicting with
* the real UART). vcons_out is currently unused.
*/
volatile uint vcons_in;
volatile uint vcons_out;
/* Output (logging) buffer
* Console output is written to a ring buffer log_buf at index log_idx.
* The host may read the output when it sees log_idx advance.
* Output will be lost if the output wraps around faster than the host
* polls.
*/
hndrte_log_t log;
/* Console input line buffer
* Characters are read one at a time into cbuf
* until <CR> is received, then
* the buffer is processed as a command line.
* Also used for virtual UART.
*/
uint cbuf_idx;
char cbuf[CBUF_LEN];
} hndrte_cons_t;

View File

@ -79,7 +79,7 @@ typedef struct {
bool mmbus; /* Bus supports memory-mapped register accesses */
pktfree_cb_fn_t tx_fn; /* Callback function for PKTFREE */
void *tx_ctx; /* Context to the callback function */
#ifdef BCMSDIO
#if defined(BCMSDIO) && !defined(BRCM_FULLMAC)
osl_rreg_fn_t rreg_fn; /* Read Register function */
osl_wreg_fn_t wreg_fn; /* Write Register function */
void *reg_ctx; /* Context to the reg callback functions */
@ -92,7 +92,7 @@ typedef struct {
((osl_pubinfo_t *)osh)->tx_ctx = _tx_ctx; \
} while (0)
#ifdef BCMSDIO
#if defined(BCMSDIO) && !defined(BRCM_FULLMAC)
#define REGOPSSET(osh, rreg, wreg, ctx) \
do { \
((osl_pubinfo_t *)osh)->rreg_fn = rreg; \
@ -115,15 +115,22 @@ extern uint osl_malloced(osl_t *osh);
#define MALLOC_FAILED(osh) osl_malloc_failed((osh))
extern uint osl_malloc_failed(osl_t *osh);
#ifdef BRCM_FULLMAC
#define DMA_CONSISTENT_ALIGN PAGE_SIZE
#define DMA_ALLOC_CONSISTENT(osh, size, pap, dmah, alignbits) \
osl_dma_alloc_consistent((osh), (size), (pap))
extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, ulong *pap);
#else
/* allocate/free shared (dma-able) consistent memory */
#define DMA_CONSISTENT_ALIGN osl_dma_consistent_align()
#define DMA_ALLOC_CONSISTENT(osh, size, align, tot, pap, dmah) \
osl_dma_alloc_consistent((osh), (size), (align), (tot), (pap))
#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \
osl_dma_free_consistent((osh), (void *)(va), (size), (pa))
extern uint osl_dma_consistent_align(void);
extern void *osl_dma_alloc_consistent(osl_t *osh, uint size, uint16 align,
uint *tot, ulong *pap);
#endif
#define DMA_FREE_CONSISTENT(osh, va, size, pa, dmah) \
osl_dma_free_consistent((osh), (void *)(va), (size), (pa))
extern void osl_dma_free_consistent(osl_t *osh, void *va, uint size, ulong pa);
/* map/unmap direction */
@ -317,32 +324,73 @@ extern int osl_error(int bcmerror);
/* packet primitives */
#define PKTGET(osh, len, send) osl_pktget((osh), (len))
#define PKTDUP(osh, skb) osl_pktdup((osh), (skb))
#define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send))
#define PKTDATA(skb) (((struct sk_buff *)(skb))->data)
#define PKTLEN(skb) (((struct sk_buff *)(skb))->len)
#define PKTDATA(skb) (((struct sk_buff *)(skb))->data)
#define PKTLEN(skb) (((struct sk_buff *)(skb))->len)
#define PKTHEADROOM(skb) (PKTDATA(skb)-(((struct sk_buff *)(skb))->head))
#define PKTTAILROOM(skb) ((((struct sk_buff *)(skb))->end)-(((struct sk_buff *)(skb))->tail))
#define PKTNEXT(skb) (((struct sk_buff *)(skb))->next)
#define PKTSETNEXT(skb, x) (((struct sk_buff *)(skb))->next = (struct sk_buff*)(x))
#define PKTSETLEN(skb, len) __skb_trim((struct sk_buff *)(skb), (len))
#define PKTPUSH(skb, bytes) skb_push((struct sk_buff *)(skb), (bytes))
#define PKTPULL(skb, bytes) skb_pull((struct sk_buff *)(skb), (bytes))
#define PKTTAG(skb) ((void *)(((struct sk_buff *)(skb))->cb))
#define PKTALLOCED(osh) (((osl_pubinfo_t *)(osh))->pktalloced)
#define PKTNEXT(skb) (((struct sk_buff *)(skb))->next)
#define PKTSETNEXT(skb, x) \
(((struct sk_buff *)(skb))->next = (struct sk_buff *)(x))
#define PKTSETLEN(skb, len) __skb_trim((struct sk_buff *)(skb), (len))
#define PKTPUSH(skb, bytes) skb_push((struct sk_buff *)(skb), (bytes))
#define PKTPULL(skb, bytes) skb_pull((struct sk_buff *)(skb), (bytes))
#define PKTDUP(osh, skb) osl_pktdup((osh), (skb))
#define PKTTAG(skb) ((void *)(((struct sk_buff *)(skb))->cb))
#define PKTALLOCED(osh) (((osl_pubinfo_t *)(osh))->pktalloced)
#define PKTSETPOOL(osh, skb, x, y) do {} while (0)
#define PKTPOOL(osh, skb) FALSE
extern void *osl_pktget(osl_t *osh, uint len);
extern void osl_pktfree(osl_t *osh, void *skb, bool send);
extern void *osl_pktdup(osl_t *osh, void *skb);
#ifdef BRCM_FULLMAC
#ifdef DHD_USE_STATIC_BUF
#define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len))
#define PKTFREE_STATIC(osh, skb, send) \
osl_pktfree_static((osh), (skb), (send))
#endif
extern void *osl_pktget_static(osl_t *osh, uint len);
extern void osl_pktfree_static(osl_t *osh, void *skb, bool send);
static INLINE void *
osl_pkt_frmnative(osl_pubinfo_t *osh, struct sk_buff *skb)
{
struct sk_buff *nskb;
if (osh->pkttag)
bzero((void *)skb->cb, OSL_PKTTAG_SZ);
for (nskb = skb; nskb; nskb = nskb->next)
osh->pktalloced++;
return (void *)skb;
}
#define PKTFRMNATIVE(osh, skb) \
osl_pkt_frmnative(((osl_pubinfo_t *)osh), (struct sk_buff*)(skb))
static INLINE struct sk_buff *
osl_pkt_tonative(osl_pubinfo_t *osh, void *pkt)
{
struct sk_buff *nskb;
if (osh->pkttag)
bzero(((struct sk_buff *)pkt)->cb, OSL_PKTTAG_SZ);
for (nskb = (struct sk_buff *)pkt; nskb; nskb = nskb->next)
osh->pktalloced--;
return (struct sk_buff *)pkt;
}
#define PKTTONATIVE(osh, pkt) \
osl_pkt_tonative((osl_pubinfo_t *)(osh), (pkt))
#else /* !BRCM_FULLMAC */
#define PKTUNALLOC(osh) (((osl_pubinfo_t *)(osh))->pktalloced--)
#define PKTSETSKIPCT(osh, skb)
#define PKTCLRSKIPCT(osh, skb)
#define PKTSKIPCT(osh, skb)
extern void osl_pktfree(osl_t *osh, void *skb, bool send);
extern void *osl_pktget(osl_t *osh, uint len);
extern void *osl_pktdup(osl_t *osh, void *skb);
#endif /* BRCM_FULLMAC */
#define PKTLINK(skb) (((struct sk_buff *)(skb))->prev)
#define PKTSETLINK(skb, x) (((struct sk_buff *)(skb))->prev = (struct sk_buff*)(x))
@ -354,7 +402,7 @@ extern void *osl_pktdup(osl_t *osh, void *skb);
/* PKTSETSUMNEEDED and PKTSUMGOOD are not possible because skb->ip_summed is overloaded */
#define PKTSHARED(skb) (((struct sk_buff *)(skb))->cloned)
#ifdef BCMSDIO
#if defined(BCMSDIO) && !defined(BRCM_FULLMAC)
#define RPC_READ_REG(osh, r) (\
sizeof(*(r)) == sizeof(uint8) ? osl_readb((osh), (volatile uint8*)(r)) : \
sizeof(*(r)) == sizeof(uint16) ? osl_readw((osh), (volatile uint16*)(r)) : \

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _MSGTRACE_H
#define _MSGTRACE_H
#ifndef _TYPEDEFS_H_
#include <typedefs.h>
#endif
/* This marks the start of a packed structure section. */
#include <packed_section_start.h>
#define MSGTRACE_VERSION 1
/* Message trace header */
typedef BWL_PRE_PACKED_STRUCT struct msgtrace_hdr {
uint8 version;
uint8 spare;
uint16 len; /* Len of the trace */
uint32 seqnum; /* Sequence number of message. Useful
* if the messsage has been lost
* because of DMA error or a bus reset
* (ex: SDIO Func2)
*/
uint32 discarded_bytes; /* Number of discarded bytes because of
trace overflow */
uint32 discarded_printf; /* Number of discarded printf
because of trace overflow */
} BWL_POST_PACKED_STRUCT msgtrace_hdr_t;
#define MSGTRACE_HDRLEN sizeof(msgtrace_hdr_t)
/* The hbus driver generates traces when sending a trace message.
* This causes endless traces.
* This flag must be set to TRUE in any hbus traces.
* The flag is reset in the function msgtrace_put.
* This prevents endless traces but generates hasardous
* lost of traces only in bus device code.
* It is recommendat to set this flag in macro SD_TRACE
* but not in SD_ERROR for avoiding missing
* hbus error traces. hbus error trace should not generates endless traces.
*/
extern bool msgtrace_hbus_trace;
typedef void (*msgtrace_func_send_t) (void *hdl1, void *hdl2, uint8 *hdr,
uint16 hdrlen, uint8 *buf,
uint16 buflen);
extern void msgtrace_sent(void);
extern void msgtrace_put(char *buf, int count);
extern void msgtrace_init(void *hdl1, void *hdl2,
msgtrace_func_send_t func_send);
/* This marks the end of a packed structure section. */
#include <packed_section_end.h>
#endif /* _MSGTRACE_H */

View File

@ -1430,7 +1430,7 @@ typedef struct dot11_obss_ie dot11_obss_ie_t;
#define WCN_OUI "\x00\x50\xf2"
#define WCN_TYPE 4
#define BRCM_OUI "\x00\x10\x18"
#include <packed_section_end.h>
#endif /* _802_11_H_ */

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BCMETH_H_
#define _BCMETH_H_
#ifndef _TYPEDEFS_H_
#include <typedefs.h>
#endif
#include <packed_section_start.h>
#define BCMILCP_SUBTYPE_RATE 1
#define BCMILCP_SUBTYPE_LINK 2
#define BCMILCP_SUBTYPE_CSA 3
#define BCMILCP_SUBTYPE_LARQ 4
#define BCMILCP_SUBTYPE_VENDOR 5
#define BCMILCP_SUBTYPE_FLH 17
#define BCMILCP_SUBTYPE_VENDOR_LONG 32769
#define BCMILCP_SUBTYPE_CERT 32770
#define BCMILCP_SUBTYPE_SES 32771
#define BCMILCP_BCM_SUBTYPE_RESERVED 0
#define BCMILCP_BCM_SUBTYPE_EVENT 1
#define BCMILCP_BCM_SUBTYPE_SES 2
#define BCMILCP_BCM_SUBTYPE_DPT 4
#define BCMILCP_BCM_SUBTYPEHDR_MINLENGTH 8
#define BCMILCP_BCM_SUBTYPEHDR_VERSION 0
typedef BWL_PRE_PACKED_STRUCT struct bcmeth_hdr {
uint16 subtype;
uint16 length;
uint8 version;
uint8 oui[3];
uint16 usr_subtype;
} BWL_POST_PACKED_STRUCT bcmeth_hdr_t;
#include <packed_section_end.h>
#endif /* _BCMETH_H_ */

View File

@ -42,6 +42,13 @@ typedef BWL_PRE_PACKED_STRUCT struct {
char ifname[BCM_MSG_IFNAME_MAX];
} BWL_POST_PACKED_STRUCT wl_event_msg_t;
#ifdef BRCM_FULLMAC
typedef BWL_PRE_PACKED_STRUCT struct bcm_event {
struct ether_header eth;
bcmeth_hdr_t bcm_hdr;
wl_event_msg_t event;
} BWL_POST_PACKED_STRUCT bcm_event_t;
#endif
#define BCM_MSG_LEN (sizeof(bcm_event_t) - sizeof(bcmeth_hdr_t) - \
sizeof(struct ether_header))

View File

@ -0,0 +1,136 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _bcmip_h_
#define _bcmip_h_
#ifndef _TYPEDEFS_H_
#include <typedefs.h>
#endif
#include <packed_section_start.h>
#define IP_VER_OFFSET 0x0
#define IP_VER_MASK 0xf0
#define IP_VER_SHIFT 4
#define IP_VER_4 4
#define IP_VER_6 6
#define IP_VER(ip_body) \
((((uint8 *)(ip_body))[IP_VER_OFFSET] & IP_VER_MASK) >> IP_VER_SHIFT)
#define IP_PROT_ICMP 0x1
#define IP_PROT_TCP 0x6
#define IP_PROT_UDP 0x11
#define IPV4_VER_HL_OFFSET 0
#define IPV4_TOS_OFFSET 1
#define IPV4_PKTLEN_OFFSET 2
#define IPV4_PKTFLAG_OFFSET 6
#define IPV4_PROT_OFFSET 9
#define IPV4_CHKSUM_OFFSET 10
#define IPV4_SRC_IP_OFFSET 12
#define IPV4_DEST_IP_OFFSET 16
#define IPV4_OPTIONS_OFFSET 20
#define IPV4_VER_MASK 0xf0
#define IPV4_VER_SHIFT 4
#define IPV4_HLEN_MASK 0x0f
#define IPV4_HLEN(ipv4_body) \
(4 * (((uint8 *)(ipv4_body))[IPV4_VER_HL_OFFSET] & IPV4_HLEN_MASK))
#define IPV4_ADDR_LEN 4
#define IPV4_ADDR_NULL(a) ((((uint8 *)(a))[0] | ((uint8 *)(a))[1] | \
((uint8 *)(a))[2] | ((uint8 *)(a))[3]) == 0)
#define IPV4_ADDR_BCAST(a) ((((uint8 *)(a))[0] & ((uint8 *)(a))[1] & \
((uint8 *)(a))[2] & ((uint8 *)(a))[3]) == 0xff)
#define IPV4_TOS_DSCP_MASK 0xfc
#define IPV4_TOS_DSCP_SHIFT 2
#define IPV4_TOS(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_TOS_OFFSET])
#define IPV4_TOS_PREC_MASK 0xe0
#define IPV4_TOS_PREC_SHIFT 5
#define IPV4_TOS_LOWDELAY 0x10
#define IPV4_TOS_THROUGHPUT 0x8
#define IPV4_TOS_RELIABILITY 0x4
#define IPV4_PROT(ipv4_body) (((uint8 *)(ipv4_body))[IPV4_PROT_OFFSET])
#define IPV4_FRAG_RESV 0x8000
#define IPV4_FRAG_DONT 0x4000
#define IPV4_FRAG_MORE 0x2000
#define IPV4_FRAG_OFFSET_MASK 0x1fff
#define IPV4_ADDR_STR_LEN 16
BWL_PRE_PACKED_STRUCT struct ipv4_addr {
uint8 addr[IPV4_ADDR_LEN];
} BWL_POST_PACKED_STRUCT;
BWL_PRE_PACKED_STRUCT struct ipv4_hdr {
uint8 version_ihl;
uint8 tos;
uint16 tot_len;
uint16 id;
uint16 frag;
uint8 ttl;
uint8 prot;
uint16 hdr_chksum;
uint8 src_ip[IPV4_ADDR_LEN];
uint8 dst_ip[IPV4_ADDR_LEN];
} BWL_POST_PACKED_STRUCT;
#define IPV6_PAYLOAD_LEN_OFFSET 4
#define IPV6_NEXT_HDR_OFFSET 6
#define IPV6_HOP_LIMIT_OFFSET 7
#define IPV6_SRC_IP_OFFSET 8
#define IPV6_DEST_IP_OFFSET 24
#define IPV6_TRAFFIC_CLASS(ipv6_body) \
(((((uint8 *)(ipv6_body))[0] & 0x0f) << 4) | \
((((uint8 *)(ipv6_body))[1] & 0xf0) >> 4))
#define IPV6_FLOW_LABEL(ipv6_body) \
(((((uint8 *)(ipv6_body))[1] & 0x0f) << 16) | \
(((uint8 *)(ipv6_body))[2] << 8) | \
(((uint8 *)(ipv6_body))[3]))
#define IPV6_PAYLOAD_LEN(ipv6_body) \
((((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 0] << 8) | \
((uint8 *)(ipv6_body))[IPV6_PAYLOAD_LEN_OFFSET + 1])
#define IPV6_NEXT_HDR(ipv6_body) \
(((uint8 *)(ipv6_body))[IPV6_NEXT_HDR_OFFSET])
#define IPV6_PROT(ipv6_body) IPV6_NEXT_HDR(ipv6_body)
#define IPV6_ADDR_LEN 16
#ifndef IP_TOS
#define IP_TOS(ip_body) \
(IP_VER(ip_body) == IP_VER_4 ? IPV4_TOS(ip_body) : \
IP_VER(ip_body) == IP_VER_6 ? IPV6_TRAFFIC_CLASS(ip_body) : 0)
#endif
#include <packed_section_end.h>
#endif /* _bcmip_h_ */

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _vlan_h_
#define _vlan_h_
#ifndef _TYPEDEFS_H_
#include <typedefs.h>
#endif
#include <packed_section_start.h>
#define VLAN_VID_MASK 0xfff
#define VLAN_CFI_SHIFT 12
#define VLAN_PRI_SHIFT 13
#define VLAN_PRI_MASK 7
#define VLAN_TAG_LEN 4
#define VLAN_TAG_OFFSET (2 * ETHER_ADDR_LEN)
#define VLAN_TPID 0x8100
struct ethervlan_header {
uint8 ether_dhost[ETHER_ADDR_LEN];
uint8 ether_shost[ETHER_ADDR_LEN];
uint16 vlan_type;
uint16 vlan_tag;
uint16 ether_type;
};
#define ETHERVLAN_HDR_LEN (ETHER_HDR_LEN + VLAN_TAG_LEN)
#include <packed_section_end.h>
#endif /* _vlan_h_ */

View File

@ -19,6 +19,9 @@
#include <typedefs.h>
#include <proto/ethernet.h>
#ifdef BRCM_FULLMAC
#include <proto/bcmeth.h>
#endif
#include <proto/bcmevent.h>
#include <proto/802.11.h>
#include <bcmwifi.h>
@ -102,7 +105,11 @@ typedef struct wl_bss_info_108 {
/* variable length Information Elements */
} wl_bss_info_108_t;
#define WL_BSS_INFO_VERSION 109 /* current version of wl_bss_info struct */
#ifdef BRCM_FULLMAC
#define WL_BSS_INFO_VERSION 108 /* current ver of wl_bss_info struct */
#else
#define WL_BSS_INFO_VERSION 109 /* current ver of wl_bss_info struct */
#endif
/* BSS info structure
* Applications MUST CHECK ie_offset field and length field to access IEs and
@ -264,6 +271,7 @@ typedef struct wl_scan_results {
#define WL_SCAN_RESULTS_PARTIAL 1
#define WL_SCAN_RESULTS_PENDING 2
#define WL_SCAN_RESULTS_ABORTED 3
#define WL_SCAN_RESULTS_NO_MEM 4
#define ESCAN_REQ_VERSION 1
@ -843,7 +851,11 @@ typedef struct wlc_iov_trx_s {
/* bump this number if you change the ioctl interface */
#define WLC_IOCTL_VERSION 1
#ifdef BRCM_FULLMAC
#define WLC_IOCTL_MAXLEN 8192
#else
#define WLC_IOCTL_MAXLEN 3072 /* max length ioctl buffer required */
#endif
#define WLC_IOCTL_SMLEN 256 /* "small" length ioctl buffer required */
#define WLC_IOCTL_MEDLEN 1536 /* "med" length ioctl buffer required */
#define WLC_SAMPLECOLLECT_MAXLEN 10240 /* Max Sample Collect buffer for two cores */
@ -2004,4 +2016,30 @@ typedef struct wl_pkteng {
#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040
#define WLFEATURE_DISABLE_11N_GF 0x00000080
#define WL_EVENTING_MASK_LEN 16
#define TOE_TX_CSUM_OL 0x00000001
#define TOE_RX_CSUM_OL 0x00000002
#define PM_OFF 0
#define PM_MAX 1
#define PM_FAST 2
typedef enum sup_auth_status {
WLC_SUP_DISCONNECTED = 0,
WLC_SUP_CONNECTING,
WLC_SUP_IDREQUIRED,
WLC_SUP_AUTHENTICATING,
WLC_SUP_AUTHENTICATED,
WLC_SUP_KEYXCHANGE,
WLC_SUP_KEYED,
WLC_SUP_TIMEOUT,
WLC_SUP_LAST_BASIC_STATE,
WLC_SUP_KEYXCHANGE_WAIT_M1 = WLC_SUP_AUTHENTICATED,
WLC_SUP_KEYXCHANGE_PREP_M2 = WLC_SUP_KEYXCHANGE,
WLC_SUP_KEYXCHANGE_WAIT_M3 = WLC_SUP_LAST_BASIC_STATE,
WLC_SUP_KEYXCHANGE_PREP_M4,
WLC_SUP_KEYXCHANGE_WAIT_G1,
WLC_SUP_KEYXCHANGE_PREP_G2
} sup_auth_status_t;
#endif /* _wlioctl_h_ */

View File

@ -39,6 +39,96 @@
*/
#define PMU_NONE(args)
#ifdef BRCM_FULLMAC
/* SDIO Pad drive strength to select value mappings */
typedef struct {
uint8 strength; /* Pad Drive Strength in mA */
uint8 sel; /* Chip-specific select value */
} sdiod_drive_str_t;
/* SDIO Drive Strength to sel value table for PMU Rev 1 */
static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = {
{4, 0x2},
{2, 0x3},
{1, 0x0},
{0, 0x0} };
/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = {
{12, 0x7},
{10, 0x6},
{8, 0x5},
{6, 0x4},
{4, 0x2},
{2, 0x1},
{0, 0x0} };
#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
void
si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength)
{
chipcregs_t *cc;
uint origidx, intr_val = 0;
sdiod_drive_str_t *str_tab = NULL;
uint32 str_mask = 0;
uint32 str_shift = 0;
if (!(sih->cccaps & CC_CAP_PMU)) {
return;
}
/* Remember original core before switch to chipc */
cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx,
&intr_val);
switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) {
case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1;
str_mask = 0x30000000;
str_shift = 28;
break;
case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2;
str_mask = 0x00003800;
str_shift = 11;
break;
default:
PMU_MSG(("No SDIO Drive strength init done for chip %x rev %d "
"pmurev %d\n", sih->chip, sih->chiprev, sih->pmurev));
break;
}
if (str_tab != NULL) {
uint32 drivestrength_sel = 0;
uint32 cc_data_temp;
int i;
for (i = 0; str_tab[i].strength != 0; i++) {
if (drivestrength >= str_tab[i].strength) {
drivestrength_sel = str_tab[i].sel;
break;
}
}
W_REG(osh, &cc->chipcontrol_addr, 1);
cc_data_temp = R_REG(osh, &cc->chipcontrol_data);
cc_data_temp &= ~str_mask;
drivestrength_sel <<= str_shift;
cc_data_temp |= drivestrength_sel;
W_REG(osh, &cc->chipcontrol_data, cc_data_temp);
PMU_MSG(("SDIO: %dmA drive strength selected, set to 0x%08x\n",
drivestrength, cc_data_temp));
}
/* Return to original core */
si_restore_core(sih, origidx, intr_val);
}
#else /* BRCM_FULLMAC */
/* PLL controls/clocks */
static void si_pmu1_pllinit0(si_t *sih, osl_t *osh, chipcregs_t *cc,
uint32 xtal);
@ -2682,3 +2772,4 @@ static void BCMATTACHFN(si_pmu_set_4330_plldivs) (si_t *sih)
(m6div << PMU1_PLL0_PC2_M6DIV_SHIFT));
si_pmu_pllcontrol(sih, PMU1_PLL0_PLLCTL2, ~0, pllc2);
}
#endif /* BRCM_FULLMAC */

View File

@ -0,0 +1,584 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <typedefs.h>
#include <bcmdefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <siutils.h>
#include <bcmdevs.h>
#include <hndsoc.h>
#include <sbchipc.h>
#include <pci_core.h>
#include <pcicfg.h>
#include <sbpcmcia.h>
#include "siutils_priv.h"
/* local prototypes */
static uint _sb_coreidx(si_info_t *sii, uint32 sba);
static uint _sb_scan(si_info_t *sii, uint32 sba, void *regs, uint bus,
uint32 sbba, uint ncores);
static uint32 _sb_coresba(si_info_t *sii);
static void *_sb_setcoreidx(si_info_t *sii, uint coreidx);
#define SET_SBREG(sii, r, mask, val) \
W_SBREG((sii), (r), ((R_SBREG((sii), (r)) & ~(mask)) | (val)))
#define REGS2SB(va) (sbconfig_t *) ((int8 *)(va) + SBCONFIGOFF)
/* sonicsrev */
#define SONICS_2_2 (SBIDL_RV_2_2 >> SBIDL_RV_SHIFT)
#define SONICS_2_3 (SBIDL_RV_2_3 >> SBIDL_RV_SHIFT)
#define R_SBREG(sii, sbr) sb_read_sbreg((sii), (sbr))
#define W_SBREG(sii, sbr, v) sb_write_sbreg((sii), (sbr), (v))
#define AND_SBREG(sii, sbr, v) \
W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) & (v)))
#define OR_SBREG(sii, sbr, v) \
W_SBREG((sii), (sbr), (R_SBREG((sii), (sbr)) | (v)))
static uint32 sb_read_sbreg(si_info_t *sii, volatile uint32 *sbr)
{
return R_REG(sii->osh, sbr);
}
static void sb_write_sbreg(si_info_t *sii, volatile uint32 *sbr, uint32 v)
{
W_REG(sii->osh, sbr, v);
}
uint sb_coreid(si_t *sih)
{
si_info_t *sii;
sbconfig_t *sb;
sii = SI_INFO(sih);
sb = REGS2SB(sii->curmap);
return (R_SBREG(sii, &sb->sbidhigh) & SBIDH_CC_MASK) >>
SBIDH_CC_SHIFT;
}
/* return core index of the core with address 'sba' */
static uint BCMATTACHFN(_sb_coreidx) (si_info_t *sii, uint32 sba)
{
uint i;
for (i = 0; i < sii->numcores; i++)
if (sba == sii->coresba[i])
return i;
return BADIDX;
}
/* return core address of the current core */
static uint32 BCMATTACHFN(_sb_coresba) (si_info_t *sii)
{
uint32 sbaddr = 0;
switch (BUSTYPE(sii->pub.bustype)) {
case SPI_BUS:
case SDIO_BUS:
sbaddr = (uint32) (uintptr) sii->curmap;
break;
default:
ASSERT(0);
break;
}
return sbaddr;
}
uint sb_corerev(si_t *sih)
{
si_info_t *sii;
sbconfig_t *sb;
uint sbidh;
sii = SI_INFO(sih);
sb = REGS2SB(sii->curmap);
sbidh = R_SBREG(sii, &sb->sbidhigh);
return SBCOREREV(sbidh);
}
bool sb_iscoreup(si_t *sih)
{
si_info_t *sii;
sbconfig_t *sb;
sii = SI_INFO(sih);
sb = REGS2SB(sii->curmap);
return (R_SBREG(sii, &sb->sbtmstatelow) &
(SBTML_RESET | SBTML_REJ_MASK |
(SICF_CLOCK_EN << SBTML_SICF_SHIFT))) ==
(SICF_CLOCK_EN << SBTML_SICF_SHIFT);
}
/*
* Switch to 'coreidx', issue a single arbitrary 32bit
* register mask&set operation,
* switch back to the original core, and return the new value.
*
* When using the silicon backplane, no fidleing with interrupts
* or core switches are needed.
*
* Also, when using pci/pcie, we can optimize away the core switching
* for pci registers
* and (on newer pci cores) chipcommon registers.
*/
uint sb_corereg(si_t *sih, uint coreidx, uint regoff, uint mask, uint val)
{
uint origidx = 0;
uint32 *r = NULL;
uint w;
uint intr_val = 0;
bool fast = FALSE;
si_info_t *sii;
sii = SI_INFO(sih);
ASSERT(GOODIDX(coreidx));
ASSERT(regoff < SI_CORE_SIZE);
ASSERT((val & ~mask) == 0);
if (coreidx >= SI_MAXCORES)
return 0;
if (!fast) {
INTR_OFF(sii, intr_val);
/* save current core index */
origidx = si_coreidx(&sii->pub);
/* switch core */
r = (uint32 *) ((uchar *) sb_setcoreidx(&sii->pub, coreidx) +
regoff);
}
ASSERT(r != NULL);
/* mask and set */
if (mask || val) {
if (regoff >= SBCONFIGOFF) {
w = (R_SBREG(sii, r) & ~mask) | val;
W_SBREG(sii, r, w);
} else {
w = (R_REG(sii->osh, r) & ~mask) | val;
W_REG(sii->osh, r, w);
}
}
/* readback */
if (regoff >= SBCONFIGOFF)
w = R_SBREG(sii, r);
else
w = R_REG(sii->osh, r);
if (!fast) {
/* restore core index */
if (origidx != coreidx)
sb_setcoreidx(&sii->pub, origidx);
INTR_RESTORE(sii, intr_val);
}
return w;
}
/* Scan the enumeration space to find all cores starting from the given
* bus 'sbba'. Append coreid and other info to the lists in 'si'. 'sba'
* is the default core address at chip POR time and 'regs' is the virtual
* address that the default core is mapped at. 'ncores' is the number of
* cores expected on bus 'sbba'. It returns the total number of cores
* starting from bus 'sbba', inclusive.
*/
#define SB_MAXBUSES 2
static uint
BCMATTACHFN(_sb_scan) (si_info_t *sii, uint32 sba, void *regs, uint bus,
uint32 sbba, uint numcores) {
uint next;
uint ncc = 0;
uint i;
if (bus >= SB_MAXBUSES) {
SI_ERROR(("_sb_scan: bus 0x%08x at level %d is too deep to "
"scan\n", sbba, bus));
return 0;
}
SI_MSG(("_sb_scan: scan bus 0x%08x assume %u cores\n",
sbba, numcores));
/* Scan all cores on the bus starting from core 0.
* Core addresses must be contiguous on each bus.
*/
for (i = 0, next = sii->numcores;
i < numcores && next < SB_BUS_MAXCORES; i++, next++) {
sii->coresba[next] = sbba + (i * SI_CORE_SIZE);
/* change core to 'next' and read its coreid */
sii->curmap = _sb_setcoreidx(sii, next);
sii->curidx = next;
sii->coreid[next] = sb_coreid(&sii->pub);
/* core specific processing... */
/* chipc provides # cores */
if (sii->coreid[next] == CC_CORE_ID) {
chipcregs_t *cc = (chipcregs_t *) sii->curmap;
uint32 ccrev = sb_corerev(&sii->pub);
/* determine numcores - this is the
total # cores in the chip */
if (((ccrev == 4) || (ccrev >= 6)))
numcores =
(R_REG(sii->osh, &cc->chipid) & CID_CC_MASK)
>> CID_CC_SHIFT;
else {
/* Older chips */
SI_ERROR(("sb_chip2numcores: unsupported chip "
"0x%x\n", CHIPID(sii->pub.chip)));
ASSERT(0);
numcores = 1;
}
SI_VMSG(("_sb_scan: %u cores in the chip %s\n",
numcores, sii->pub.issim ? "QT" : ""));
}
/* scan bridged SB(s) and add results to the end of the list */
else if (sii->coreid[next] == OCP_CORE_ID) {
sbconfig_t *sb = REGS2SB(sii->curmap);
uint32 nsbba = R_SBREG(sii, &sb->sbadmatch1);
uint nsbcc;
sii->numcores = next + 1;
if ((nsbba & 0xfff00000) != SI_ENUM_BASE)
continue;
nsbba &= 0xfffff000;
if (_sb_coreidx(sii, nsbba) != BADIDX)
continue;
nsbcc =
(R_SBREG(sii, &sb->sbtmstatehigh) & 0x000f0000) >>
16;
nsbcc = _sb_scan(sii, sba, regs, bus + 1, nsbba, nsbcc);
if (sbba == SI_ENUM_BASE)
numcores -= nsbcc;
ncc += nsbcc;
}
}
SI_MSG(("_sb_scan: found %u cores on bus 0x%08x\n", i, sbba));
sii->numcores = i + ncc;
return sii->numcores;
}
/* scan the sb enumerated space to identify all cores */
void BCMATTACHFN(sb_scan) (si_t *sih, void *regs, uint devid)
{
si_info_t *sii;
uint32 origsba;
sbconfig_t *sb;
sii = SI_INFO(sih);
sb = REGS2SB(sii->curmap);
sii->pub.socirev =
(R_SBREG(sii, &sb->sbidlow) & SBIDL_RV_MASK) >> SBIDL_RV_SHIFT;
/* Save the current core info and validate it later till we know
* for sure what is good and what is bad.
*/
origsba = _sb_coresba(sii);
/* scan all SB(s) starting from SI_ENUM_BASE */
sii->numcores = _sb_scan(sii, origsba, regs, 0, SI_ENUM_BASE, 1);
}
/*
* This function changes logical "focus" to the indicated core;
* must be called with interrupts off.
* Moreover, callers should keep interrupts off during switching out of
* and back to d11 core
*/
void *sb_setcoreidx(si_t *sih, uint coreidx)
{
si_info_t *sii;
sii = SI_INFO(sih);
if (coreidx >= sii->numcores)
return NULL;
/*
* If the user has provided an interrupt mask enabled function,
* then assert interrupts are disabled before switching the core.
*/
ASSERT((sii->intrsenabled_fn == NULL)
|| !(*(sii)->intrsenabled_fn) ((sii)->intr_arg));
sii->curmap = _sb_setcoreidx(sii, coreidx);
sii->curidx = coreidx;
return sii->curmap;
}
/* This function changes the logical "focus" to the indicated core.
* Return the current core's virtual address.
*/
static void *_sb_setcoreidx(si_info_t *sii, uint coreidx)
{
uint32 sbaddr = sii->coresba[coreidx];
void *regs;
switch (BUSTYPE(sii->pub.bustype)) {
#ifdef BCMSDIO
case SPI_BUS:
case SDIO_BUS:
/* map new one */
if (!sii->regs[coreidx]) {
sii->regs[coreidx] = (void *)(uintptr) sbaddr;
ASSERT(GOODREGS(sii->regs[coreidx]));
}
regs = sii->regs[coreidx];
break;
#endif /* BCMSDIO */
default:
ASSERT(0);
regs = NULL;
break;
}
return regs;
}
/* traverse all cores to find and clear source of serror */
static void sb_serr_clear(si_info_t *sii)
{
sbconfig_t *sb;
uint origidx;
uint i, intr_val = 0;
void *corereg = NULL;
INTR_OFF(sii, intr_val);
origidx = si_coreidx(&sii->pub);
for (i = 0; i < sii->numcores; i++) {
corereg = sb_setcoreidx(&sii->pub, i);
if (NULL != corereg) {
sb = REGS2SB(corereg);
if ((R_SBREG(sii, &sb->sbtmstatehigh)) & SBTMH_SERR) {
AND_SBREG(sii, &sb->sbtmstatehigh, ~SBTMH_SERR);
SI_ERROR(("sb_serr_clear: SError core 0x%x\n",
sb_coreid(&sii->pub)));
}
}
}
sb_setcoreidx(&sii->pub, origidx);
INTR_RESTORE(sii, intr_val);
}
/*
* Check if any inband, outband or timeout errors has happened and clear them.
* Must be called with chip clk on !
*/
bool sb_taclear(si_t *sih, bool details)
{
si_info_t *sii;
sbconfig_t *sb;
uint origidx;
uint intr_val = 0;
bool rc = FALSE;
uint32 inband = 0, serror = 0, timeout = 0;
void *corereg = NULL;
volatile uint32 imstate, tmstate;
sii = SI_INFO(sih);
if ((BUSTYPE(sii->pub.bustype) == SDIO_BUS) ||
(BUSTYPE(sii->pub.bustype) == SPI_BUS)) {
INTR_OFF(sii, intr_val);
origidx = si_coreidx(sih);
corereg = si_setcore(sih, PCMCIA_CORE_ID, 0);
if (NULL == corereg)
corereg = si_setcore(sih, SDIOD_CORE_ID, 0);
if (NULL != corereg) {
sb = REGS2SB(corereg);
imstate = R_SBREG(sii, &sb->sbimstate);
if ((imstate != 0xffffffff)
&& (imstate & (SBIM_IBE | SBIM_TO))) {
AND_SBREG(sii, &sb->sbimstate,
~(SBIM_IBE | SBIM_TO));
/* inband = imstate & SBIM_IBE; cmd error */
timeout = imstate & SBIM_TO;
}
tmstate = R_SBREG(sii, &sb->sbtmstatehigh);
if ((tmstate != 0xffffffff)
&& (tmstate & SBTMH_INT_STATUS)) {
sb_serr_clear(sii);
serror = 1;
OR_SBREG(sii, &sb->sbtmstatelow, SBTML_INT_ACK);
AND_SBREG(sii, &sb->sbtmstatelow,
~SBTML_INT_ACK);
}
}
sb_setcoreidx(sih, origidx);
INTR_RESTORE(sii, intr_val);
}
if (inband | timeout | serror) {
rc = TRUE;
SI_ERROR(("sb_taclear: inband 0x%x, serror 0x%x, timeout "
"0x%x!\n", inband, serror, timeout));
}
return rc;
}
void sb_core_disable(si_t *sih, uint32 bits)
{
si_info_t *sii;
volatile uint32 dummy;
sbconfig_t *sb;
sii = SI_INFO(sih);
ASSERT(GOODREGS(sii->curmap));
sb = REGS2SB(sii->curmap);
/* if core is already in reset, just return */
if (R_SBREG(sii, &sb->sbtmstatelow) & SBTML_RESET)
return;
/* if clocks are not enabled, put into reset and return */
if ((R_SBREG(sii, &sb->sbtmstatelow) &
(SICF_CLOCK_EN << SBTML_SICF_SHIFT)) == 0)
goto disable;
/* set target reject and spin until busy is clear
(preserve core-specific bits) */
OR_SBREG(sii, &sb->sbtmstatelow, SBTML_REJ);
dummy = R_SBREG(sii, &sb->sbtmstatelow);
OSL_DELAY(1);
SPINWAIT((R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY), 100000);
if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_BUSY)
SI_ERROR(("%s: target state still busy\n", __func__));
if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT) {
OR_SBREG(sii, &sb->sbimstate, SBIM_RJ);
dummy = R_SBREG(sii, &sb->sbimstate);
OSL_DELAY(1);
SPINWAIT((R_SBREG(sii, &sb->sbimstate) & SBIM_BY), 100000);
}
/* set reset and reject while enabling the clocks */
W_SBREG(sii, &sb->sbtmstatelow,
(((bits | SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
SBTML_REJ | SBTML_RESET));
dummy = R_SBREG(sii, &sb->sbtmstatelow);
OSL_DELAY(10);
/* don't forget to clear the initiator reject bit */
if (R_SBREG(sii, &sb->sbidlow) & SBIDL_INIT)
AND_SBREG(sii, &sb->sbimstate, ~SBIM_RJ);
disable:
/* leave reset and reject asserted */
W_SBREG(sii, &sb->sbtmstatelow,
((bits << SBTML_SICF_SHIFT) | SBTML_REJ | SBTML_RESET));
OSL_DELAY(1);
}
/* reset and re-enable a core
* inputs:
* bits - core specific bits that are set during and after reset sequence
* resetbits - core specific bits that are set only during reset sequence
*/
void sb_core_reset(si_t *sih, uint32 bits, uint32 resetbits)
{
si_info_t *sii;
sbconfig_t *sb;
volatile uint32 dummy;
sii = SI_INFO(sih);
ASSERT(GOODREGS(sii->curmap));
sb = REGS2SB(sii->curmap);
/*
* Must do the disable sequence first to work for
* arbitrary current core state.
*/
sb_core_disable(sih, (bits | resetbits));
/*
* Now do the initialization sequence.
*/
/* set reset while enabling the clock and
forcing them on throughout the core */
W_SBREG(sii, &sb->sbtmstatelow,
(((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) <<
SBTML_SICF_SHIFT) | SBTML_RESET));
dummy = R_SBREG(sii, &sb->sbtmstatelow);
OSL_DELAY(1);
if (R_SBREG(sii, &sb->sbtmstatehigh) & SBTMH_SERR)
W_SBREG(sii, &sb->sbtmstatehigh, 0);
if ((dummy = R_SBREG(sii, &sb->sbimstate)) & (SBIM_IBE | SBIM_TO))
AND_SBREG(sii, &sb->sbimstate, ~(SBIM_IBE | SBIM_TO));
/* clear reset and allow it to propagate throughout the core */
W_SBREG(sii, &sb->sbtmstatelow,
((bits | resetbits | SICF_FGC | SICF_CLOCK_EN) <<
SBTML_SICF_SHIFT));
dummy = R_SBREG(sii, &sb->sbtmstatelow);
OSL_DELAY(1);
/* leave clock enabled */
W_SBREG(sii, &sb->sbtmstatelow,
((bits | SICF_CLOCK_EN) << SBTML_SICF_SHIFT));
dummy = R_SBREG(sii, &sb->sbtmstatelow);
OSL_DELAY(1);
}
uint32 sb_base(uint32 admatch)
{
uint32 base;
uint type;
type = admatch & SBAM_TYPE_MASK;
ASSERT(type < 3);
base = 0;
if (type == 0) {
base = admatch & SBAM_BASE0_MASK;
} else if (type == 1) {
ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
base = admatch & SBAM_BASE1_MASK;
} else if (type == 2) {
ASSERT(!(admatch & SBAM_ADNEG)); /* neg not supported */
base = admatch & SBAM_BASE2_MASK;
}
return base;
}

View File

@ -59,12 +59,16 @@ static bool si_buscore_prep(si_info_t *sii, uint bustype, uint devid,
void *sdh);
static bool si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype,
uint32 savewin, uint *origidx, void *regs);
#ifndef BRCM_FULLMAC
static void si_nvram_process(si_info_t *sii, char *pvars);
#endif
/* dev path concatenation util */
#ifndef BRCM_FULLMAC
static char *si_devpathvar(si_t *sih, char *var, int len, const char *name);
static bool _si_clkctl_cc(si_info_t *sii, uint mode);
static bool si_ispcie(si_info_t *sii);
#endif
static uint BCMINITFN(socram_banksize) (si_info_t *sii, sbsocramregs_t *r,
uint8 idx, uint8 mtype);
@ -115,9 +119,11 @@ static bool
BCMATTACHFN(si_buscore_prep) (si_info_t *sii, uint bustype, uint devid,
void *sdh) {
#ifndef BRCM_FULLMAC
/* kludge to enable the clock on the 4306 which lacks a slowclock */
if (BUSTYPE(bustype) == PCI_BUS && !si_ispcie(sii))
si_clkctl_xtal(&sii->pub, XTAL | PLL, ON);
#endif
#if defined(BCMSDIO)
if (BUSTYPE(bustype) == SDIO_BUS) {
@ -186,9 +192,10 @@ BCMATTACHFN(si_buscore_setup) (si_info_t *sii, chipcregs_t *cc, uint bustype,
sii->pub.cccaps = R_REG(sii->osh, &cc->capabilities);
/* get chipcommon extended capabilities */
#ifndef BRCM_FULLMAC
if (sii->pub.ccrev >= 35)
sii->pub.cccaps_ext = R_REG(sii->osh, &cc->capabilities_ext);
#endif
/* get pmu rev and caps */
if (sii->pub.cccaps & CC_CAP_PMU) {
sii->pub.pmucaps = R_REG(sii->osh, &cc->pmucapabilities);
@ -248,6 +255,20 @@ BCMATTACHFN(si_buscore_setup) (si_info_t *sii, chipcregs_t *cc, uint bustype,
*origidx = i;
}
#ifdef BRCM_FULLMAC
SI_MSG(("Buscore id/type/rev %d/0x%x/%d\n", sii->pub.buscoreidx,
sii->pub.buscoretype, sii->pub.buscorerev));
/* Make sure any on-chip ARM is off (in case strapping is wrong),
* or downloaded code was
* already running.
*/
if ((BUSTYPE(bustype) == SDIO_BUS) || (BUSTYPE(bustype) == SPI_BUS)) {
if (si_setcore(&sii->pub, ARM7S_CORE_ID, 0) ||
si_setcore(&sii->pub, ARMCM3_CORE_ID, 0))
si_core_disable(&sii->pub, 0);
}
#else
if (pci && pcie) {
if (si_ispcie(sii))
pci = FALSE;
@ -283,13 +304,14 @@ BCMATTACHFN(si_buscore_setup) (si_info_t *sii, chipcregs_t *cc, uint bustype,
return FALSE;
}
}
#endif
/* return to the original core */
si_setcoreidx(&sii->pub, *origidx);
return TRUE;
}
#ifndef BRCM_FULLMAC
static void BCMATTACHFN(si_nvram_process) (si_info_t *sii, char *pvars)
{
uint w = 0;
@ -347,6 +369,7 @@ static void BCMATTACHFN(si_nvram_process) (si_info_t *sii, char *pvars)
sii->pub.boardflags = getintvar(pvars, "boardflags");
}
#endif /* !BRCM_FULLMAC */
/* this is will make Sonics calls directly, since Sonics is no longer supported in the Si abstraction */
/* this has been customized for the bcm 4329 ONLY */
@ -401,10 +424,10 @@ static si_info_t *BCMATTACHFN(si_doattach) (si_info_t *sii, uint devid,
sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) &&
(sih->chippkg != BCM4329_289PIN_PKG_ID)) {
sih->chippkg = BCM4329_182PIN_PKG_ID;
}
if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) &&
(sih->chippkg != BCM4329_289PIN_PKG_ID))
sih->chippkg = BCM4329_182PIN_PKG_ID;
sih->issim = IS_SIM(sih->chippkg);
/* scan for cores */
@ -423,6 +446,9 @@ static si_info_t *BCMATTACHFN(si_doattach) (si_info_t *sii, uint devid,
goto exit;
}
#ifdef BRCM_FULLMAC
pvars = NULL;
#else
/* Init nvram from flash if it exists */
nvram_init((void *)&(sii->pub));
@ -434,14 +460,22 @@ static si_info_t *BCMATTACHFN(si_doattach) (si_info_t *sii, uint devid,
}
pvars = vars ? *vars : NULL;
si_nvram_process(sii, pvars);
#endif
/* === NVRAM, clock is ready === */
#ifdef BRCM_FULLMAC
if (sii->pub.ccrev >= 20) {
#endif
cc = (chipcregs_t *) si_setcore(sih, CC_CORE_ID, 0);
W_REG(osh, &cc->gpiopullup, 0);
W_REG(osh, &cc->gpiopulldown, 0);
sb_setcoreidx(sih, origidx);
#ifdef BRCM_FULLMAC
}
#endif
#ifndef BRCM_FULLMAC
/* PMU specific initializations */
if (PMUCTL_ENAB(sih)) {
uint32 xtalfreq;
@ -466,6 +500,7 @@ static si_info_t *BCMATTACHFN(si_doattach) (si_info_t *sii, uint devid,
/* clear any previous epidiag-induced target abort */
sb_taclear(sih, FALSE);
#endif /* BCMDBG */
#endif
return sii;
@ -690,6 +725,7 @@ void BCMATTACHFN(si_detach) (si_t *sih)
sii->regs[idx] = NULL;
}
#ifndef BRCM_FULLMAC
nvram_exit((void *)si_local); /* free up nvram buffers */
if (BUSTYPE(sih->bustype) == PCI_BUS) {
@ -697,6 +733,7 @@ void BCMATTACHFN(si_detach) (si_t *sih)
pcicore_deinit(sii->pch);
sii->pch = NULL;
}
#endif
#if !defined(BCMBUSTYPE) || (BCMBUSTYPE == SI_BUS)
if (sii != &ksii)
#endif /* !BCMBUSTYPE || (BCMBUSTYPE == SI_BUS) */
@ -1219,6 +1256,7 @@ uint32 BCMINITFN(si_clock_rate) (uint32 pll_type, uint32 n, uint32 m)
}
}
#ifndef BRCM_FULLMAC
uint32 BCMINITFN(si_clock) (si_t *sih)
{
si_info_t *sii;
@ -1277,8 +1315,35 @@ uint32 BCMINITFN(si_ilp_clock) (si_t *sih)
return ILP_CLOCK;
}
#endif
/* set chip watchdog reset timer to fire in 'ticks' */
#ifdef BRCM_FULLMAC
void
si_watchdog(si_t *sih, uint ticks)
{
if (PMUCTL_ENAB(sih)) {
if ((sih->chip == BCM4319_CHIP_ID) && (sih->chiprev == 0) &&
(ticks != 0)) {
si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t,
clk_ctl_st), ~0, 0x2);
si_setcore(sih, USB20D_CORE_ID, 0);
si_core_disable(sih, 1);
si_setcore(sih, CC_CORE_ID, 0);
}
if (ticks == 1)
ticks = 2;
si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, pmuwatchdog),
~0, ticks);
} else {
/* instant NMI */
si_corereg(sih, SI_CC_IDX, OFFSETOF(chipcregs_t, watchdog),
~0, ticks);
}
}
#else
void si_watchdog(si_t *sih, uint ticks)
{
uint nb, maxt;
@ -1321,6 +1386,7 @@ void si_watchdog(si_t *sih, uint ticks)
ticks);
}
}
#endif
/* trigger watchdog reset after ms milliseconds */
void si_watchdog_ms(si_t *sih, uint32 ms)
@ -1328,6 +1394,7 @@ void si_watchdog_ms(si_t *sih, uint32 ms)
si_watchdog(sih, wd_msticks * ms);
}
#ifndef BRCM_FULLMAC
uint16 BCMATTACHFN(si_d11_devid) (si_t *sih)
{
si_info_t *sii = SI_INFO(sih);
@ -1897,6 +1964,7 @@ void si_pci_pmeclr(si_t *sih)
pcicore_pmeclr(sii->pch);
}
#endif /* !BRCM_FULLMAC */
#ifdef BCMSDIO
/* initialize the sdio core */
@ -1937,6 +2005,7 @@ void si_sdio_init(si_t *sih)
}
#endif /* BCMSDIO */
#ifndef BRCM_FULLMAC
bool BCMATTACHFN(si_pci_war16165) (si_t *sih)
{
si_info_t *sii;
@ -2160,6 +2229,7 @@ int si_pci_fixcfg(si_t *sih)
pcicore_hwup(sii->pch);
return 0;
}
#endif /* !BRCM_FULLMAC */
/* change logical "focus" to the gpio core for optimized access */
void *si_gpiosetcore(si_t *sih)
@ -2800,6 +2870,7 @@ bool si_deviceremoved(si_t *sih)
return FALSE;
}
#ifndef BRCM_FULLMAC
bool si_is_sprom_available(si_t *sih)
{
if (sih->ccrev >= 31) {
@ -2959,3 +3030,4 @@ int si_cis_source(si_t *sih)
return CIS_DEFAULT;
}
}
#endif /* BRCM_FULLMAC */