photon: add sdpcm tx basic support
This commit is contained in:
parent
11d3db5c35
commit
d646bde1f8
@ -44,6 +44,7 @@ ifeq ($(CONFIG_IEEE80211_BROADCOM_FULLMAC_SDIO),y)
|
||||
CSRCS += bcmf_sdio.c
|
||||
CSRCS += bcmf_core.c
|
||||
CSRCS += bcmf_sdpcm.c
|
||||
CSRCS += bcmf_hexdump.c
|
||||
CSRCS += mmc_sdio.c
|
||||
endif
|
||||
|
||||
|
@ -51,10 +51,6 @@
|
||||
#define SOCSRAM_BASE_ADDRESS 0x18004000 /* SOCSRAM core register region */
|
||||
#define BACKPLANE_ADDRESS_MASK 0x7FFF
|
||||
|
||||
#define CHIP_STA_INTERFACE 0
|
||||
#define CHIP_AP_INTERFACE 1
|
||||
#define CHIP_P2P_INTERFACE 2
|
||||
|
||||
/* Maximum value of bus data credit difference */
|
||||
#define CHIP_MAX_BUS_DATA_CREDIT_DIFF 7
|
||||
|
||||
|
@ -51,7 +51,7 @@ struct bcmf_dev_s
|
||||
uint32_t (*get_core_base_address)(unsigned int core); /* Get chip specific
|
||||
base address for evey cores */
|
||||
|
||||
sem_t sem; /* Semaphore for processing thread event */
|
||||
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 */
|
||||
@ -61,6 +61,15 @@ struct bcmf_dev_s
|
||||
uint8_t max_seq; /* Maximum transmit sequence allowed */
|
||||
uint8_t tx_seq; /* Transmit sequence number (next) */
|
||||
uint8_t rx_seq; /* Receive sequence number (expected) */
|
||||
|
||||
// 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 */
|
||||
|
||||
// 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 */
|
||||
};
|
||||
|
||||
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_DRIVER_H */
|
||||
|
36
drivers/wireless/ieee80211/bcmf_hexdump.c
Normal file
36
drivers/wireless/ieee80211/bcmf_hexdump.c
Normal file
@ -0,0 +1,36 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <debug.h>
|
||||
|
||||
#define LINE_LEN 16
|
||||
|
||||
void bcmf_hexdump(uint8_t *data, unsigned int len, unsigned long offset)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int char_count = 0;
|
||||
char char_line[20];
|
||||
char hex_line[64];
|
||||
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
if (char_count >= LINE_LEN) {
|
||||
/* Flush line */
|
||||
_info("%08x: %s%s\n", offset+i-char_count, hex_line, char_line);
|
||||
char_count = 0;
|
||||
}
|
||||
|
||||
sprintf(hex_line+3*char_count, "%02x ", data[i]);
|
||||
sprintf(char_line+char_count, "%c",
|
||||
data[i] < 0x20 || data[i] >= 0x7f? '.': data[i]);
|
||||
char_count ++;
|
||||
}
|
||||
|
||||
if (char_count > 0) {
|
||||
/* Flush last line */
|
||||
memset(hex_line+3*char_count, ' ', 3*(LINE_LEN-char_count));
|
||||
hex_line[3*LINE_LEN] = 0;
|
||||
_info("%08x: %s%s\n", offset+i-char_count, hex_line, char_line);
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@
|
||||
#include <string.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <queue.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/sdio.h>
|
||||
@ -59,6 +60,9 @@
|
||||
#include "bcmf_core.h"
|
||||
#include "bcmf_sdpcm.h"
|
||||
|
||||
// TODO remove
|
||||
#include "bcmf_ioctl.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
@ -114,7 +118,7 @@ int bcmf_oob_irq(int irq, FAR void *context, FAR void *arg)
|
||||
/* Signal bmcf thread */
|
||||
priv->irq_pending = true;
|
||||
|
||||
sem_post(&priv->sem);
|
||||
sem_post(&priv->thread_signal);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
@ -362,8 +366,8 @@ int bcmf_bus_setup_interrupts(FAR struct bcmf_dev_s *priv)
|
||||
|
||||
/* Redirect, configure and enable io for out-of-band interrupt signal */
|
||||
|
||||
ret = sdio_io_rw_direct(priv->sdio_dev, true, 0, SDIO_CCCR_BRCM_SEPINT,
|
||||
SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI, NULL);
|
||||
ret = bcmf_write_reg(priv, 0, SDIO_CCCR_BRCM_SEPINT,
|
||||
SDIO_SEPINT_MASK | SDIO_SEPINT_OE | SDIO_SEPINT_ACT_HI);
|
||||
if (ret != OK)
|
||||
{
|
||||
return ret;
|
||||
@ -527,6 +531,29 @@ int bcmf_write_reg(FAR struct bcmf_dev_s *priv, uint8_t function,
|
||||
return bcmf_transfer_bytes(priv, true, function, address, ®, 1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bcmf_sdio_initialize
|
||||
****************************************************************************/
|
||||
@ -555,11 +582,11 @@ int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
|
||||
priv->ready = false;
|
||||
priv->sleeping = true;
|
||||
|
||||
if ((ret = sem_init(&priv->sem, 0, 0)) != OK)
|
||||
if ((ret = sem_init(&priv->thread_signal, 0, 0)) != OK)
|
||||
{
|
||||
goto exit_free_priv;
|
||||
}
|
||||
if ((ret = sem_setprotocol(&priv->sem, SEM_PRIO_NONE)) != OK)
|
||||
if ((ret = sem_setprotocol(&priv->thread_signal, SEM_PRIO_NONE)) != OK)
|
||||
{
|
||||
goto exit_free_priv;
|
||||
}
|
||||
@ -571,6 +598,27 @@ int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
|
||||
goto exit_free_priv;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
goto exit_free_waitdog;
|
||||
}
|
||||
sq_init(&priv->tx_queue);
|
||||
|
||||
/* Initialize device hardware */
|
||||
|
||||
ret = bcmf_hwinitialize(priv);
|
||||
@ -632,6 +680,15 @@ int bcmf_sdio_initialize(int minor, FAR struct sdio_dev_s *dev)
|
||||
/* Device is up and running
|
||||
TODO Create a wlan device name and register network driver here */
|
||||
|
||||
// TODO remove: basic iovar test
|
||||
up_mdelay(2000);
|
||||
char fw_version[64];
|
||||
ret = bcmf_sdpcm_iovar_request(priv, CHIP_STA_INTERFACE, false,
|
||||
IOVAR_STR_VERSION, fw_version,
|
||||
sizeof(fw_version));
|
||||
_info("fw version %d\n", ret);
|
||||
|
||||
|
||||
return OK;
|
||||
|
||||
exit_uninit_hw:
|
||||
@ -675,7 +732,8 @@ void bcmf_sdio_waitdog_timeout(int argc, wdparm_t arg1, ...)
|
||||
FAR struct bcmf_dev_s *priv = g_sdio_priv;
|
||||
|
||||
/* Notify bcmf thread */
|
||||
sem_post(&priv->sem);
|
||||
|
||||
sem_post(&priv->thread_signal);
|
||||
}
|
||||
|
||||
int bcmf_sdio_thread(int argc, char **argv)
|
||||
@ -693,7 +751,7 @@ int bcmf_sdio_thread(int argc, char **argv)
|
||||
{
|
||||
/* Wait for event (device interrupt, user request or waitdog timer) */
|
||||
|
||||
ret = sem_wait(&priv->sem);
|
||||
ret = sem_wait(&priv->thread_signal);
|
||||
if (ret != OK)
|
||||
{
|
||||
_err("Error while waiting for semaphore\n");
|
||||
@ -715,8 +773,6 @@ int bcmf_sdio_thread(int argc, char **argv)
|
||||
|
||||
priv->irq_pending = false;
|
||||
|
||||
_info("process irq\n");
|
||||
|
||||
bcmf_read_sbregw(priv,
|
||||
CORE_BUS_REG(priv->get_core_base_address(SDIOD_CORE_ID),
|
||||
intstatus), &priv->intstatus);
|
||||
@ -748,10 +804,16 @@ int bcmf_sdio_thread(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO send all queued frames
|
||||
/* Send all queued frames */
|
||||
|
||||
do
|
||||
{
|
||||
ret = bcmf_sdpcm_sendframe(priv);
|
||||
} while (ret == OK);
|
||||
|
||||
/* If we're done for now, turn off clock request. */
|
||||
|
||||
// TODO add wakelock
|
||||
bcmf_sdio_bus_sleep(priv, true);
|
||||
}
|
||||
return 0;
|
||||
|
@ -24,4 +24,6 @@ int bcmf_read_reg(FAR struct bcmf_dev_s *priv, uint8_t function,
|
||||
int bcmf_write_reg(FAR struct bcmf_dev_s *priv, 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 */
|
@ -61,6 +61,10 @@
|
||||
#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,
|
||||
DOT11MAC_CORE_ID,
|
||||
|
@ -45,10 +45,18 @@
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <queue.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#include "bcmf_sdio.h"
|
||||
#include "bcmf_core.h"
|
||||
#include "bcmf_sdpcm.h"
|
||||
#include "bcmf_ioctl.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* SDA_FRAMECTRL */
|
||||
#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */
|
||||
@ -57,25 +65,78 @@
|
||||
#define SFC_ABORTALL (1 << 3) /* Abort all in-progress frames */
|
||||
|
||||
/* tosbmailbox bits corresponding to intstatus bits */
|
||||
#define SMB_NAK (1 << 0) /* Frame NAK */
|
||||
#define SMB_NAK (1 << 0) /* Frame NAK */
|
||||
#define SMB_INT_ACK (1 << 1) /* Host Interrupt ACK */
|
||||
#define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */
|
||||
#define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */
|
||||
|
||||
/****************************************************************************
|
||||
* 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 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);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct bcmf_sdpcm_header {
|
||||
uint16_t size;
|
||||
uint16_t checksum;
|
||||
uint8_t sequence;
|
||||
uint8_t channel;
|
||||
uint8_t next_length;
|
||||
uint8_t data_offset;
|
||||
uint8_t flow_control;
|
||||
uint8_t credit;
|
||||
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_frame {
|
||||
dq_entry_t list_entry;
|
||||
struct bcmf_sdpcm_header header;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
struct bcmf_sdpcm_cdc_dcmd {
|
||||
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_process_header(FAR struct bcmf_dev_s *priv,
|
||||
struct bcmf_sdpcm_header *header);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
@ -105,19 +166,11 @@ int bcmf_sdpcm_rxfail(FAR struct bcmf_dev_s *priv, bool retry)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
int bcmf_sdpcm_process_header(FAR struct bcmf_dev_s *priv,
|
||||
struct bcmf_sdpcm_header *header)
|
||||
{
|
||||
uint16_t len;
|
||||
|
||||
len = header->frametag[0];
|
||||
|
||||
if (header->data_offset < sizeof(struct bcmf_sdpcm_header) ||
|
||||
header->data_offset > len)
|
||||
header->data_offset > header->size)
|
||||
{
|
||||
_err("Invalid data offset\n");
|
||||
bcmf_sdpcm_rxfail(priv, false);
|
||||
@ -142,6 +195,10 @@ int bcmf_sdpcm_process_header(FAR struct bcmf_dev_s *priv,
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
// FIXME remove
|
||||
uint8_t tmp_buffer[512];
|
||||
int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv)
|
||||
@ -160,8 +217,8 @@ int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv)
|
||||
goto exit_abort;
|
||||
}
|
||||
|
||||
len = header->frametag[0];
|
||||
checksum = header->frametag[1];
|
||||
len = header->size;
|
||||
checksum = header->checksum;
|
||||
|
||||
/* All zero means no more to read */
|
||||
|
||||
@ -194,6 +251,9 @@ int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv)
|
||||
goto exit_abort;
|
||||
}
|
||||
|
||||
_info("Receive frame\n");
|
||||
bcmf_hexdump((uint8_t*)header, len, (unsigned int)header);
|
||||
|
||||
/* Process and validate header */
|
||||
|
||||
ret = bcmf_sdpcm_process_header(priv, header);
|
||||
@ -209,9 +269,242 @@ exit_abort:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bcmf_sdpcm_iovar_data_get(FAR struct bcmf_dev_s *priv, char *name,
|
||||
void *data, unsigned int len)
|
||||
int bcmf_sdpcm_sendframe(FAR struct bcmf_dev_s *priv)
|
||||
{
|
||||
// TODO implement
|
||||
return -EINVAL;
|
||||
int ret;
|
||||
struct bcmf_sdpcm_frame *frame;
|
||||
|
||||
if (priv->tx_queue.tail == NULL)
|
||||
{
|
||||
/* No more frames to send */
|
||||
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
if (priv->tx_seq == priv->max_seq)
|
||||
{
|
||||
// TODO handle this case
|
||||
_err("No credit to send frame\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
|
||||
if ((ret = sem_wait(&priv->tx_queue_mutex)) != OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
frame = (struct bcmf_sdpcm_frame*)priv->tx_queue.tail;
|
||||
|
||||
/* Set frame sequence id */
|
||||
|
||||
frame->header.sequence = priv->tx_seq++;
|
||||
|
||||
_info("Send frame\n");
|
||||
bcmf_hexdump((uint8_t*)&frame->header, frame->header.size,
|
||||
(unsigned int)&frame->header);
|
||||
|
||||
ret = bcmf_transfer_bytes(priv, true, 2, 0, (uint8_t*)&frame->header,
|
||||
frame->header.size);
|
||||
if (ret != OK)
|
||||
{
|
||||
_info("fail send frame %d\n", ret);
|
||||
ret = -EIO;
|
||||
goto exit_abort;
|
||||
// TODO handle retry count and remove frame from queue + abort TX
|
||||
}
|
||||
|
||||
/* Frame sent, remove it from queue */
|
||||
|
||||
if (priv->tx_queue.head == &frame->list_entry)
|
||||
{
|
||||
/* List is empty */
|
||||
|
||||
priv->tx_queue.head = NULL;
|
||||
priv->tx_queue.tail = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->tx_queue.tail = frame->list_entry.blink;
|
||||
frame->list_entry.blink->flink = priv->tx_queue.head;
|
||||
}
|
||||
|
||||
/* TODO free frame buffer */
|
||||
|
||||
goto exit_post_sem;
|
||||
|
||||
exit_abort:
|
||||
// bcmf_sdpcm_txfail(priv, false);
|
||||
exit_post_sem:
|
||||
sem_post(&priv->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,
|
||||
char *data, uint32_t *len)
|
||||
{
|
||||
uint32_t data_len;
|
||||
uint16_t name_len = strlen(name) + 1;
|
||||
|
||||
if (!data)
|
||||
{
|
||||
data_len = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
data_len = *len;
|
||||
}
|
||||
|
||||
// FIXME allocate buffer and use max_size instead of 512
|
||||
if (data_len > 512-sizeof(struct bcmf_sdpcm_cdc_dcmd) ||
|
||||
(data_len + name_len) > 512-sizeof(struct bcmf_sdpcm_cdc_dcmd))
|
||||
{
|
||||
*len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// TODO allocate buffer
|
||||
|
||||
/* Copy name string and data */
|
||||
|
||||
memcpy(tmp_buffer2+sizeof(struct bcmf_sdpcm_cdc_dcmd), name, name_len);
|
||||
memcpy(tmp_buffer2+sizeof(struct bcmf_sdpcm_cdc_dcmd)+name_len,
|
||||
data, data_len);
|
||||
|
||||
*len = sizeof(struct bcmf_sdpcm_cdc_dcmd)+name_len+data_len;
|
||||
return tmp_buffer2;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Add frame in tx queue */
|
||||
|
||||
if ((ret = sem_wait(&priv->tx_queue_mutex)) != OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (priv->tx_queue.head == NULL)
|
||||
{
|
||||
/* List is empty */
|
||||
|
||||
priv->tx_queue.head = &frame->list_entry;
|
||||
priv->tx_queue.tail = &frame->list_entry;
|
||||
|
||||
frame->list_entry.flink = &frame->list_entry;
|
||||
frame->list_entry.blink = &frame->list_entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Insert entry at list head */
|
||||
|
||||
frame->list_entry.flink = priv->tx_queue.head;
|
||||
frame->list_entry.blink = priv->tx_queue.tail;
|
||||
|
||||
priv->tx_queue.head->blink = &frame->list_entry;
|
||||
priv->tx_queue.head = &frame->list_entry;
|
||||
}
|
||||
|
||||
sem_post(&priv->tx_queue_mutex);
|
||||
|
||||
/* Notify bcmf thread tx frame is ready */
|
||||
|
||||
sem_post(&priv->thread_signal);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int bcmf_sdpcm_send_dcmd(FAR struct bcmf_dev_s *priv, uint32_t cmd,
|
||||
int ifidx, bool set, uint8_t *data, uint32_t len)
|
||||
{
|
||||
struct bcmf_sdpcm_cdc_dcmd *msg = (struct bcmf_sdpcm_cdc_dcmd*)data;
|
||||
|
||||
/* Setup cdc_dcmd header */
|
||||
|
||||
msg->cdc_header.cmd = cmd;
|
||||
msg->cdc_header.len = len-sizeof(struct bcmf_sdpcm_cdc_dcmd);
|
||||
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_iovar_request(FAR struct bcmf_dev_s *priv,
|
||||
uint32_t ifidx, bool set, char *name,
|
||||
char *data, uint32_t len)
|
||||
{
|
||||
int ret;
|
||||
uint8_t *iovar_buf;
|
||||
uint32_t iovar_buf_len = len;
|
||||
|
||||
/* 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 */
|
||||
|
||||
ret = bcmf_sdpcm_send_dcmd(priv, set ? WLC_SET_VAR : WLC_GET_VAR,
|
||||
ifidx, set, iovar_buf, iovar_buf_len);
|
||||
if (ret != OK)
|
||||
{
|
||||
goto exit_free_iovar;
|
||||
}
|
||||
|
||||
/* Wait for response */
|
||||
|
||||
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_free_iovar;
|
||||
}
|
||||
|
||||
if (!set)
|
||||
{
|
||||
/* Request sent, copy received data back */
|
||||
|
||||
memcpy(data, iovar_buf+sizeof(struct bcmf_sdpcm_cdc_dcmd), len);
|
||||
}
|
||||
|
||||
exit_free_iovar:
|
||||
// TODO free allocated buffer here
|
||||
exit_sem_post:
|
||||
sem_post(&priv->control_mutex);
|
||||
return ret;
|
||||
}
|
@ -2,34 +2,13 @@
|
||||
#define __DRIVERS_WIRELESS_IEEE80211_BCMF_SDPCM_H
|
||||
|
||||
#include "bcmf_driver.h"
|
||||
#include <stdint.h>
|
||||
|
||||
struct bcmf_sdpcm_header {
|
||||
uint16_t frametag[2];
|
||||
uint8_t sequence;
|
||||
uint8_t channel_flags;
|
||||
uint8_t next_length;
|
||||
uint8_t data_offset;
|
||||
uint8_t flow_control;
|
||||
uint8_t credit;
|
||||
uint16_t padding;
|
||||
};
|
||||
|
||||
struct bcmf_sdpcm_cdc_dcmd {
|
||||
struct bcmf_sdpcm_header 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 */
|
||||
};
|
||||
|
||||
int bcmf_sdpcm_process_header(FAR struct bcmf_dev_s *priv,
|
||||
struct bcmf_sdpcm_header *header);
|
||||
|
||||
int bcmf_sdpcm_readframe(FAR struct bcmf_dev_s *priv);
|
||||
|
||||
int bcmf_sdpcm_iovar_data_get(FAR struct bcmf_dev_s *priv, char *name,
|
||||
void *data, unsigned int len);
|
||||
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,
|
||||
char *data, uint32_t len);
|
||||
|
||||
#endif /* __DRIVERS_WIRELESS_IEEE80211_BCMF_SDPCM_H */
|
Loading…
Reference in New Issue
Block a user