photon: cleanup and refactor bcmf driver

This commit is contained in:
Simon Piriou 2017-04-23 22:17:43 +02:00
parent 6601912f12
commit c0862c862f
18 changed files with 1070 additions and 755 deletions

View File

@ -45,7 +45,7 @@
* Character array of NVRAM image
*/
const char __attribute__((section(".wlan_nvram_image"))) bcmf_nvram_image[] =
const char __attribute__((section(".wlan_nvram_image"))) bcm43362_nvram_image[] =
"manfid=0x2d0" "\x00"
"prodid=0x492" "\x00"
"vendid=0x14e4" "\x00"
@ -106,10 +106,10 @@ const char __attribute__((section(".wlan_nvram_image"))) bcmf_nvram_image[] =
"edoffthd=-76" "\x00"
"\x00\x00";
const unsigned int bcmf_nvram_image_len = sizeof(bcmf_nvram_image);
const unsigned int bcm43362_nvram_image_len = sizeof(bcm43362_nvram_image);
const uint8_t
__attribute__((section(".wlan_firmware_image"))) bcmf_firmware_image[] = {
__attribute__((section(".wlan_firmware_image"))) bcm43362_firmware_image[] = {
0x00, 0x00, 0x00, 0x00, 0xcd, 0xc2, 0x00, 0x00, 0x91, 0xc1, 0x00, 0x00,
0x91, 0xc1, 0x00, 0x00, 0x91, 0xc1, 0x00, 0x00, 0x91, 0xc1, 0x00, 0x00,
0x91, 0xc1, 0x00, 0x00, 0x91, 0xc1, 0x00, 0x00, 0x91, 0xc1, 0x00, 0x00,
@ -17647,4 +17647,4 @@ __attribute__((section(".wlan_firmware_image"))) bcmf_firmware_image[] = {
0xd2, 0x58, 0x82, 0x92
};
const unsigned int bcmf_firmware_image_len = sizeof(bcmf_firmware_image);
const unsigned int bcm43362_firmware_image_len = sizeof(bcm43362_firmware_image);

View File

@ -40,19 +40,24 @@ ifeq ($(CONFIG_DRIVERS_IEEE80211),y)
# Include IEEE 802.11 drivers into the build
ifeq ($(CONFIG_IEEE80211_BROADCOM_FULLMAC_SDIO),y)
ifeq ($(CONFIG_IEEE80211_BROADCOM_FULLMAC),y)
CSRCS += bcmf_driver.c
CSRCS += bcmf_cdc.c
CSRCS += bcmf_utils.c
ifeq ($(CONFIG_IEEE80211_BROADCOM_FULLMAC_SDIO),y)
CSRCS += mmc_sdio.c
CSRCS += bcmf_sdio.c
CSRCS += bcmf_core.c
CSRCS += bcmf_sdpcm.c
CSRCS += bcmf_hexdump.c
CSRCS += mmc_sdio.c
endif
ifeq ($(CONFIG_IEEE80211_BROADCOM_BCM43362),y)
CSRCS += bcmf_chip_43362.c
endif
endif # CONFIG_IEEE80211_BROADCOM_FULLMAC
# Include IEEE 802.11 build support
DEPPATH += --dep-path wireless$(DELIM)ieee80211

View File

@ -1,76 +0,0 @@
/*
* Copyright (c) 2015 Broadcom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* 3. Neither the name of Broadcom nor the names of other contributors to this
* software may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* 4. This software may not be used as a standalone product, and may only be used as
* incorporated in your product or device that incorporates Broadcom wireless connectivity
* products and solely for the purpose of enabling the functionalities of such Broadcom products.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT, ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BCM43362_CONSTANTS_H_
#define BCM43362_CONSTANTS_H_
/******************************************************
* Architecture Constants
******************************************************/
/* General chip stats */
#define CHIP_RAM_SIZE 0x3C000
/* Backplane architecture */
#define CHIPCOMMON_BASE_ADDRESS 0x18000000 /* Chipcommon core register region */
#define DOT11MAC_BASE_ADDRESS 0x18001000 /* dot11mac core register region */
#define SDIO_BASE_ADDRESS 0x18002000 /* SDIOD Device core register region */
#define WLAN_ARMCM3_BASE_ADDRESS 0x18003000 /* ARMCM3 core register region */
#define SOCSRAM_BASE_ADDRESS 0x18004000 /* SOCSRAM core register region */
#define BACKPLANE_ADDRESS_MASK 0x7FFF
/* Maximum value of bus data credit difference */
#define CHIP_MAX_BUS_DATA_CREDIT_DIFF 7
/* Chipcommon registers */
#define CHIPCOMMON_GPIO_CONTROL ((uint32_t) (CHIPCOMMON_BASE_ADDRESS + 0x6C) )
/******************************************************
* Bit Masks
******************************************************/
#define WL_CHANSPEC_BAND_MASK (0xf000)
#define WL_CHANSPEC_BAND_5G (0x1000)
#define WL_CHANSPEC_BAND_2G (0x2000)
#define WL_CHANSPEC_CTL_SB_MASK (0x0300)
#define WL_CHANSPEC_CTL_SB_LOWER (0x0100)
#define WL_CHANSPEC_CTL_SB_UPPER (0x0200)
#define WL_CHANSPEC_CTL_SB_NONE (0x0300)
#define WL_CHANSPEC_BW_MASK (0x0C00)
#define WL_CHANSPEC_BW_10 (0x0400)
#define WL_CHANSPEC_BW_20 (0x0800)
#define WL_CHANSPEC_BW_40 (0x0C00)
#endif /* ifndef BCM43362_CONSTANTS_H_ */

View File

@ -0,0 +1,333 @@
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_cdc.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Simon Piriou <spiriou31@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/compiler.h>
#include <debug.h>
#include <errno.h>
#include <nuttx/arch.h>
#include <stddef.h>
#include <string.h>
#include <semaphore.h>
#include "bcmf_driver.h"
#include "bcmf_ioctl.h"
#include "bcmf_utils.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* CDC flag definitions */
#define CDC_DCMD_ERROR 0x01 /* 1=cmd failed */
#define CDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */
#define CDC_DCMD_IF_MASK 0xF000 /* I/F index */
#define CDC_DCMD_IF_SHIFT 12
#define CDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */
#define CDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */
#define CDC_DCMD_ID(flags) \
(((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT)
#define CDC_CONTROL_TIMEOUT_MS 1000
/****************************************************************************
* Private Types
****************************************************************************/
struct bcmf_cdc_header {
uint32_t cmd; /* dongle command value */
uint32_t len; /* lower 16: output buflen;
* upper 16: input buflen (excludes header) */
uint32_t flags; /* flag defns given below */
uint32_t status; /* status code returned from the device */
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static struct bcmf_frame_s* bcmf_cdc_allocate_frame(
FAR struct bcmf_dev_s *priv, char *name,
uint8_t *data, uint32_t len);
static int bcmf_cdc_sendframe(FAR struct bcmf_dev_s *priv, uint32_t cmd,
int ifidx, bool set, struct bcmf_frame_s *frame);
static int bcmf_cdc_control_request(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, uint32_t cmd,
char *name, uint8_t *data, uint32_t *len);
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
struct bcmf_frame_s* bcmf_cdc_allocate_frame(FAR struct bcmf_dev_s *priv,
char *name, uint8_t *data, uint32_t len)
{
uint32_t data_len;
uint16_t name_len;
struct bcmf_frame_s *frame;
if (name)
{
name_len = strlen(name) + 1;
}
else
{
name_len = 0;
}
if (data)
{
data_len = len;
}
else
{
data_len = 0;
}
if (data_len + name_len + sizeof(struct bcmf_cdc_header) < data_len)
{
/* Integer overflow */
return NULL;
}
/* Allocate control frame */
frame = priv->bus->allocate_frame(priv,
sizeof(struct bcmf_cdc_header) + data_len + name_len,
true, true);
if (!frame)
{
return NULL;
}
/* Copy name string and data */
memcpy(frame->data + sizeof(struct bcmf_cdc_header), name, name_len);
memcpy(frame->data + sizeof(struct bcmf_cdc_header)
+ name_len, data, data_len);
return frame;
}
int bcmf_cdc_sendframe(FAR struct bcmf_dev_s *priv, uint32_t cmd,
int ifidx, bool set, struct bcmf_frame_s *frame)
{
struct bcmf_cdc_header* header =
(struct bcmf_cdc_header*)frame->data;
/* Setup cdc_dcmd header */
uint32_t cdc_data_len = frame->len - (uint32_t)(frame->data-frame->base);
header->cmd = cmd;
header->len = cdc_data_len-sizeof(struct bcmf_cdc_header);
header->status = 0;
header->flags = ++priv->control_reqid << CDC_DCMD_ID_SHIFT;
header->flags |= ifidx << CDC_DCMD_IF_SHIFT;
if (set)
{
header->flags |= CDC_DCMD_SET;
}
/* Queue frame */
return priv->bus->txframe(priv, frame);
}
int bcmf_cdc_control_request(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, uint32_t cmd,
char *name, uint8_t *data, uint32_t *len)
{
int ret;
struct bcmf_frame_s *frame;
uint32_t out_len = *len;
*len = 0;
/* Take device control mutex */
if ((ret = sem_wait(&priv->control_mutex)) != OK)
{
return ret;
}
/* Prepare control frame */
frame = bcmf_cdc_allocate_frame(priv, name, data, out_len);
if (!frame)
{
_err("Cannot allocate cdc frame\n");
ret = -ENOMEM;
goto exit_sem_post;
}
/* Setup buffer to store response */
priv->control_rxdata = set ? NULL : data;
priv->control_rxdata_len = out_len;
/* Send control frame. iovar buffer is freed when sent */
ret = bcmf_cdc_sendframe(priv, cmd, ifidx, set, frame);
if (ret != OK)
{
// TODO free allocated iovar buffer here
goto exit_sem_post;
}
ret = bcmf_sem_wait(&priv->control_timeout, CDC_CONTROL_TIMEOUT_MS);
if (ret != OK)
{
_err("Error while waiting for control response %d\n", ret);
goto exit_sem_post;
}
*len = priv->control_rxdata_len;
/* Check frame status */
if (priv->control_status != 0)
{
_err("Invalid cdc status 0x%x\n", priv->control_status);
ret = -EINVAL;
}
exit_sem_post:
sem_post(&priv->control_mutex);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
int bcmf_cdc_iovar_request(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, char *name,
uint8_t *data, uint32_t *len)
{
return bcmf_cdc_control_request(priv, ifidx, set,
set ? WLC_SET_VAR : WLC_GET_VAR, name,
data, len);
}
int bcmf_cdc_ioctl(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, uint32_t cmd,
uint8_t *data, uint32_t *len)
{
return bcmf_cdc_control_request(priv, ifidx, set, cmd, NULL, data, len);
}
int bcmf_cdc_process_control_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame)
{
unsigned int data_size;
struct bcmf_cdc_header *cdc_header;
/* Check frame */
data_size = frame->len - (unsigned int)(frame->data - frame->base);
if (data_size < sizeof(struct bcmf_cdc_header))
{
_err("Control frame too small\n");
return -EINVAL;
}
cdc_header = (struct bcmf_cdc_header*)frame->data;
if (data_size < cdc_header->len ||
data_size < sizeof(struct bcmf_cdc_header) + cdc_header->len)
{
_err("Invalid control frame size\n");
return -EINVAL;
}
// TODO check interface ?
if (cdc_header->flags >> CDC_DCMD_ID_SHIFT == priv->control_reqid)
{
/* Expected frame received, send it back to user */
priv->control_status = cdc_header->status;
if (priv->control_rxdata)
{
if (priv->control_rxdata_len > cdc_header->len)
{
_err("Not enough data %d %d\n",
priv->control_rxdata_len, cdc_header->len);
priv->control_rxdata_len = cdc_header->len;
}
memcpy(priv->control_rxdata, (uint8_t*)&cdc_header[1],
priv->control_rxdata_len);
}
sem_post(&priv->control_timeout);
return OK;
}
_info("Got unexpected control frame\n");
return -EINVAL;
}
int bcmf_cdc_process_event_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame)
{
_info("Event message\n");
bcmf_hexdump(frame->base, frame->len, (unsigned long)frame->base);
return OK;
}
int bcmf_cdc_process_data_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame)
{
_info("Data message\n");
bcmf_hexdump(frame->base, frame->len, (unsigned long)frame->base);
return OK;
}

View File

@ -0,0 +1,23 @@
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_CDC_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_CDC_H
#include "bcmf_driver.h"
#include <stdbool.h>
#include <stdint.h>
int bcmf_cdc_iovar_request(FAR struct bcmf_dev_s *priv, uint32_t ifidx,
bool set, char *name, uint8_t *data, uint32_t *len);
int bcmf_cdc_ioctl(FAR struct bcmf_dev_s *priv, uint32_t ifidx, bool set,
uint32_t cmd, uint8_t *data, uint32_t *len);
int bcmf_cdc_process_control_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame);
int bcmf_cdc_process_data_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame);
int bcmf_cdc_process_event_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_CDC_H */

View File

@ -1,28 +1,73 @@
#include "bcmf_chip_43362.h"
#include "bcm43362_constants.h"
/****************************************************************************
* drivers/wireless/ieee80211/bcmf_chip_43362.c
*
* Copyright (C) 2017 Gregory Nutt. All rights reserved.
* Author: Simon Piriou <spiriou31@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#include <stdint.h>
#include <debug.h>
#include "bcmf_sdio_core.h"
#include "bcmf_sdio.h"
#define WRAPPER_REGISTER_OFFSET 0x100000
#define WRAPPER_REGISTER_OFFSET (0x100000)
extern const char bcm43362_nvram_image[];
extern const unsigned int bcm43362_nvram_image_len;
uint32_t bcmf_43362_get_core_base_address(unsigned int core)
{
switch (core)
{
case CHIPCOMMON_CORE_ID:
return CHIPCOMMON_BASE_ADDRESS;
case DOT11MAC_CORE_ID:
return DOT11MAC_BASE_ADDRESS;
case SDIOD_CORE_ID:
return SDIO_BASE_ADDRESS;
case WLAN_ARMCM3_CORE_ID:
return WLAN_ARMCM3_BASE_ADDRESS + WRAPPER_REGISTER_OFFSET;
case SOCSRAM_CORE_ID:
return SOCSRAM_BASE_ADDRESS + WRAPPER_REGISTER_OFFSET;
default:
_err("Invalid core id %d\n", core);
}
return 0;
}
extern const uint8_t bcm43362_firmware_image[];
extern const unsigned int bcm43362_firmware_image_len;
const struct bcmf_sdio_chip bcmf_43362_config_sdio = {
/* General chip stats */
.ram_size = 0x3C000,
/* Backplane architecture */
.core_base = {
[CHIPCOMMON_CORE_ID] = 0x18000000, /* Chipcommon core register base */
[DOT11MAC_CORE_ID] = 0x18001000, /* dot11mac core register base */
[SDIOD_CORE_ID] = 0x18002000, /* SDIOD Device core register base */
[WLAN_ARMCM3_CORE_ID] = 0x18003000 + /* ARMCM3 core register base */
WRAPPER_REGISTER_OFFSET,
[SOCSRAM_CORE_ID] = 0x18004000 + /* SOCSRAM core register base */
WRAPPER_REGISTER_OFFSET
},
/* Firmware images */
// TODO find something smarter than using image_len references
.firmware_image = bcm43362_firmware_image,
.firmware_image_size = (unsigned int*)&bcm43362_firmware_image_len,
.nvram_image = bcm43362_nvram_image,
.nvram_image_size = (unsigned int*)&bcm43362_nvram_image_len
};

View File

@ -1,8 +0,0 @@
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCM_CHIP_43362_H
#define __DRIVERS_WIRELESS_IEEE80211_BCM_CHIP_43362_H
#include <stdint.h>
uint32_t bcmf_43362_get_core_base_address(unsigned int core);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCM_CHIP_43362_H */

View File

@ -48,6 +48,8 @@
#include "bcmf_core.h"
#include "bcmf_sdio.h"
#include "bcmf_sdio_regs.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -75,15 +77,6 @@
/* Transfer size properties */
#define BCMF_UPLOAD_TRANSFER_SIZE (64 * 256)
// TODO move in chip configuration data
#define CHIP_RAM_SIZE 0x3C000
extern const char bcmf_nvram_image[];
extern const unsigned int bcmf_nvram_image_len;
extern const uint8_t bcmf_firmware_image[];
extern const unsigned int bcmf_firmware_image_len;
/****************************************************************************
* Private Types
****************************************************************************/
@ -92,14 +85,14 @@ extern const unsigned int bcmf_firmware_image_len;
* Private Function Prototypes
****************************************************************************/
static int bcmf_core_set_backplane_window(FAR struct bcmf_dev_s *priv,
static int bcmf_core_set_backplane_window(FAR struct bcmf_sdio_dev_s *sbus,
uint32_t address);
static int bcmf_upload_binary(FAR struct bcmf_dev_s *priv,
static int bcmf_upload_binary(FAR struct bcmf_sdio_dev_s *sbusv,
uint32_t address, uint8_t *buf,
unsigned int len);
static int bcmf_upload_nvram(FAR struct bcmf_dev_s *priv);
static int bcmf_upload_nvram(FAR struct bcmf_sdio_dev_s *sbus);
/****************************************************************************
* Private Data
@ -109,7 +102,8 @@ static int bcmf_upload_nvram(FAR struct bcmf_dev_s *priv);
* Private Functions
****************************************************************************/
int bcmf_core_set_backplane_window(FAR struct bcmf_dev_s *priv, uint32_t address)
int bcmf_core_set_backplane_window(FAR struct bcmf_sdio_dev_s *sbus,
uint32_t address)
{
int ret;
int i;
@ -119,13 +113,13 @@ int bcmf_core_set_backplane_window(FAR struct bcmf_dev_s *priv, uint32_t address
for (i = 1; i < 4; i++)
{
uint8_t addr_part = (address >> (8*i)) & 0xff;
uint8_t cur_addr_part = (priv->backplane_current_addr >> (8*i)) & 0xff;
uint8_t cur_addr_part = (sbus->backplane_current_addr >> (8*i)) & 0xff;
if (addr_part != cur_addr_part)
{
/* Update current backplane base address */
ret = bcmf_write_reg(priv, 1, SBSDIO_FUNC1_SBADDRLOW+i-1,
ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_SBADDRLOW+i-1,
addr_part);
if (ret != OK)
@ -133,15 +127,15 @@ int bcmf_core_set_backplane_window(FAR struct bcmf_dev_s *priv, uint32_t address
return ret;
}
priv->backplane_current_addr &= ~(0xff << (8*i));
priv->backplane_current_addr |= addr_part << (8*i);
sbus->backplane_current_addr &= ~(0xff << (8*i));
sbus->backplane_current_addr |= addr_part << (8*i);
}
}
return OK;
}
int bcmf_upload_binary(FAR struct bcmf_dev_s *priv, uint32_t address,
int bcmf_upload_binary(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address,
uint8_t *buf, unsigned int len)
{
unsigned int size;
@ -150,7 +144,7 @@ int bcmf_upload_binary(FAR struct bcmf_dev_s *priv, uint32_t address,
{
/* Set the backplane window to include the start address */
int ret = bcmf_core_set_backplane_window(priv, address);
int ret = bcmf_core_set_backplane_window(sbus, address);
if (ret != OK)
{
return ret;
@ -167,7 +161,7 @@ int bcmf_upload_binary(FAR struct bcmf_dev_s *priv, uint32_t address,
/* Transfer firmware data */
ret = bcmf_transfer_bytes(priv, true, 1,
ret = bcmf_transfer_bytes(sbus, true, 1,
address & SBSDIO_SB_OFT_ADDR_MASK, buf, size);
if (ret != OK)
{
@ -182,7 +176,7 @@ int bcmf_upload_binary(FAR struct bcmf_dev_s *priv, uint32_t address,
return OK;
}
int bcmf_upload_nvram(FAR struct bcmf_dev_s *priv)
int bcmf_upload_nvram(FAR struct bcmf_sdio_dev_s *sbus)
{
int ret;
uint32_t nvram_sz;
@ -190,14 +184,16 @@ int bcmf_upload_nvram(FAR struct bcmf_dev_s *priv)
/* Round up the size of the image */
nvram_sz = (bcmf_nvram_image_len + 63) & (-64);
nvram_sz = (*sbus->chip->nvram_image_size + 63) & (-64);
_info("nvram size is %d %d bytes\n", nvram_sz, bcmf_nvram_image_len);
_info("nvram size is %d %d bytes\n", nvram_sz,
*sbus->chip->nvram_image_size);
/* Write image */
ret = bcmf_upload_binary(priv, CHIP_RAM_SIZE - 4 - nvram_sz,
(uint8_t*)bcmf_nvram_image, bcmf_nvram_image_len);
ret = bcmf_upload_binary(sbus, sbus->chip->ram_size - 4 - nvram_sz,
sbus->chip->nvram_image,
*sbus->chip->nvram_image_size);
if ( ret != OK)
{
return ret;
@ -210,7 +206,7 @@ int bcmf_upload_nvram(FAR struct bcmf_dev_s *priv)
/* Write the length token to the last word */
ret = bcmf_write_sbreg(priv, CHIP_RAM_SIZE - 4, (uint8_t*)&token, 4);
ret = bcmf_write_sbreg(sbus, sbus->chip->ram_size - 4, (uint8_t*)&token, 4);
if ( ret != OK)
{
return ret;
@ -227,16 +223,16 @@ int bcmf_upload_nvram(FAR struct bcmf_dev_s *priv)
* Name: bcmf_read_sbreg
****************************************************************************/
int bcmf_read_sbreg(FAR struct bcmf_dev_s *priv, uint32_t address,
int bcmf_read_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address,
uint8_t *reg, unsigned int len)
{
int ret = bcmf_core_set_backplane_window(priv, address);
int ret = bcmf_core_set_backplane_window(sbus, address);
if (ret != OK)
{
return ret;
}
return bcmf_transfer_bytes(priv, false, 1,
return bcmf_transfer_bytes(sbus, false, 1,
address & SBSDIO_SB_OFT_ADDR_MASK, reg, len);
}
@ -244,17 +240,17 @@ int bcmf_read_sbreg(FAR struct bcmf_dev_s *priv, uint32_t address,
* Name: bcmf_write_sbreg
****************************************************************************/
int bcmf_write_sbreg(FAR struct bcmf_dev_s *priv, uint32_t address,
int bcmf_write_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address,
uint8_t *reg, unsigned int len)
{
int ret = bcmf_core_set_backplane_window(priv, address);
int ret = bcmf_core_set_backplane_window(sbus, address);
if (ret != OK)
{
return ret;
}
return bcmf_transfer_bytes(priv, true, 1, address & SBSDIO_SB_OFT_ADDR_MASK,
return bcmf_transfer_bytes(sbus, true, 1, address & SBSDIO_SB_OFT_ADDR_MASK,
reg, len);
}
@ -262,7 +258,7 @@ int bcmf_write_sbreg(FAR struct bcmf_dev_s *priv, uint32_t address,
* Name: bcmf_core_upload_firmware
****************************************************************************/
int bcmf_core_upload_firmware(FAR struct bcmf_dev_s *priv)
int bcmf_core_upload_firmware(FAR struct bcmf_sdio_dev_s *sbus)
{
int ret;
@ -271,16 +267,16 @@ int bcmf_core_upload_firmware(FAR struct bcmf_dev_s *priv)
/* Disable ARMCM3 core and reset SOCRAM core
* to set device in firmware upload mode */
bcmf_core_disable(priv, WLAN_ARMCM3_CORE_ID);
bcmf_core_reset(priv, SOCSRAM_CORE_ID);
bcmf_core_disable(sbus, WLAN_ARMCM3_CORE_ID);
bcmf_core_reset(sbus, SOCSRAM_CORE_ID);
up_mdelay(50);
/* Flash chip firmware */
_info("firmware size is %d bytes\n", bcmf_firmware_image_len);
ret = bcmf_upload_binary(priv, 0, (uint8_t*)bcmf_firmware_image,
bcmf_firmware_image_len);
_info("firmware size is %d bytes\n", *sbus->chip->firmware_image_size);
ret = bcmf_upload_binary(sbus, 0, sbus->chip->firmware_image,
*sbus->chip->firmware_image_size);
if (ret != OK)
{
@ -291,7 +287,7 @@ int bcmf_core_upload_firmware(FAR struct bcmf_dev_s *priv)
/* Flash NVRAM configuration file */
_info("upload nvram configuration\n");
ret = bcmf_upload_nvram(priv);
ret = bcmf_upload_nvram(sbus);
if (ret != OK)
{
_err("Failed to upload nvram\n");
@ -301,12 +297,12 @@ int bcmf_core_upload_firmware(FAR struct bcmf_dev_s *priv)
/* Firmware upload done, restart ARMCM3 core */
up_mdelay(10);
bcmf_core_reset(priv, WLAN_ARMCM3_CORE_ID);
bcmf_core_reset(sbus, WLAN_ARMCM3_CORE_ID);
/* Check ARMCM3 core is running */
up_mdelay(10);
if (!bcmf_core_isup(priv, WLAN_ARMCM3_CORE_ID))
if (!bcmf_core_isup(sbus, WLAN_ARMCM3_CORE_ID))
{
_err("Cannot start ARMCM3 core\n");
return -ETIMEDOUT;
@ -315,31 +311,43 @@ int bcmf_core_upload_firmware(FAR struct bcmf_dev_s *priv)
return OK;
}
bool bcmf_core_isup(FAR struct bcmf_dev_s *priv, unsigned int core)
bool bcmf_core_isup(FAR struct bcmf_sdio_dev_s *sbus, unsigned int core)
{
uint32_t value = 0;
uint32_t base = priv->get_core_base_address(core);
bcmf_read_sbregw(priv, base + BCMA_IOCTL, &value);
if (core >= MAX_CORE_ID)
{
_err("Invalid core id %d\n", core);
return false;
}
uint32_t base = sbus->chip->core_base[core];
bcmf_read_sbregw(sbus, base + BCMA_IOCTL, &value);
if ((value & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) != BCMA_IOCTL_CLK)
{
return false;
}
bcmf_read_sbregw(priv, base + BCMA_RESET_CTL, &value);
bcmf_read_sbregw(sbus, base + BCMA_RESET_CTL, &value);
return (value & BCMA_RESET_CTL_RESET) == 0;
}
void bcmf_core_disable(FAR struct bcmf_dev_s *priv, unsigned int core)
void bcmf_core_disable(FAR struct bcmf_sdio_dev_s *sbus, unsigned int core)
{
uint8_t value;
uint32_t base = priv->get_core_base_address(core);
if (core >= MAX_CORE_ID)
{
_err("Invalid core id %d\n", core);
return;
}
uint32_t base = sbus->chip->core_base[core];
/* Check if core is already in reset state */
bcmf_read_sbregb(priv, base + BCMA_RESET_CTL, &value);
bcmf_read_sbregb(sbus, base + BCMA_RESET_CTL, &value);
if ((value & BCMA_RESET_CTL_RESET) != 0)
{
@ -354,37 +362,43 @@ void bcmf_core_disable(FAR struct bcmf_dev_s *priv, unsigned int core)
/* Set core in reset state */
bcmf_write_sbregb(priv, base + BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
bcmf_write_sbregb(sbus, base + BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
up_udelay(1);
/* Write 0 to the IO control and read it back */
bcmf_write_sbregb(priv, base + BCMA_IOCTL, 0);
bcmf_read_sbregb(priv, base + BCMA_IOCTL, &value);
bcmf_write_sbregb(sbus, base + BCMA_IOCTL, 0);
bcmf_read_sbregb(sbus, base + BCMA_IOCTL, &value);
up_udelay(10);
}
void bcmf_core_reset(FAR struct bcmf_dev_s *priv, unsigned int core)
void bcmf_core_reset(FAR struct bcmf_sdio_dev_s *sbus, unsigned int core)
{
uint32_t value;
uint32_t base = priv->get_core_base_address(core);
if (core >= MAX_CORE_ID)
{
_err("Invalid core id %d\n", core);
return;
}
uint32_t base = sbus->chip->core_base[core];
/* Put core in reset state */
bcmf_core_disable(priv, core);
bcmf_core_disable(sbus, core);
/* Run initialization sequence */
bcmf_write_sbregb(priv, base + BCMA_IOCTL, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
bcmf_read_sbregw(priv, base + BCMA_IOCTL, &value);
bcmf_write_sbregb(sbus, base + BCMA_IOCTL, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
bcmf_read_sbregw(sbus, base + BCMA_IOCTL, &value);
bcmf_write_sbregb(priv, base + BCMA_RESET_CTL, 0);
bcmf_read_sbregw(priv, base + BCMA_RESET_CTL, &value);
bcmf_write_sbregb(sbus, base + BCMA_RESET_CTL, 0);
bcmf_read_sbregw(sbus, base + BCMA_RESET_CTL, &value);
up_udelay(1);
bcmf_write_sbregb(priv, base + BCMA_IOCTL, BCMA_IOCTL_CLK);
bcmf_read_sbregw(priv, base + BCMA_IOCTL, &value);
bcmf_write_sbregb(sbus, base + BCMA_IOCTL, BCMA_IOCTL_CLK);
bcmf_read_sbregw(sbus, base + BCMA_IOCTL, &value);
up_udelay(1);
}

View File

@ -39,45 +39,44 @@
#include <stdint.h>
#include <stdbool.h>
#include "bcmf_driver.h"
#include "bcmf_sdio.h"
int bcmf_read_sbreg(FAR struct bcmf_dev_s *priv, uint32_t address,
int bcmf_read_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address,
uint8_t *reg, unsigned int len);
int bcmf_write_sbreg(FAR struct bcmf_dev_s *priv, uint32_t address,
int bcmf_write_sbreg(FAR struct bcmf_sdio_dev_s *sbus, uint32_t address,
uint8_t *reg, unsigned int len);
bool bcmf_core_isup(FAR struct bcmf_dev_s *priv, unsigned int core);
bool bcmf_core_isup(FAR struct bcmf_sdio_dev_s *sbus, unsigned int core);
void bcmf_core_disable(FAR struct bcmf_dev_s *priv, unsigned int core);
void bcmf_core_disable(FAR struct bcmf_sdio_dev_s *sbus, unsigned int core);
void bcmf_core_reset(FAR struct bcmf_dev_s *priv, unsigned int core);
void bcmf_core_reset(FAR struct bcmf_sdio_dev_s *sbus, unsigned int core);
int bcmf_core_upload_firmware(FAR struct bcmf_dev_s *priv);
int bcmf_core_upload_firmware(FAR struct bcmf_sdio_dev_s *sbus);
static inline int bcmf_read_sbregb(FAR struct bcmf_dev_s *priv,
static inline int bcmf_read_sbregb(FAR struct bcmf_sdio_dev_s *sbus,
uint32_t address, uint8_t *reg)
{
return bcmf_read_sbreg(priv, address, reg, 1);
return bcmf_read_sbreg(sbus, address, reg, 1);
}
static inline int bcmf_read_sbregw(FAR struct bcmf_dev_s *priv,
static inline int bcmf_read_sbregw(FAR struct bcmf_sdio_dev_s *sbus,
uint32_t address, uint32_t *reg)
{
return bcmf_read_sbreg(priv, address, (uint8_t*)reg, 4);
return bcmf_read_sbreg(sbus, address, (uint8_t*)reg, 4);
}
static inline int bcmf_write_sbregb(FAR struct bcmf_dev_s *priv,
static inline int bcmf_write_sbregb(FAR struct bcmf_sdio_dev_s *sbus,
uint32_t address, uint8_t reg)
{
return bcmf_write_sbreg(priv, address, &reg, 1);
return bcmf_write_sbreg(sbus, address, &reg, 1);
}
static inline int bcmf_write_sbregw(FAR struct bcmf_dev_s *priv,
static inline int bcmf_write_sbregw(FAR struct bcmf_sdio_dev_s *sbus,
uint32_t address, uint32_t reg)
{
return bcmf_write_sbreg(priv, address, (uint8_t*)&reg, 4);
return bcmf_write_sbreg(sbus, address, (uint8_t*)&reg, 4);
}
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_CORE_H */

View File

@ -48,10 +48,12 @@
#include <nuttx/kmalloc.h>
#include "bcmf_driver.h"
#include "bcmf_sdpcm.h"
#include "bcmf_sdio_core.h"
#include "bcmf_cdc.h"
#include "bcmf_ioctl.h"
#include <nuttx/sdio.h>
#include "bcmf_sdio.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -62,6 +64,11 @@
#define WL_SCAN_UNASSOC_TIME 40
#define WL_SCAN_PASSIVE_TIME 120
/* Chip interfaces */
#define CHIP_STA_INTERFACE 0
#define CHIP_AP_INTERFACE 1
#define CHIP_P2P_INTERFACE 2
/****************************************************************************
* Private Types
****************************************************************************/
@ -70,7 +77,12 @@
* Private Function Prototypes
****************************************************************************/
static FAR struct bcmf_dev_s* bcmf_allocate_device(void);
static void bcmf_free_device(FAR struct bcmf_dev_s *priv);
#if 0
static int bcmf_run_escan(FAR struct bcmf_dev_s *priv);
#endif
/****************************************************************************
* Private Data
@ -80,12 +92,58 @@ static int bcmf_run_escan(FAR struct bcmf_dev_s *priv);
* Private Functions
****************************************************************************/
FAR struct bcmf_dev_s* bcmf_allocate_device(void)
{
int ret;
FAR struct bcmf_dev_s *priv;
/* Allocate a bcmf device structure */
priv = (FAR struct bcmf_dev_s *)kmm_malloc(sizeof(*priv));
if (!priv)
{
return NULL;
}
/* Initialize bcmf device structure */
memset(priv, 0, sizeof(*priv));
/* Init control frames mutex and timeout signal */
if ((ret = sem_init(&priv->control_mutex, 0, 1)) != OK)
{
goto exit_free_priv;
}
if ((ret = sem_init(&priv->control_timeout, 0, 0)) != OK)
{
goto exit_free_priv;
}
if ((ret = sem_setprotocol(&priv->control_timeout, SEM_PRIO_NONE)) != OK)
{
goto exit_free_priv;
}
return priv;
exit_free_priv:
kmm_free(priv);
return NULL;
}
void bcmf_free_device(FAR struct bcmf_dev_s *priv)
{
/* TODO deinitialize device structures */
kmm_free(priv);
}
int bcmf_wl_set_mac_address(FAR struct bcmf_dev_s *priv, uint8_t *addr)
{
int ret;
uint32_t out_len = 6;
ret = bcmf_sdpcm_iovar_request(priv, CHIP_STA_INTERFACE, true,
ret = bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, true,
IOVAR_STR_CUR_ETHERADDR, addr,
&out_len);
if (ret != OK)
@ -109,7 +167,7 @@ int bcmf_wl_enable(FAR struct bcmf_dev_s *priv, bool enable)
/* TODO chek device state */
out_len = 0;
ret = bcmf_sdpcm_ioctl(priv, CHIP_STA_INTERFACE, true,
ret = bcmf_cdc_ioctl(priv, CHIP_STA_INTERFACE, true,
enable ? WLC_UP : WLC_DOWN, NULL, &out_len);
if (ret == OK)
@ -128,7 +186,7 @@ int bcmf_dongle_scantime(FAR struct bcmf_dev_s *priv, int32_t scan_assoc_time,
out_len = 4;
value = scan_assoc_time;
ret = bcmf_sdpcm_ioctl(priv, CHIP_STA_INTERFACE, true,
ret = bcmf_cdc_ioctl(priv, CHIP_STA_INTERFACE, true,
WLC_SET_SCAN_CHANNEL_TIME, (uint8_t*)&value,
&out_len);
if (ret != OK)
@ -138,7 +196,7 @@ int bcmf_dongle_scantime(FAR struct bcmf_dev_s *priv, int32_t scan_assoc_time,
out_len = 4;
value = scan_unassoc_time;
ret = bcmf_sdpcm_ioctl(priv, CHIP_STA_INTERFACE, true,
ret = bcmf_cdc_ioctl(priv, CHIP_STA_INTERFACE, true,
WLC_SET_SCAN_UNASSOC_TIME, (uint8_t*)&value,
&out_len);
if (ret != OK)
@ -148,7 +206,7 @@ int bcmf_dongle_scantime(FAR struct bcmf_dev_s *priv, int32_t scan_assoc_time,
out_len = 4;
value = scan_passive_time;
ret = bcmf_sdpcm_ioctl(priv, CHIP_STA_INTERFACE, true,
ret = bcmf_cdc_ioctl(priv, CHIP_STA_INTERFACE, true,
WLC_SET_SCAN_PASSIVE_TIME, (uint8_t*)&value,
&out_len);
if (ret != OK)
@ -182,7 +240,7 @@ int bcmf_dongle_initialize(FAR struct bcmf_dev_s *priv)
out_len = 4;
value = 0;
ret = bcmf_sdpcm_ioctl(priv, CHIP_STA_INTERFACE, true,
ret = bcmf_cdc_ioctl(priv, CHIP_STA_INTERFACE, true,
WLC_SET_PM, (uint8_t*)&value, &out_len);
if (ret != OK)
{
@ -193,7 +251,7 @@ int bcmf_dongle_initialize(FAR struct bcmf_dev_s *priv)
out_len = 4;
value = GMODE_AUTO;
ret = bcmf_sdpcm_ioctl(priv, CHIP_STA_INTERFACE, true,
ret = bcmf_cdc_ioctl(priv, CHIP_STA_INTERFACE, true,
WLC_SET_GMODE, (uint8_t*)&value, &out_len);
if (ret != OK)
{
@ -204,22 +262,25 @@ int bcmf_dongle_initialize(FAR struct bcmf_dev_s *priv)
out_len = 4;
value = 1;
ret = bcmf_sdpcm_iovar_request(priv, CHIP_STA_INTERFACE, true,
ret = bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, true,
IOVAR_STR_ROAM_OFF, (uint8_t*)&value,
&out_len);
// FIXME remove
#if 0
/* Try scan */
value = 0;
out_len = 4;
ret = bcmf_sdpcm_ioctl(priv, CHIP_STA_INTERFACE, true,
ret = bcmf_cdc_ioctl(priv, CHIP_STA_INTERFACE, true,
WLC_SET_PASSIVE_SCAN, (uint8_t*)&value, &out_len);
bcmf_run_escan(priv);
return OK;
#endif
return ret;
}
#if 0
int bcmf_run_escan(FAR struct bcmf_dev_s *priv)
{
int ret;
@ -254,7 +315,7 @@ int bcmf_run_escan(FAR struct bcmf_dev_s *priv)
_info("start scan\n");
out_len = sizeof(*params);
ret = bcmf_sdpcm_iovar_request(priv, CHIP_STA_INTERFACE, true,
ret = bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, true,
IOVAR_STR_ESCAN, (uint8_t*)params,
&out_len);
@ -267,6 +328,7 @@ int bcmf_run_escan(FAR struct bcmf_dev_s *priv)
return OK;
}
#endif
/****************************************************************************
* Public Functions
@ -282,7 +344,7 @@ int bcmf_wl_initialize(FAR struct bcmf_dev_s *priv)
out_len = 4;
*(uint32_t*)tmp_buf = 0;
ret = bcmf_sdpcm_iovar_request(priv, CHIP_STA_INTERFACE, false,
ret = bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, false,
IOVAR_STR_TX_GLOM, tmp_buf,
&out_len);
if (ret != OK)
@ -293,7 +355,7 @@ int bcmf_wl_initialize(FAR struct bcmf_dev_s *priv)
/* Query MAC address */
out_len = 6;
ret = bcmf_sdpcm_iovar_request(priv, CHIP_STA_INTERFACE, false,
ret = bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, false,
IOVAR_STR_CUR_ETHERADDR, tmp_buf,
&out_len);
if (ret != OK)
@ -310,7 +372,7 @@ int bcmf_wl_initialize(FAR struct bcmf_dev_s *priv)
/* Query firmware version string */
out_len = sizeof(tmp_buf);
ret = bcmf_sdpcm_iovar_request(priv, CHIP_STA_INTERFACE, false,
ret = bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, false,
IOVAR_STR_VERSION, tmp_buf,
&out_len);
if (ret != OK)
@ -333,7 +395,7 @@ int bcmf_wl_initialize(FAR struct bcmf_dev_s *priv)
memset(event_mask, 0xff, sizeof(event_mask));
out_len = sizeof(event_mask);
ret = bcmf_sdpcm_iovar_request(priv, CHIP_STA_INTERFACE, true,
ret = bcmf_cdc_iovar_request(priv, CHIP_STA_INTERFACE, true,
IOVAR_STR_EVENT_MSGS, event_mask,
&out_len);
if (ret != OK)
@ -343,4 +405,35 @@ int bcmf_wl_initialize(FAR struct bcmf_dev_s *priv)
// TODO Create a wlan device name and register network driver
return bcmf_dongle_initialize(priv);
}
int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
{
int ret;
FAR struct bcmf_dev_s *priv;
_info("minor: %d\n", minor);
priv = bcmf_allocate_device();
if (!priv)
{
return -ENOMEM;
}
/* Init sdio bus */
ret = bcmf_bus_sdio_initialize(priv, minor, dev);
if (ret != OK)
{
ret = -EIO;
goto exit_free_device;
}
/* Bus initialized, register network driver */
return bcmf_wl_initialize(priv);
exit_free_device:
bcmf_free_device(priv);
return ret;
}

View File

@ -37,7 +37,8 @@
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_DRIVER_H
#include <stdbool.h>
#include <nuttx/sdio.h>
#include <stdint.h>
#include <semaphore.h>
#define BCMF_STATUS_BUS_UP (1<<0) /* Chip is flashed and running */
#define BCMF_STATUS_READY (1<<1) /* Chip is ready to receive requests */
@ -45,43 +46,56 @@
#define BCMF_STATUS_SLEEP (1<<2) /* Chip is in low power mode */
#define BCMF_STATUS_WAIT_CONTROL (1<<3) /* Waiting for control response */
struct bcmf_bus_dev_s;
struct bcmf_frame_s;
/* This structure contains the unique state of the Broadcom FullMAC driver */
struct bcmf_dev_s
{
FAR struct sdio_dev_s *sdio_dev; /* The SDIO device bound to this instance */
int minor; /* Device minor number */
uint32_t backplane_current_addr; /* Current function 1 backplane base addr */
uint32_t (*get_core_base_address)(unsigned int core); /* Get chip specific
base address for evey cores */
sem_t thread_signal; /* Semaphore for processing thread event */
struct wdog_s *waitdog; /* Processing thread waitdog */
bool ready; /* Current device status */
bool sleeping; /* Current sleep status */
volatile bool irq_pending; /* True if interrupt is pending */
uint32_t intstatus; /* Copy of device current interrupt status */
uint8_t max_seq; /* Maximum transmit sequence allowed */
uint8_t tx_seq; /* Transmit sequence number (next) */
uint8_t rx_seq; /* Receive sequence number (expected) */
FAR struct bcmf_bus_dev_s *bus; /* Bus interface structure */
// FIXME use mutex instead of semaphore
sem_t control_mutex; /* Cannot handle multiple control requests */
sem_t control_timeout; /* Semaphore to wait for control frame rsp */
uint16_t control_reqid; /* Current control request id */
uint8_t *control_rxframe; /* Received control frame response */
uint32_t control_status; /* Last received frame status */
sem_t control_mutex; /* Cannot handle multiple control requests */
sem_t control_timeout; /* Semaphore to wait for control frame rsp */
uint16_t control_reqid; /* Current control request id */
uint16_t control_rxdata_len; /* Received control frame out buffer length */
uint8_t *control_rxdata; /* Received control frame out buffer */
uint32_t control_status; /* Last received frame status */
// FIXME use mutex instead of semaphore
sem_t tx_queue_mutex; /* Lock for transmit queue */
dq_queue_t tx_queue; /* Queue of frames to tramsmit */
uint8_t mac_addr[6]; /* Current mac address */
uint8_t mac_addr[6]; /* Current mac address */
};
int bcmf_wl_initialize(FAR struct bcmf_dev_s *priv);
/* Default bus interface structure */
struct bcmf_bus_dev_s {
void (*stop)(FAR struct bcmf_dev_s *priv);
int (*txframe)(FAR struct bcmf_dev_s *priv, struct bcmf_frame_s *frame);
/* Frame buffer allocation primitive
* len - requested payload length
* control - true if control frame else false
* block - true to block until free frame is available
*/
struct bcmf_frame_s* (*allocate_frame)(FAR struct bcmf_dev_s *priv,
unsigned int len, bool control, bool block);
};
/* bcmf frame definition */
struct bcmf_frame_s {
uint8_t *base; /* Frame base buffer used by low level layer (SDIO) */
uint8_t *data; /* Payload data (Control, data and event messages) */
unsigned int len; /* Frame buffer size */
};
/* Notify driver frame is available */
void bcmf_notify_rxframe(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame);
/* Notify driver bus is ready */
int brcmf_bus_start(FAR struct bcmf_dev_s *priv);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_DRIVER_H */

View File

@ -46,9 +46,9 @@
#include <debug.h>
#include <errno.h>
#include <queue.h>
#include <semaphore.h>
#include <nuttx/kmalloc.h>
#include <nuttx/sdio.h>
#include <nuttx/arch.h>
#include <nuttx/kthread.h>
@ -60,9 +60,17 @@
#include "bcmf_core.h"
#include "bcmf_sdpcm.h"
#include "bcmf_sdio_core.h"
#include "bcmf_sdio_regs.h"
// TODO remove
#include "bcmf_ioctl.h"
/* Supported chip configurations */
#ifdef CONFIG_IEEE80211_BROADCOM_BCM43362
extern const struct bcmf_sdio_chip bcmf_43362_config_sdio;
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
@ -84,66 +92,66 @@
* Private Function Prototypes
****************************************************************************/
static int bcmf_probe(FAR struct bcmf_dev_s *priv);
static int bcmf_hwinitialize(FAR struct bcmf_dev_s *priv);
static void bcmf_hwuninitialize(FAR struct bcmf_dev_s *priv);
static int bcmf_chipinitialize(FAR struct bcmf_dev_s *priv);
static int bcmf_probe(FAR struct bcmf_sdio_dev_s *sbus);
static int bcmf_hwinitialize(FAR struct bcmf_sdio_dev_s *sbus);
static void bcmf_hwuninitialize(FAR struct bcmf_sdio_dev_s *sbus);
static int bcmf_chipinitialize(FAR struct bcmf_sdio_dev_s *sbus);
static int bcmf_oob_irq(int irq, FAR void *context, FAR void *arg);
static int bcmf_sdio_bus_sleep(FAR struct bcmf_dev_s *priv, bool sleep);
static int bcmf_sdio_bus_sleep(FAR struct bcmf_sdio_dev_s *sbus, bool sleep);
static void bcmf_sdio_waitdog_timeout(int argc, wdparm_t arg1, ...);
static int bcmf_sdio_thread(int argc, char **argv);
static int bcmf_sdio_find_block_size(unsigned int size);
/* FIXME remove */
FAR struct bcmf_dev_s *g_sdio_priv;
/****************************************************************************
* Private Data
****************************************************************************/
/* FIXME remove */
FAR struct bcmf_dev_s *g_sdio_priv;
/****************************************************************************
* Private Functions
****************************************************************************/
int bcmf_oob_irq(int irq, FAR void *context, FAR void *arg)
{
FAR struct bcmf_dev_s *priv = (struct bcmf_dev_s*)arg;
FAR struct bcmf_sdio_dev_s *sbus = (struct bcmf_sdio_dev_s*)arg;
if (priv->ready)
if (sbus->ready)
{
/* Signal bmcf thread */
priv->irq_pending = true;
sbus->irq_pending = true;
sem_post(&priv->thread_signal);
sem_post(&sbus->thread_signal);
}
return OK;
}
int bcmf_sdio_bus_sleep(FAR struct bcmf_dev_s *priv, bool sleep)
int bcmf_sdio_bus_sleep(FAR struct bcmf_sdio_dev_s *sbus, bool sleep)
{
int ret;
int loops;
uint8_t value;
if (priv->sleeping == sleep)
if (sbus->sleeping == sleep)
{
return OK;
}
if (sleep)
{
priv->sleeping = true;
return bcmf_write_reg(priv, 1, SBSDIO_FUNC1_CHIPCLKCSR, 0);
sbus->sleeping = true;
return bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, 0);
}
else
{
/* Request HT Avail */
ret = bcmf_write_reg(priv, 1, SBSDIO_FUNC1_CHIPCLKCSR,
ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR,
SBSDIO_HT_AVAIL_REQ | SBSDIO_FORCE_HT);
if (ret != OK)
{
@ -157,7 +165,7 @@ int bcmf_sdio_bus_sleep(FAR struct bcmf_dev_s *priv, bool sleep)
while (--loops > 0)
{
up_mdelay(1);
ret = bcmf_read_reg(priv, 1, SBSDIO_FUNC1_CHIPCLKCSR, &value);
ret = bcmf_read_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, &value);
if (ret != OK)
{
@ -177,7 +185,7 @@ int bcmf_sdio_bus_sleep(FAR struct bcmf_dev_s *priv, bool sleep)
return -ETIMEDOUT;
}
priv->sleeping = false;
sbus->sleeping = false;
}
return OK;
@ -187,13 +195,13 @@ int bcmf_sdio_bus_sleep(FAR struct bcmf_dev_s *priv, bool sleep)
* Name: bcmf_probe
****************************************************************************/
int bcmf_probe(FAR struct bcmf_dev_s *priv)
int bcmf_probe(FAR struct bcmf_sdio_dev_s *sbus)
{
int ret;
/* Probe sdio card compatible device */
ret = sdio_probe(priv->sdio_dev);
ret = sdio_probe(sbus->sdio_dev);
if (ret != OK)
{
goto exit_error;
@ -201,19 +209,19 @@ int bcmf_probe(FAR struct bcmf_dev_s *priv)
/* Set FN0 / FN1 / FN2 default block size */
ret = sdio_set_blocksize(priv->sdio_dev, 0, 64);
ret = sdio_set_blocksize(sbus->sdio_dev, 0, 64);
if (ret != OK)
{
goto exit_error;
}
ret = sdio_set_blocksize(priv->sdio_dev, 1, 64);
ret = sdio_set_blocksize(sbus->sdio_dev, 1, 64);
if (ret != OK)
{
goto exit_error;
}
ret = sdio_set_blocksize(priv->sdio_dev, 2, 64);
ret = sdio_set_blocksize(sbus->sdio_dev, 2, 64);
if (ret != OK)
{
goto exit_error;
@ -221,7 +229,7 @@ int bcmf_probe(FAR struct bcmf_dev_s *priv)
/* Enable device interrupts for FN0, FN1 and FN2 */
ret = bcmf_write_reg(priv, 0, SDIO_CCCR_INTEN,
ret = bcmf_write_reg(sbus, 0, SDIO_CCCR_INTEN,
(1 << 0) | (1 << 1) | (1 << 2));
if (ret != OK)
{
@ -231,12 +239,12 @@ int bcmf_probe(FAR struct bcmf_dev_s *priv)
/* Default device clock speed is up to 25 Mhz
* We could set EHS bit to operate at a clock rate up to 50 Mhz */
SDIO_CLOCK(priv->sdio_dev, CLOCK_SD_TRANSFER_4BIT);
SDIO_CLOCK(sbus->sdio_dev, CLOCK_SD_TRANSFER_4BIT);
up_mdelay(BCMF_CLOCK_SETUP_DELAY_MS);
/* Enable bus FN1 */
ret = sdio_enable_function(priv->sdio_dev, 1);
ret = sdio_enable_function(sbus->sdio_dev, 1);
if (ret != OK)
{
goto exit_error;
@ -246,7 +254,7 @@ int bcmf_probe(FAR struct bcmf_dev_s *priv)
exit_error:
_err("ERROR: failed to probe device %d\n", priv->minor);
_err("ERROR: failed to probe device %d\n", sbus->minor);
return ret;
}
@ -254,7 +262,7 @@ exit_error:
* Name: bcmf_businitialize
****************************************************************************/
int bcmf_businitialize(FAR struct bcmf_dev_s *priv)
int bcmf_businitialize(FAR struct bcmf_sdio_dev_s *sbus)
{
int ret;
int loops;
@ -262,7 +270,7 @@ int bcmf_businitialize(FAR struct bcmf_dev_s *priv)
/* Send Active Low-Power clock request */
ret = bcmf_write_reg(priv, 1, SBSDIO_FUNC1_CHIPCLKCSR,
ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR,
SBSDIO_FORCE_HW_CLKREQ_OFF |
SBSDIO_ALP_AVAIL_REQ |
SBSDIO_FORCE_ALP);
@ -276,7 +284,7 @@ int bcmf_businitialize(FAR struct bcmf_dev_s *priv)
while (--loops > 0)
{
up_mdelay(10);
ret = bcmf_read_reg(priv, 1, SBSDIO_FUNC1_CHIPCLKCSR, &value);
ret = bcmf_read_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, &value);
if (ret != OK)
{
@ -298,7 +306,7 @@ int bcmf_businitialize(FAR struct bcmf_dev_s *priv)
/* Clear Active Low-Power clock request */
ret = bcmf_write_reg(priv, 1, SBSDIO_FUNC1_CHIPCLKCSR, 0);
ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_CHIPCLKCSR, 0);
if (ret != OK)
{
return ret;
@ -306,7 +314,7 @@ int bcmf_businitialize(FAR struct bcmf_dev_s *priv)
/* Disable pull-ups on SDIO cmd, d0-2 lines */
ret = bcmf_write_reg(priv, 1, SBSDIO_FUNC1_SDIOPULLUP, 0);
ret = bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_SDIOPULLUP, 0);
if (ret != OK)
{
return ret;
@ -314,7 +322,7 @@ int bcmf_businitialize(FAR struct bcmf_dev_s *priv)
/* Do chip specific initialization */
ret = bcmf_chipinitialize(priv);
ret = bcmf_chipinitialize(sbus);
if (ret != OK)
{
return ret;
@ -322,7 +330,7 @@ int bcmf_businitialize(FAR struct bcmf_dev_s *priv)
/* Upload firmware */
ret = bcmf_core_upload_firmware(priv);
ret = bcmf_core_upload_firmware(sbus);
if (ret != OK)
{
return ret;
@ -330,7 +338,7 @@ int bcmf_businitialize(FAR struct bcmf_dev_s *priv)
/* Enable FN2 (frame transfers) */
ret = sdio_enable_function(priv->sdio_dev, 2);
ret = sdio_enable_function(sbus->sdio_dev, 2);
if (ret != OK)
{
return ret;
@ -339,22 +347,22 @@ int bcmf_businitialize(FAR struct bcmf_dev_s *priv)
return OK;
}
int bcmf_bus_setup_interrupts(FAR struct bcmf_dev_s *priv)
int bcmf_bus_setup_interrupts(FAR struct bcmf_sdio_dev_s *sbus)
{
int ret;
/* Configure gpio interrupt pin */
bcmf_board_setup_oob_irq(priv->minor, bcmf_oob_irq, (void*)priv);
bcmf_board_setup_oob_irq(sbus->minor, bcmf_oob_irq, (void*)sbus);
/* Enable function 2 interrupt */
ret = sdio_enable_interrupt(priv->sdio_dev, 0);
ret = sdio_enable_interrupt(sbus->sdio_dev, 0);
if (ret != OK)
{
return ret;
}
ret = sdio_enable_interrupt(priv->sdio_dev, 2);
ret = sdio_enable_interrupt(sbus->sdio_dev, 2);
if (ret != OK)
{
return ret;
@ -362,7 +370,7 @@ int bcmf_bus_setup_interrupts(FAR struct bcmf_dev_s *priv)
/* Redirect, configure and enable io for out-of-band interrupt signal */
ret = bcmf_write_reg(priv, 0, SDIO_CCCR_BRCM_SEPINT,
ret = bcmf_write_reg(sbus, 0, SDIO_CCCR_BRCM_SEPINT,
SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI);
if (ret != OK)
{
@ -371,7 +379,7 @@ int bcmf_bus_setup_interrupts(FAR struct bcmf_dev_s *priv)
/* Wake up chip to be sure function 2 is running */
ret = bcmf_sdio_bus_sleep(priv, false);
ret = bcmf_sdio_bus_sleep(sbus, false);
if (ret != OK)
{
return ret;
@ -379,15 +387,15 @@ int bcmf_bus_setup_interrupts(FAR struct bcmf_dev_s *priv)
/* FN2 successfully enabled, set core and enable interrupts */
bcmf_write_sbregw(priv,
CORE_BUS_REG(priv->get_core_base_address(SDIOD_CORE_ID),
bcmf_write_sbregw(sbus,
CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID],
hostintmask), I_HMB_SW_MASK);
bcmf_write_sbregb(priv,
CORE_BUS_REG(priv->get_core_base_address(SDIOD_CORE_ID),
bcmf_write_sbregb(sbus,
CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID],
funcintmask), 2);
bcmf_write_reg(priv, 1, SBSDIO_WATERMARK, 8);
bcmf_write_reg(sbus, 1, SBSDIO_WATERMARK, 8);
return OK;
}
@ -396,26 +404,26 @@ int bcmf_bus_setup_interrupts(FAR struct bcmf_dev_s *priv)
* Name: bcmf_hwinitialize
****************************************************************************/
int bcmf_hwinitialize(FAR struct bcmf_dev_s *priv)
int bcmf_hwinitialize(FAR struct bcmf_sdio_dev_s *sbus)
{
/* Attach and prepare SDIO interrupts */
SDIO_ATTACH(priv->sdio_dev);
SDIO_ATTACH(sbus->sdio_dev);
/* Set ID mode clocking (<400KHz) */
SDIO_CLOCK(priv->sdio_dev, CLOCK_IDMODE);
SDIO_CLOCK(sbus->sdio_dev, CLOCK_IDMODE);
/* Configure hardware */
bcmf_board_initialize(priv->minor);
bcmf_board_initialize(sbus->minor);
/* Reset and power device */
bcmf_board_reset(priv->minor, true);
bcmf_board_power(priv->minor, true);
bcmf_board_reset(sbus->minor, true);
bcmf_board_power(sbus->minor, true);
up_mdelay(BCMF_DEVICE_RESET_DELAY_MS);
bcmf_board_reset(priv->minor, false);
bcmf_board_reset(sbus->minor, false);
/* Wait for device to start */
@ -428,12 +436,12 @@ int bcmf_hwinitialize(FAR struct bcmf_dev_s *priv)
* Name: bcmf_hwuninitialize
****************************************************************************/
void bcmf_hwuninitialize(FAR struct bcmf_dev_s *priv)
void bcmf_hwuninitialize(FAR struct bcmf_sdio_dev_s *sbus)
{
/* Shutdown device */
bcmf_board_power(priv->minor, false);
bcmf_board_reset(priv->minor, true);
bcmf_board_power(sbus->minor, false);
bcmf_board_reset(sbus->minor, true);
}
int bcmf_sdio_find_block_size(unsigned int size)
@ -460,7 +468,7 @@ int bcmf_sdio_find_block_size(unsigned int size)
* Name: bcmf_transfer_bytes
****************************************************************************/
int bcmf_transfer_bytes(FAR struct bcmf_dev_s *priv, bool write,
int bcmf_transfer_bytes(FAR struct bcmf_sdio_dev_s *sbus, bool write,
uint8_t function, uint32_t address,
uint8_t *buf, unsigned int len)
{
@ -478,10 +486,10 @@ int bcmf_transfer_bytes(FAR struct bcmf_dev_s *priv, bool write,
{
if (write)
{
return sdio_io_rw_direct(priv->sdio_dev, write,
return sdio_io_rw_direct(sbus->sdio_dev, write,
function, address, *buf, NULL);
}
return sdio_io_rw_direct(priv->sdio_dev, write,
return sdio_io_rw_direct(sbus->sdio_dev, write,
function, address, 0, buf);
}
@ -502,7 +510,7 @@ int bcmf_transfer_bytes(FAR struct bcmf_dev_s *priv, bool write,
nblocks = 0;
}
return sdio_io_rw_extended(priv->sdio_dev, write,
return sdio_io_rw_extended(sbus->sdio_dev, write,
function, address, true, buf, blocklen, nblocks);
}
@ -510,114 +518,85 @@ int bcmf_transfer_bytes(FAR struct bcmf_dev_s *priv, bool write,
* Name: bcmf_read_reg
****************************************************************************/
int bcmf_read_reg(FAR struct bcmf_dev_s *priv, uint8_t function,
int bcmf_read_reg(FAR struct bcmf_sdio_dev_s *sbus, uint8_t function,
uint32_t address, uint8_t *reg)
{
*reg = 0;
return bcmf_transfer_bytes(priv, false, function, address, reg, 1);
return bcmf_transfer_bytes(sbus, false, function, address, reg, 1);
}
/****************************************************************************
* Name: bcmf_write_reg
****************************************************************************/
int bcmf_write_reg(FAR struct bcmf_dev_s *priv, uint8_t function,
int bcmf_write_reg(FAR struct bcmf_sdio_dev_s *sbus, uint8_t function,
uint32_t address, uint8_t reg)
{
return bcmf_transfer_bytes(priv, true, function, address, &reg, 1);
return bcmf_transfer_bytes(sbus, true, function, address, &reg, 1);
}
/****************************************************************************
* Name: bcmf_sem_wait
* Name: bcmf_bus_sdio_initialize
****************************************************************************/
int bcmf_sem_wait(sem_t *sem, unsigned int timeout_ms)
int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv,
int minor, FAR struct sdio_dev_s *dev)
{
struct timespec abstime;
/* Get the current time */
(void)clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_nsec += 1000 * 1000* timeout_ms;
if (abstime.tv_nsec >= 1000 * 1000 * 1000)
{
abstime.tv_sec++;
abstime.tv_nsec -= 1000 * 1000 * 1000;
}
return sem_timedwait(sem, &abstime);
}
/****************************************************************************
* Name: bcmf_sdio_initialize
****************************************************************************/
int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
{
FAR struct bcmf_dev_s *priv;
int ret;
FAR struct bcmf_sdio_dev_s *sbus;
_info("minor: %d\n", minor);
/* Allocate sdio bus structure */
/* Allocate a bcmf device structure */
sbus = (FAR struct bcmf_sdio_dev_s*)kmm_malloc(sizeof(*sbus));
priv = (FAR struct bcmf_dev_s *)kmm_malloc(sizeof(*priv));
if (!priv)
if (!sbus)
{
return -ENOMEM;
}
/* Initialize bcmf device structure */
/* Initialize sdio bus device structure */
memset(priv, 0, sizeof(*priv));
priv->sdio_dev = dev;
priv->minor = minor;
priv->ready = false;
priv->sleeping = true;
if ((ret = sem_init(&priv->thread_signal, 0, 0)) != OK)
{
goto exit_free_priv;
}
if ((ret = sem_setprotocol(&priv->thread_signal, SEM_PRIO_NONE)) != OK)
{
goto exit_free_priv;
}
memset(sbus, 0, sizeof(*sbus));
sbus->sdio_dev = dev;
sbus->minor = minor;
sbus->ready = false;
sbus->sleeping = true;
priv->waitdog = wd_create();
if (!priv->waitdog)
{
ret = -ENOMEM;
goto exit_free_priv;
}
sbus->bus.txframe = bcmf_sdpcm_queue_frame;
sbus->bus.allocate_frame = bcmf_sdpcm_allocate_frame;
sbus->bus.stop = NULL; // TODO
if ((ret = sem_init(&priv->control_mutex, 0, 1)) != OK)
{
goto exit_free_waitdog;
}
if ((ret = sem_init(&priv->control_timeout, 0, 0)) != OK)
{
goto exit_free_waitdog;
}
if ((ret = sem_setprotocol(&priv->control_timeout, SEM_PRIO_NONE)) != OK)
{
goto exit_free_waitdog;
}
/* Init transmit frames queue */
if ((ret = sem_init(&priv->tx_queue_mutex, 0, 1)) != OK)
if ((ret = sem_init(&sbus->tx_queue_mutex, 0, 1)) != OK)
{
goto exit_free_waitdog;
goto exit_free_bus;
}
sq_init(&sbus->tx_queue);
/* Init thread semaphore */
if ((ret = sem_init(&sbus->thread_signal, 0, 0)) != OK)
{
goto exit_free_bus;
}
if ((ret = sem_setprotocol(&sbus->thread_signal, SEM_PRIO_NONE)) != OK)
{
goto exit_free_bus;
}
/* Init thread waitdog */
sbus->waitdog = wd_create();
if (!sbus->waitdog)
{
ret = -ENOMEM;
goto exit_free_bus;
}
sq_init(&priv->tx_queue);
/* Initialize device hardware */
ret = bcmf_hwinitialize(priv);
ret = bcmf_hwinitialize(sbus);
if (ret != OK)
{
@ -626,7 +605,7 @@ int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
/* Probe device */
ret = bcmf_probe(priv);
ret = bcmf_probe(sbus);
if (ret != OK)
{
@ -635,7 +614,7 @@ int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
/* Initialize device bus */
ret = bcmf_businitialize(priv);
ret = bcmf_businitialize(sbus);
if (ret != OK)
{
@ -645,9 +624,9 @@ int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
up_mdelay(100);
priv->ready = true;
sbus->ready = true;
ret = bcmf_bus_setup_interrupts(priv);
ret = bcmf_bus_setup_interrupts(sbus);
if (ret != OK)
{
goto exit_uninit_hw;
@ -656,9 +635,13 @@ int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
/* FIXME global variable for now */
g_sdio_priv = priv;
/* Register sdio bus */
priv->bus = &sbus->bus;
/* Start the waitdog timer */
wd_start(priv->waitdog, BCMF_WAITDOG_TIMEOUT_TICK, bcmf_sdio_waitdog_timeout, 0);
wd_start(sbus->waitdog, BCMF_WAITDOG_TIMEOUT_TICK, bcmf_sdio_waitdog_timeout, 0);
/* Spawn bcmf daemon thread */
@ -673,34 +656,30 @@ int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
goto exit_uninit_hw;
}
/* sdio bus is ready, init driver */
sbus->thread_id = ret;
ret = bcmf_wl_initialize(priv);
if (ret != OK)
{
_err("Cannot init wlan driver %d\n", ret);
ret = -EIO;
goto exit_uninit_hw;
}
/* sdio bus is up and running */
return OK;
exit_uninit_hw:
bcmf_hwuninitialize(priv);
bcmf_hwuninitialize(sbus);
exit_free_waitdog:
// TODO
exit_free_priv:
kmm_free(priv);
priv->ready = false;
wd_delete(sbus->waitdog);
exit_free_bus:
kmm_free(sbus);
priv->bus = NULL;
return ret;
}
int bcmf_chipinitialize(FAR struct bcmf_dev_s *priv)
int bcmf_chipinitialize(FAR struct bcmf_sdio_dev_s *sbus)
{
int ret;
uint32_t value = 0;
ret = bcmf_read_sbregw(priv, SI_ENUM_BASE, &value);
ret = bcmf_read_sbregw(sbus, SI_ENUM_BASE, &value);
if (ret != OK)
{
return ret;
@ -710,10 +689,12 @@ int bcmf_chipinitialize(FAR struct bcmf_dev_s *priv)
int chipid = value & 0xffff;
switch (chipid)
{
#ifdef CONFIG_IEEE80211_BROADCOM_BCM43362
case SDIO_DEVICE_ID_BROADCOM_43362:
_info("bcm43362 chip detected\n");
priv->get_core_base_address = bcmf_43362_get_core_base_address;
sbus->chip = (struct bcmf_sdio_chip*)&bcmf_43362_config_sdio;
break;
#endif
default:
_err("chip 0x%x is not supported\n", chipid);
return -ENODEV;
@ -724,16 +705,18 @@ int bcmf_chipinitialize(FAR struct bcmf_dev_s *priv)
void bcmf_sdio_waitdog_timeout(int argc, wdparm_t arg1, ...)
{
FAR struct bcmf_dev_s *priv = g_sdio_priv;
FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s*)priv->bus;
/* Notify bcmf thread */
sem_post(&priv->thread_signal);
sem_post(&sbus->thread_signal);
}
int bcmf_sdio_thread(int argc, char **argv)
{
int ret;
FAR struct bcmf_dev_s *priv = g_sdio_priv;
FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s*)priv->bus;
_info("Enter\n");
@ -741,11 +724,11 @@ int bcmf_sdio_thread(int argc, char **argv)
up_mdelay(50);
while (1)
while (sbus->ready)
{
/* Wait for event (device interrupt, user request or waitdog timer) */
ret = sem_wait(&priv->thread_signal);
ret = sem_wait(&sbus->thread_signal);
if (ret != OK)
{
_err("Error while waiting for semaphore\n");
@ -754,34 +737,34 @@ int bcmf_sdio_thread(int argc, char **argv)
/* Restart the waitdog timer */
wd_start(priv->waitdog, BCMF_WAITDOG_TIMEOUT_TICK,
wd_start(sbus->waitdog, BCMF_WAITDOG_TIMEOUT_TICK,
bcmf_sdio_waitdog_timeout, 0);
/* Wake up device */
bcmf_sdio_bus_sleep(priv, false);
bcmf_sdio_bus_sleep(sbus, false);
if (priv->irq_pending)
if (sbus->irq_pending)
{
/* Woken up by interrupt, read device status */
priv->irq_pending = false;
sbus->irq_pending = false;
bcmf_read_sbregw(priv,
CORE_BUS_REG(priv->get_core_base_address(SDIOD_CORE_ID),
intstatus), &priv->intstatus);
bcmf_read_sbregw(sbus,
CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID],
intstatus), &sbus->intstatus);
/* Clear interrupts */
bcmf_write_sbregw(priv,
CORE_BUS_REG(priv->get_core_base_address(SDIOD_CORE_ID),
intstatus), priv->intstatus);
// _info("intstatus %x\n", priv->intstatus);
bcmf_write_sbregw(sbus,
CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID],
intstatus), sbus->intstatus);
// _info("intstatus %x\n", sbus->intstatus);
}
/* On frame indication, read available frames */
if (priv->intstatus & I_HMB_FRAME_IND)
if (sbus->intstatus & I_HMB_FRAME_IND)
{
// _info("Frames available\n");
@ -794,7 +777,7 @@ int bcmf_sdio_thread(int argc, char **argv)
{
/* All frames processed */
priv->intstatus &= ~I_HMB_FRAME_IND;
sbus->intstatus &= ~I_HMB_FRAME_IND;
}
}
@ -808,7 +791,10 @@ int bcmf_sdio_thread(int argc, char **argv)
/* If we're done for now, turn off clock request. */
// TODO add wakelock
// bcmf_sdio_bus_sleep(priv, true);
// bcmf_sdio_bus_sleep(sbus, true);
}
return 0;
_info("Exit\n");
return 0;
}

View File

@ -1,12 +1,59 @@
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_H
#include "bcmf_sdio_regs.h"
#include "bcmf_sdio_core.h"
#include "bcmf_driver.h"
#include <stdint.h>
#include <stdbool.h>
#include <queue.h>
#include <semaphore.h>
#include <nuttx/sdio.h>
#include "bcmf_sdio_core.h"
/* sdio chip configuration structure */
struct bcmf_sdio_chip {
uint32_t ram_size;
uint32_t core_base[MAX_CORE_ID];
uint8_t *firmware_image;
unsigned int *firmware_image_size;
uint8_t *nvram_image;
unsigned int *nvram_image_size;
};
/* sdio bus structure extension */
struct bcmf_sdio_dev_s {
struct bcmf_bus_dev_s bus; /* Default bcmf bus structure */
FAR struct sdio_dev_s *sdio_dev; /* The SDIO device bound to this instance */
int minor; /* Device minor number */
struct bcmf_sdio_chip *chip; /* Chip specific configuration */
volatile bool ready; /* Current device status */
bool sleeping; /* Current sleep status */
int thread_id; /* Processing thread id */
sem_t thread_signal; /* Semaphore for processing thread event */
struct wdog_s *waitdog; /* Processing thread waitdog */
uint32_t backplane_current_addr; /* Current function 1 backplane base addr */
volatile bool irq_pending; /* True if interrupt is pending */
uint32_t intstatus; /* Copy of device current interrupt status */
uint8_t max_seq; /* Maximum transmit sequence allowed */
uint8_t tx_seq; /* Transmit sequence number (next) */
uint8_t rx_seq; /* Receive sequence number (expected) */
sem_t tx_queue_mutex; /* Lock for transmit queue */
dq_queue_t tx_queue; /* Queue of frames to tramsmit */
};
int bcmf_bus_sdio_initialize(FAR struct bcmf_dev_s *priv,
int minor, FAR struct sdio_dev_s *dev);
/* FIXME: Low level bus data transfer function
* To avoid bus error, len will be aligned to:
@ -14,16 +61,14 @@
* - upper 64 bytes block if len is greater than 64
*/
int bcmf_transfer_bytes(FAR struct bcmf_dev_s *priv, bool write,
int bcmf_transfer_bytes(FAR struct bcmf_sdio_dev_s *sbus, bool write,
uint8_t function, uint32_t address,
uint8_t *buf, unsigned int len);
int bcmf_read_reg(FAR struct bcmf_dev_s *priv, uint8_t function,
int bcmf_read_reg(FAR struct bcmf_sdio_dev_s *sbus, uint8_t function,
uint32_t address, uint8_t *reg);
int bcmf_write_reg(FAR struct bcmf_dev_s *priv, uint8_t function,
int bcmf_write_reg(FAR struct bcmf_sdio_dev_s *sbus, uint8_t function,
uint32_t address, uint8_t reg);
int bcmf_sem_wait(sem_t *sem, unsigned int timeout_ms);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_SDIO_H */

View File

@ -61,16 +61,13 @@
#define I_HMB_SW_MASK ( (uint32_t) 0x000000F0 )
#define I_HMB_FRAME_IND ( 1<<6 )
#define CHIP_STA_INTERFACE 0
#define CHIP_AP_INTERFACE 1
#define CHIP_P2P_INTERFACE 2
enum {
CHIPCOMMON_CORE_ID,
CHIPCOMMON_CORE_ID = 0,
DOT11MAC_CORE_ID,
SDIOD_CORE_ID,
WLAN_ARMCM3_CORE_ID,
SOCSRAM_CORE_ID
SOCSRAM_CORE_ID,
MAX_CORE_ID
};
struct chip_core_info {
@ -212,8 +209,4 @@ struct sdpcmd_regs {
uint16_t PAD[0x80];
};
#ifdef CONFIG_IEEE80211_BROADCOM_BCM43362
#include "bcmf_chip_43362.h"
#endif
#endif /* _BCMF_SDIO_CHIP_H_ */

View File

@ -52,7 +52,10 @@
#include "bcmf_sdio.h"
#include "bcmf_core.h"
#include "bcmf_sdpcm.h"
#include "bcmf_ioctl.h"
#include "bcmf_cdc.h"
#include "bcmf_utils.h"
#include "bcmf_sdio_regs.h"
/****************************************************************************
* Pre-processor Definitions
@ -70,26 +73,14 @@
#define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */
#define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */
/* CDC flag definitions */
#define CDC_DCMD_ERROR 0x01 /* 1=cmd failed */
#define CDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */
#define CDC_DCMD_IF_MASK 0xF000 /* I/F index */
#define CDC_DCMD_IF_SHIFT 12
#define CDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */
#define CDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */
#define CDC_DCMD_ID(flags) \
(((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT)
#define SDPCM_CONTROL_CHANNEL 0 /* Control */
#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication */
#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv */
#define SDPCM_GLOM_CHANNEL 3 /* Coalesced packets */
#define SDPCM_TEST_CHANNEL 15 /* Test/debug packets */
#define SDPCM_CONTROL_TIMEOUT_MS 1000
// TODO remove
void bcmf_hexdump(uint8_t *data, unsigned int len, unsigned long offset);
#define container_of(ptr, type, member) \
(type *)( (uint8_t *)(ptr) - offsetof(type,member) )
/****************************************************************************
* Private Types
@ -107,40 +98,18 @@ struct bcmf_sdpcm_header {
uint16_t padding;
};
struct bcmf_sdpcm_cdc_header {
uint32_t cmd; /* dongle command value */
uint32_t len; /* lower 16: output buflen;
* upper 16: input buflen (excludes header) */
uint32_t flags; /* flag defns given below */
uint32_t status; /* status code returned from the device */
};
struct bcmf_sdpcm_cdc_dcmd {
struct bcmf_sdpcm_header header;
struct bcmf_sdpcm_cdc_header cdc_header;
uint8_t data[0];
};
struct bcmf_sdpcm_frame {
struct bcmf_frame_s frame_header;
dq_entry_t list_entry;
struct bcmf_sdpcm_header header;
uint8_t data[0];
};
struct bcmf_sdpcm_cdc_frame {
dq_entry_t list_entry;
struct bcmf_sdpcm_header header;
struct bcmf_sdpcm_cdc_header cdc_header;
uint8_t data[0];
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static int bcmf_sdpcm_rxfail(FAR struct bcmf_dev_s *priv, bool retry);
static int bcmf_sdpcm_rxfail(FAR struct bcmf_sdio_dev_s *sbus, bool retry);
static int bcmf_sdpcm_process_header(FAR struct bcmf_dev_s *priv,
static int bcmf_sdpcm_process_header(FAR struct bcmf_sdio_dev_s *sbus,
struct bcmf_sdpcm_header *header);
/****************************************************************************
@ -151,51 +120,51 @@ static int bcmf_sdpcm_process_header(FAR struct bcmf_dev_s *priv,
* Private Functions
****************************************************************************/
int bcmf_sdpcm_rxfail(FAR struct bcmf_dev_s *priv, bool retry)
int bcmf_sdpcm_rxfail(FAR struct bcmf_sdio_dev_s *sbus, bool retry)
{
/* issue abort command for F2 through F0 */
bcmf_write_reg(priv, 0, SDIO_CCCR_IOABORT, 2);
bcmf_write_reg(sbus, 0, SDIO_CCCR_IOABORT, 2);
bcmf_write_reg(priv, 1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM);
bcmf_write_reg(sbus, 1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM);
/* TODO Wait until the packet has been flushed (device/FIFO stable) */
/* Send NAK to retry to read frame */
if (retry)
{
bcmf_write_sbregb(priv,
CORE_BUS_REG(priv->get_core_base_address(SDIOD_CORE_ID),
bcmf_write_sbregb(sbus,
CORE_BUS_REG(sbus->chip->core_base[SDIOD_CORE_ID],
tosbmailbox), SMB_NAK);
}
return 0;
}
int bcmf_sdpcm_process_header(FAR struct bcmf_dev_s *priv,
int bcmf_sdpcm_process_header(FAR struct bcmf_sdio_dev_s *sbus,
struct bcmf_sdpcm_header *header)
{
if (header->data_offset < sizeof(struct bcmf_sdpcm_header) ||
header->data_offset > header->size)
{
_err("Invalid data offset\n");
bcmf_sdpcm_rxfail(priv, false);
bcmf_sdpcm_rxfail(sbus, false);
return -ENXIO;
}
/* Update tx credits */
_info("update credit %x %x %x\n", header->credit,
priv->tx_seq, priv->max_seq);
// _info("update credit %x %x %x\n", header->credit,
// sbus->tx_seq, sbus->max_seq);
if (header->credit - priv->tx_seq > 0x40)
if (header->credit - sbus->tx_seq > 0x40)
{
_err("seq %d: max tx seq number error\n", priv->tx_seq);
priv->max_seq = priv->tx_seq + 2;
_err("seq %d: max tx seq number error\n", sbus->tx_seq);
sbus->max_seq = sbus->tx_seq + 2;
}
else
{
priv->max_seq = header->credit;
sbus->max_seq = header->credit;
}
return OK;
@ -207,16 +176,22 @@ int bcmf_sdpcm_process_header(FAR struct bcmf_dev_s *priv,
// FIXME remove
uint8_t tmp_buffer[1024];
uint8_t tmp_buffer_ctl[1024];
int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv)
{
int ret;
uint16_t len, checksum;
struct bcmf_sdpcm_header *header = (struct bcmf_sdpcm_header*)tmp_buffer;
struct bcmf_sdpcm_header *header;
struct bcmf_sdpcm_frame *sframe;
FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s*)priv->bus;
/* TODO request free frame buffer */
sframe = (struct bcmf_sdpcm_frame*)tmp_buffer;
header = (struct bcmf_sdpcm_header*)&sframe[1];
/* Read header */
ret = bcmf_transfer_bytes(priv, false, 2, 0, (uint8_t*)header, 4);
ret = bcmf_transfer_bytes(sbus, false, 2, 0, (uint8_t*)header, 4);
if (ret != OK)
{
_info("failread size\n");
@ -252,7 +227,7 @@ int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv)
/* Read remaining frame data */
// TODO allocate buffer
ret = bcmf_transfer_bytes(priv, false, 2, 0, (uint8_t*)header+4, len - 4);
ret = bcmf_transfer_bytes(sbus, false, 2, 0, (uint8_t*)header+4, len - 4);
if (ret != OK)
{
ret = -EIO;
@ -260,11 +235,11 @@ int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv)
}
// _info("Receive frame\n");
// bcmf_hexdump((uint8_t*)header, len, (unsigned int)header);
// bcmf_hexdump((uint8_t*)header, header->size, (unsigned int)header);
/* Process and validate header */
ret = bcmf_sdpcm_process_header(priv, header);
ret = bcmf_sdpcm_process_header(sbus, header);
if (ret != OK)
{
_err("Error while processing header %d\n", ret);
@ -272,70 +247,26 @@ int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv)
goto exit_free_frame;
}
/* Setup new frame structure */
sframe->frame_header.len = header->size;
sframe->frame_header.data = (uint8_t*)header + header->data_offset;
sframe->frame_header.base = (uint8_t*)header;
/* Process received frame content */
switch (header->channel & 0x0f)
{
case SDPCM_CONTROL_CHANNEL:
// _info("Control message\n");
/* Check frame */
if (header->size < sizeof(struct bcmf_sdpcm_header) +
sizeof(struct bcmf_sdpcm_cdc_header))
{
_err("Control frame too small\n");
ret = -EINVAL;
goto exit_free_frame;
}
struct bcmf_sdpcm_cdc_header *cdc_header =
(struct bcmf_sdpcm_cdc_header*)&header[1];
if (header->size < sizeof(struct bcmf_sdpcm_header) +
sizeof(struct bcmf_sdpcm_cdc_header) +
cdc_header->len ||
cdc_header->len > sizeof(tmp_buffer) -
sizeof(struct bcmf_sdpcm_header) -
sizeof(struct bcmf_sdpcm_cdc_header))
{
_err("Invalid control frame size\n");
ret = -EINVAL;
goto exit_free_frame;
}
// TODO check interface ?
if (cdc_header->flags >> CDC_DCMD_ID_SHIFT == priv->control_reqid)
{
/* Expected frame received, send it back to user */
// TODO allocate real buffer
memcpy(tmp_buffer_ctl, tmp_buffer, header->size);
priv->control_rxframe = tmp_buffer_ctl;
// priv->control_rxframe = (uint8_t*)header;
sem_post(&priv->control_timeout);
return OK;
}
else
{
_info("Got unexpected control frame\n");
ret = -EINVAL;
goto exit_free_frame;
}
ret = bcmf_cdc_process_control_frame(priv, &sframe->frame_header);
break;
case SDPCM_EVENT_CHANNEL:
_info("Event message\n");
bcmf_hexdump((uint8_t*)header, header->size, (unsigned long)header);
ret = OK;
ret = bcmf_cdc_process_event_frame(priv, &sframe->frame_header);
break;
case SDPCM_DATA_CHANNEL:
_info("Data message\n");
ret = OK;
ret = bcmf_cdc_process_data_frame(priv, &sframe->frame_header);
break;
default:
@ -350,23 +281,25 @@ exit_free_frame:
exit_free_abort:
// TODO free frame buffer
exit_abort:
bcmf_sdpcm_rxfail(priv, false);
bcmf_sdpcm_rxfail(sbus, false);
return ret;
}
int bcmf_sdpcm_sendframe(FAR struct bcmf_dev_s *priv)
{
int ret;
struct bcmf_sdpcm_frame *frame;
struct bcmf_sdpcm_frame *sframe;
struct bcmf_sdpcm_header *header;
FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s*)priv->bus;
if (priv->tx_queue.tail == NULL)
if (sbus->tx_queue.tail == NULL)
{
/* No more frames to send */
return -ENODATA;
}
if (priv->tx_seq == priv->max_seq)
if (sbus->tx_seq == sbus->max_seq)
{
// TODO handle this case
_err("No credit to send frame\n");
@ -374,23 +307,25 @@ int bcmf_sdpcm_sendframe(FAR struct bcmf_dev_s *priv)
}
if ((ret = sem_wait(&priv->tx_queue_mutex)) != OK)
if ((ret = sem_wait(&sbus->tx_queue_mutex)) != OK)
{
return ret;
}
frame = (struct bcmf_sdpcm_frame*)priv->tx_queue.tail;
sframe = container_of(sbus->tx_queue.tail,
struct bcmf_sdpcm_frame, list_entry);
header = (struct bcmf_sdpcm_header*)sframe->frame_header.base;
/* Set frame sequence id */
frame->header.sequence = priv->tx_seq++;
header->sequence = sbus->tx_seq++;
// _info("Send frame\n");
// bcmf_hexdump((uint8_t*)&frame->header, frame->header.size,
// (unsigned int)&frame->header);
// bcmf_hexdump(sframe->frame_header.base, sframe->frame_header.len,
// (unsigned long)sframe->frame_header.base);
ret = bcmf_transfer_bytes(priv, true, 2, 0, (uint8_t*)&frame->header,
frame->header.size);
ret = bcmf_transfer_bytes(sbus, true, 2, 0, sframe->frame_header.base,
sframe->frame_header.len);
if (ret != OK)
{
_info("fail send frame %d\n", ret);
@ -401,17 +336,17 @@ int bcmf_sdpcm_sendframe(FAR struct bcmf_dev_s *priv)
/* Frame sent, remove it from queue */
if (priv->tx_queue.head == &frame->list_entry)
if (sbus->tx_queue.head == &sframe->list_entry)
{
/* List is empty */
priv->tx_queue.head = NULL;
priv->tx_queue.tail = NULL;
sbus->tx_queue.head = NULL;
sbus->tx_queue.tail = NULL;
}
else
{
priv->tx_queue.tail = frame->list_entry.blink;
frame->list_entry.blink->flink = priv->tx_queue.head;
sbus->tx_queue.tail = sframe->list_entry.blink;
sframe->list_entry.blink->flink = sbus->tx_queue.head;
}
/* TODO free frame buffer */
@ -419,235 +354,110 @@ int bcmf_sdpcm_sendframe(FAR struct bcmf_dev_s *priv)
goto exit_post_sem;
exit_abort:
// bcmf_sdpcm_txfail(priv, false);
// bcmf_sdpcm_txfail(sbus, false);
exit_post_sem:
sem_post(&priv->tx_queue_mutex);
sem_post(&sbus->tx_queue_mutex);
return ret;
}
// FIXME remove
uint8_t tmp_buffer2[512];
uint8_t* bcmf_sdpcm_allocate_iovar(FAR struct bcmf_dev_s *priv, char *name,
uint8_t *data, uint32_t *len)
struct bcmf_frame_s* bcmf_sdpcm_allocate_frame(FAR struct bcmf_dev_s *priv,
unsigned int len, bool control, bool block)
{
uint32_t data_len;
uint16_t name_len;
unsigned int frame_len;
if (name)
{
name_len = strlen(name) + 1;
}
else
{
name_len = 0;
}
/* Integer overflow check */
if (data)
{
data_len = *len;
}
else
{
data_len = 0;
}
*len = 0;
// FIXME allocate buffer and use max_size instead of 512
if (data_len > 512-sizeof(struct bcmf_sdpcm_cdc_frame) ||
(data_len + name_len) > 512-sizeof(struct bcmf_sdpcm_cdc_frame))
if (len > 512)
{
return NULL;
}
// TODO allocate buffer len + sizeof(struct bcmf_sdpcm_cdc_frame)
frame_len = len + sizeof(struct bcmf_sdpcm_frame)
+ sizeof(struct bcmf_sdpcm_header);
if (!control)
{
/* Data frames needs 2 bytes padding */
/* Copy name string and data */
frame_len += 2;
}
memcpy(tmp_buffer2+sizeof(struct bcmf_sdpcm_cdc_frame), name, name_len);
memcpy(tmp_buffer2+sizeof(struct bcmf_sdpcm_cdc_frame)+name_len,
data, data_len);
if (frame_len > 512)
{
return NULL;
}
*len = sizeof(struct bcmf_sdpcm_cdc_frame)+name_len+data_len;
return tmp_buffer2;
}
// FIXME allocate buffer and use max_size instead of 512
// allocate buffer len + sizeof(struct bcmf_sdpcm_frame)
int bcmf_sdpcm_queue_frame(FAR struct bcmf_dev_s *priv, uint8_t channel,
uint8_t *data, uint32_t len)
{
int ret;
struct bcmf_sdpcm_frame *frame = (struct bcmf_sdpcm_frame*)data;
uint16_t frame_size = len - sizeof(frame->list_entry);
struct bcmf_sdpcm_frame *sframe = (struct bcmf_sdpcm_frame*)tmp_buffer2;
struct bcmf_sdpcm_header *header = (struct bcmf_sdpcm_header*)&sframe[1];
/* Prepare sw header */
memset(&frame->header, 0, sizeof(struct bcmf_sdpcm_header));
frame->header.size = frame_size;
frame->header.checksum = ~frame_size;
frame->header.channel = channel;
frame->header.data_offset = sizeof(struct bcmf_sdpcm_header);
memset(header, 0, sizeof(struct bcmf_sdpcm_header));
header->size = frame_len - sizeof(struct bcmf_sdpcm_frame);
header->checksum = ~header->size;
if (control)
{
header->channel = SDPCM_CONTROL_CHANNEL;
header->data_offset = sizeof(struct bcmf_sdpcm_header);
}
else
{
header->channel = SDPCM_DATA_CHANNEL;
header->data_offset = sizeof(struct bcmf_sdpcm_header)+2;
}
sframe->frame_header.len = header->size;
sframe->frame_header.base = (uint8_t*)header;
sframe->frame_header.data = (uint8_t*)header + header->data_offset;
return &sframe->frame_header;
}
int bcmf_sdpcm_queue_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame)
{
int ret;
FAR struct bcmf_sdio_dev_s *sbus = (FAR struct bcmf_sdio_dev_s*)priv->bus;
struct bcmf_sdpcm_frame *sframe = (struct bcmf_sdpcm_frame*)frame;
/* Add frame in tx queue */
if ((ret = sem_wait(&priv->tx_queue_mutex)) != OK)
if ((ret = sem_wait(&sbus->tx_queue_mutex)) != OK)
{
return ret;
}
if (priv->tx_queue.head == NULL)
if (sbus->tx_queue.head == NULL)
{
/* List is empty */
priv->tx_queue.head = &frame->list_entry;
priv->tx_queue.tail = &frame->list_entry;
sbus->tx_queue.head = &sframe->list_entry;
sbus->tx_queue.tail = &sframe->list_entry;
frame->list_entry.flink = &frame->list_entry;
frame->list_entry.blink = &frame->list_entry;
sframe->list_entry.flink = &sframe->list_entry;
sframe->list_entry.blink = &sframe->list_entry;
}
else
{
/* Insert entry at list head */
frame->list_entry.flink = priv->tx_queue.head;
frame->list_entry.blink = priv->tx_queue.tail;
sframe->list_entry.flink = sbus->tx_queue.head;
sframe->list_entry.blink = sbus->tx_queue.tail;
priv->tx_queue.head->blink = &frame->list_entry;
priv->tx_queue.head = &frame->list_entry;
sbus->tx_queue.head->blink = &sframe->list_entry;
sbus->tx_queue.head = &sframe->list_entry;
}
sem_post(&priv->tx_queue_mutex);
sem_post(&sbus->tx_queue_mutex);
/* Notify bcmf thread tx frame is ready */
sem_post(&priv->thread_signal);
sem_post(&sbus->thread_signal);
return OK;
}
int bcmf_sdpcm_send_cdc_frame(FAR struct bcmf_dev_s *priv, uint32_t cmd,
int ifidx, bool set, uint8_t *data, uint32_t len)
{
struct bcmf_sdpcm_cdc_frame *msg = (struct bcmf_sdpcm_cdc_frame*)data;
/* Setup cdc_dcmd header */
msg->cdc_header.cmd = cmd;
msg->cdc_header.len = len-sizeof(struct bcmf_sdpcm_cdc_frame);
msg->cdc_header.status = 0;
msg->cdc_header.flags = ++priv->control_reqid << CDC_DCMD_ID_SHIFT;
msg->cdc_header.flags |= ifidx << CDC_DCMD_IF_SHIFT;
if (set)
{
msg->cdc_header.flags |= CDC_DCMD_SET;
}
/* Queue frame */
return bcmf_sdpcm_queue_frame(priv, SDPCM_CONTROL_CHANNEL, data, len);
}
int bcmf_sdpcm_control_request(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, uint32_t cmd,
char *name, uint8_t *data, uint32_t *len)
{
int ret;
uint8_t *iovar_buf;
uint32_t out_len = *len;
uint32_t iovar_buf_len = *len;
*len = 0;
/* Take device control mutex */
if ((ret = sem_wait(&priv->control_mutex)) !=OK)
{
return ret;
}
/* Prepare control frame */
iovar_buf = bcmf_sdpcm_allocate_iovar(priv, name, data, &iovar_buf_len);
if (!iovar_buf)
{
_err("Cannot allocate iovar buf\n");
ret = -ENOMEM;
goto exit_sem_post;
}
/* Send control frame. iovar buffer is freed when sent */
ret = bcmf_sdpcm_send_cdc_frame(priv, cmd,
ifidx, set, iovar_buf, iovar_buf_len);
if (ret != OK)
{
// TODO free allocated iovar buffer here
goto exit_sem_post;
}
/* Wait for response */
priv->control_rxframe = NULL;
ret = bcmf_sem_wait(&priv->control_timeout, SDPCM_CONTROL_TIMEOUT_MS);
if (ret != OK)
{
_err("Error while waiting for control response %d\n", ret);
goto exit_sem_post;
}
/* Check frame status */
struct bcmf_sdpcm_cdc_dcmd *rxframe =
(struct bcmf_sdpcm_cdc_dcmd*)priv->control_rxframe;
priv->control_status = rxframe->cdc_header.status;
if (priv->control_status != 0)
{
_err("Invalid cdc status 0x%x\n", priv->control_status);
ret = -EIO;
goto exit_free_rx_frame;
}
if (!set)
{
/* Request sent, copy received data back */
if (rxframe->cdc_header.len > out_len)
{
_err("RX frame too big %d %d\n", rxframe->cdc_header.len, out_len);
memcpy(data, rxframe->data, out_len);
*len = out_len;
}
else
{
memcpy(data, rxframe->data, rxframe->cdc_header.len);
*len = rxframe->cdc_header.len;
}
}
exit_free_rx_frame:
// TODO free rxframe buffer */
priv->control_rxframe = NULL;
exit_sem_post:
sem_post(&priv->control_mutex);
return ret;
}
int bcmf_sdpcm_iovar_request(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, char *name,
uint8_t *data, uint32_t *len)
{
return bcmf_sdpcm_control_request(priv, ifidx, set,
set ? WLC_SET_VAR : WLC_GET_VAR, name,
data, len);
}
int bcmf_sdpcm_ioctl(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, uint32_t cmd,
uint8_t *data, uint32_t *len)
{
return bcmf_sdpcm_control_request(priv, ifidx, set, cmd, NULL, data, len);
}

View File

@ -7,12 +7,10 @@ int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv);
int bcmf_sdpcm_sendframe(FAR struct bcmf_dev_s *priv);
int bcmf_sdpcm_iovar_request(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, char *name,
uint8_t *data, uint32_t *len);
int bcmf_sdpcm_queue_frame(FAR struct bcmf_dev_s *priv,
struct bcmf_frame_s *frame);
int bcmf_sdpcm_ioctl(FAR struct bcmf_dev_s *priv,
uint32_t ifidx, bool set, uint32_t cmd,
uint8_t *data, uint32_t *len);
struct bcmf_frame_s* bcmf_sdpcm_allocate_frame(FAR struct bcmf_dev_s *priv,
unsigned int len, bool control, bool block);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_SDPCM_H */

View File

@ -1,11 +1,18 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <semaphore.h>
#include <debug.h>
#include <stdio.h>
#include "bcmf_utils.h"
#define LINE_LEN 16
/****************************************************************************
* Name: bcmf_hexdump
****************************************************************************/
void bcmf_hexdump(uint8_t *data, unsigned int len, unsigned long offset)
{
unsigned int i;
@ -33,4 +40,27 @@ void bcmf_hexdump(uint8_t *data, unsigned int len, unsigned long offset)
hex_line[3*LINE_LEN] = 0;
_info("%08x: %s%s\n", offset+i-char_count, hex_line, char_line);
}
}
/****************************************************************************
* Name: bcmf_sem_wait
****************************************************************************/
int bcmf_sem_wait(sem_t *sem, unsigned int timeout_ms)
{
struct timespec abstime;
/* Get the current time */
(void)clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_nsec += 1000 * 1000* timeout_ms;
if (abstime.tv_nsec >= 1000 * 1000 * 1000)
{
abstime.tv_sec++;
abstime.tv_nsec -= 1000 * 1000 * 1000;
}
return sem_timedwait(sem, &abstime);
}

View File

@ -0,0 +1,11 @@
#ifndef __DRIVERS_WIRELESS_IEEE80211_BCMF_UTILS_H
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_UTILS_H
#include <stdint.h>
#include <semaphore.h>
void bcmf_hexdump(uint8_t *data, unsigned int len, unsigned long offset);
int bcmf_sem_wait(sem_t *sem, unsigned int timeout_ms);
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_UTILS_H */