Bluetooth: hci_raw: Move buffer management to common place
This makes hci_raw to manage RX and TX buffers so its logic don't have to be replicated on each an every driver/application, it also makes it simpler to deal with extra headers for H:4 mode since that then can be done at earlier at buffer allocation. Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
parent
05f0816f93
commit
4b622afbb3
8 changed files with 171 additions and 270 deletions
|
@ -32,6 +32,8 @@ enum bt_buf_type {
|
||||||
BT_BUF_ACL_OUT,
|
BT_BUF_ACL_OUT,
|
||||||
/** Incoming ACL data */
|
/** Incoming ACL data */
|
||||||
BT_BUF_ACL_IN,
|
BT_BUF_ACL_IN,
|
||||||
|
/** H:4 data */
|
||||||
|
BT_BUF_H4,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Minimum amount of user data size for buffers passed to the stack. */
|
/** Minimum amount of user data size for buffers passed to the stack. */
|
||||||
|
@ -61,6 +63,22 @@ enum bt_buf_type {
|
||||||
*/
|
*/
|
||||||
struct net_buf *bt_buf_get_rx(enum bt_buf_type type, s32_t timeout);
|
struct net_buf *bt_buf_get_rx(enum bt_buf_type type, s32_t timeout);
|
||||||
|
|
||||||
|
/** Allocate a buffer for outgoing data
|
||||||
|
*
|
||||||
|
* This will set the buffer type so bt_buf_set_type() does not need to
|
||||||
|
* be explicitly called before bt_send().
|
||||||
|
*
|
||||||
|
* @param type Type of buffer. Only BT_BUF_CMD, BT_BUF_ACL_OUT or
|
||||||
|
* BT_BUF_H4, when operating on H:4 mode, are allowed.
|
||||||
|
* @param timeout Timeout in milliseconds, or one of the special values
|
||||||
|
* K_NO_WAIT and K_FOREVER.
|
||||||
|
* @param data Initial data to append to buffer.
|
||||||
|
* @param size Initial data size.
|
||||||
|
* @return A new buffer.
|
||||||
|
*/
|
||||||
|
struct net_buf *bt_buf_get_tx(enum bt_buf_type type, s32_t timeout,
|
||||||
|
const void *data, size_t size);
|
||||||
|
|
||||||
/** Allocate a buffer for an HCI Command Complete/Status Event
|
/** Allocate a buffer for an HCI Command Complete/Status Event
|
||||||
*
|
*
|
||||||
* This will set the buffer type so bt_buf_set_type() does not need to
|
* This will set the buffer type so bt_buf_set_type() does not need to
|
||||||
|
|
|
@ -21,6 +21,23 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_TX_BUFFER_SIZE)
|
||||||
|
#define BT_L2CAP_MTU (CONFIG_BT_CTLR_TX_BUFFER_SIZE - BT_L2CAP_HDR_SIZE)
|
||||||
|
#else
|
||||||
|
#define BT_L2CAP_MTU 65 /* 64-byte public key + opcode */
|
||||||
|
#endif /* CONFIG_BT_CTLR */
|
||||||
|
|
||||||
|
/** Data size needed for ACL buffers */
|
||||||
|
#define BT_BUF_ACL_SIZE BT_L2CAP_BUF_SIZE(BT_L2CAP_MTU)
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_TX_BUFFERS)
|
||||||
|
#define BT_HCI_ACL_COUNT CONFIG_BT_CTLR_TX_BUFFERS
|
||||||
|
#else
|
||||||
|
#define BT_HCI_ACL_COUNT 6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BT_BUF_TX_SIZE MAX(BT_BUF_RX_SIZE, BT_BUF_ACL_SIZE)
|
||||||
|
|
||||||
/** @brief Send packet to the Bluetooth controller
|
/** @brief Send packet to the Bluetooth controller
|
||||||
*
|
*
|
||||||
* Send packet to the Bluetooth controller. Caller needs to
|
* Send packet to the Bluetooth controller. Caller needs to
|
||||||
|
|
|
@ -127,29 +127,6 @@ static void rpmsg_service_unbind(struct rpmsg_endpoint *ep)
|
||||||
|
|
||||||
static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE);
|
static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE);
|
||||||
static struct k_thread tx_thread_data;
|
static struct k_thread tx_thread_data;
|
||||||
|
|
||||||
/* HCI command buffers */
|
|
||||||
#define CMD_BUF_SIZE BT_BUF_RX_SIZE
|
|
||||||
NET_BUF_POOL_FIXED_DEFINE(cmd_tx_pool, CONFIG_BT_HCI_CMD_COUNT, CMD_BUF_SIZE,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_TX_BUFFER_SIZE)
|
|
||||||
#define BT_L2CAP_MTU (CONFIG_BT_CTLR_TX_BUFFER_SIZE - BT_L2CAP_HDR_SIZE)
|
|
||||||
#else
|
|
||||||
#define BT_L2CAP_MTU 65 /* 64-byte public key + opcode */
|
|
||||||
#endif /* CONFIG_BT_CTLR */
|
|
||||||
|
|
||||||
/** Data size needed for ACL buffers */
|
|
||||||
#define BT_BUF_ACL_SIZE BT_L2CAP_BUF_SIZE(BT_L2CAP_MTU)
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_TX_BUFFERS)
|
|
||||||
#define TX_BUF_COUNT CONFIG_BT_CTLR_TX_BUFFERS
|
|
||||||
#else
|
|
||||||
#define TX_BUF_COUNT 6
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NET_BUF_POOL_FIXED_DEFINE(acl_tx_pool, TX_BUF_COUNT, BT_BUF_ACL_SIZE, NULL);
|
|
||||||
|
|
||||||
static K_FIFO_DEFINE(tx_queue);
|
static K_FIFO_DEFINE(tx_queue);
|
||||||
|
|
||||||
#define HCI_RPMSG_CMD 0x01
|
#define HCI_RPMSG_CMD 0x01
|
||||||
|
@ -159,35 +136,30 @@ static K_FIFO_DEFINE(tx_queue);
|
||||||
|
|
||||||
static struct net_buf *hci_rpmsg_cmd_recv(u8_t *data, size_t remaining)
|
static struct net_buf *hci_rpmsg_cmd_recv(u8_t *data, size_t remaining)
|
||||||
{
|
{
|
||||||
struct bt_hci_cmd_hdr hdr;
|
struct bt_hci_cmd_hdr *hdr = (void *)data;
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
|
|
||||||
if (remaining < sizeof(hdr)) {
|
if (remaining < sizeof(*hdr)) {
|
||||||
LOG_ERR("Not enought data for command header");
|
LOG_ERR("Not enought data for command header");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = net_buf_alloc(&cmd_tx_pool, K_NO_WAIT);
|
buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, hdr, sizeof(*hdr));
|
||||||
if (buf) {
|
if (buf) {
|
||||||
bt_buf_set_type(buf, BT_BUF_CMD);
|
data += sizeof(*hdr);
|
||||||
|
remaining -= sizeof(*hdr);
|
||||||
memcpy((void *)&hdr, data, sizeof(hdr));
|
|
||||||
data += sizeof(hdr);
|
|
||||||
remaining -= sizeof(hdr);
|
|
||||||
|
|
||||||
net_buf_add_mem(buf, &hdr, sizeof(hdr));
|
|
||||||
} else {
|
} else {
|
||||||
LOG_ERR("No available command buffers!");
|
LOG_ERR("No available command buffers!");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remaining != hdr.param_len) {
|
if (remaining != hdr->param_len) {
|
||||||
LOG_ERR("Command payload length is not correct");
|
LOG_ERR("Command payload length is not correct");
|
||||||
net_buf_unref(buf);
|
net_buf_unref(buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DBG("len %u", hdr.param_len);
|
LOG_DBG("len %u", hdr->param_len);
|
||||||
net_buf_add_mem(buf, data, remaining);
|
net_buf_add_mem(buf, data, remaining);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
|
@ -195,29 +167,24 @@ static struct net_buf *hci_rpmsg_cmd_recv(u8_t *data, size_t remaining)
|
||||||
|
|
||||||
static struct net_buf *hci_rpmsg_acl_recv(u8_t *data, size_t remaining)
|
static struct net_buf *hci_rpmsg_acl_recv(u8_t *data, size_t remaining)
|
||||||
{
|
{
|
||||||
struct bt_hci_acl_hdr hdr;
|
struct bt_hci_acl_hdr *hdr = (void *)data;
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
|
|
||||||
if (remaining < sizeof(hdr)) {
|
if (remaining < sizeof(*hdr)) {
|
||||||
LOG_ERR("Not enought data for ACL header");
|
LOG_ERR("Not enought data for ACL header");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = net_buf_alloc(&acl_tx_pool, K_NO_WAIT);
|
buf = bt_buf_get_tx(BT_BUF_ACL_OUT, K_NO_WAIT, hdr, sizeof(*hdr));
|
||||||
if (buf) {
|
if (buf) {
|
||||||
bt_buf_set_type(buf, BT_BUF_ACL_OUT);
|
data += sizeof(*hdr);
|
||||||
|
remaining -= sizeof(*hdr);
|
||||||
memcpy((void *)&hdr, data, sizeof(hdr));
|
|
||||||
data += sizeof(hdr);
|
|
||||||
remaining -= sizeof(hdr);
|
|
||||||
|
|
||||||
net_buf_add_mem(buf, &hdr, sizeof(hdr));
|
|
||||||
} else {
|
} else {
|
||||||
LOG_ERR("No available ACL buffers!");
|
LOG_ERR("No available ACL buffers!");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remaining != sys_le16_to_cpu(hdr.len)) {
|
if (remaining != sys_le16_to_cpu(hdr->len)) {
|
||||||
LOG_ERR("ACL payload length is not correct");
|
LOG_ERR("ACL payload length is not correct");
|
||||||
net_buf_unref(buf);
|
net_buf_unref(buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -71,27 +71,6 @@ const static struct spi_buf_set tx_bufs = {
|
||||||
/* HCI buffer pools */
|
/* HCI buffer pools */
|
||||||
#define CMD_BUF_SIZE BT_BUF_RX_SIZE
|
#define CMD_BUF_SIZE BT_BUF_RX_SIZE
|
||||||
|
|
||||||
NET_BUF_POOL_FIXED_DEFINE(cmd_tx_pool, CONFIG_BT_HCI_CMD_COUNT, CMD_BUF_SIZE,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR)
|
|
||||||
#define BT_L2CAP_MTU (CONFIG_BT_CTLR_TX_BUFFER_SIZE - \
|
|
||||||
BT_L2CAP_HDR_SIZE)
|
|
||||||
#else
|
|
||||||
#define BT_L2CAP_MTU 65 /* 64-byte public key + opcode */
|
|
||||||
#endif /* CONFIG_BT_CTLR */
|
|
||||||
|
|
||||||
/* Data size needed for ACL buffers */
|
|
||||||
#define BT_BUF_ACL_SIZE BT_L2CAP_BUF_SIZE(BT_L2CAP_MTU)
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_TX_BUFFERS)
|
|
||||||
#define TX_BUF_COUNT CONFIG_BT_CTLR_TX_BUFFERS
|
|
||||||
#else
|
|
||||||
#define TX_BUF_COUNT 6
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NET_BUF_POOL_FIXED_DEFINE(acl_tx_pool, TX_BUF_COUNT, BT_BUF_ACL_SIZE, NULL);
|
|
||||||
|
|
||||||
static struct device *spi_hci_dev;
|
static struct device *spi_hci_dev;
|
||||||
static struct spi_config spi_cfg = {
|
static struct spi_config spi_cfg = {
|
||||||
.operation = SPI_WORD_SET(8) | SPI_OP_MODE_SLAVE,
|
.operation = SPI_WORD_SET(8) | SPI_OP_MODE_SLAVE,
|
||||||
|
@ -216,13 +195,9 @@ static void bt_tx_thread(void *p1, void *p2, void *p3)
|
||||||
|
|
||||||
switch (rxmsg[PACKET_TYPE]) {
|
switch (rxmsg[PACKET_TYPE]) {
|
||||||
case HCI_CMD:
|
case HCI_CMD:
|
||||||
memcpy(&cmd_hdr, &rxmsg[1], sizeof(cmd_hdr));
|
buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, &rxmsg[1],
|
||||||
|
sizeof(cmd_hdr));
|
||||||
buf = net_buf_alloc(&cmd_tx_pool, K_NO_WAIT);
|
|
||||||
if (buf) {
|
if (buf) {
|
||||||
bt_buf_set_type(buf, BT_BUF_CMD);
|
|
||||||
net_buf_add_mem(buf, &cmd_hdr,
|
|
||||||
sizeof(cmd_hdr));
|
|
||||||
net_buf_add_mem(buf, &rxmsg[4],
|
net_buf_add_mem(buf, &rxmsg[4],
|
||||||
cmd_hdr.param_len);
|
cmd_hdr.param_len);
|
||||||
} else {
|
} else {
|
||||||
|
@ -231,13 +206,9 @@ static void bt_tx_thread(void *p1, void *p2, void *p3)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case HCI_ACL:
|
case HCI_ACL:
|
||||||
memcpy(&acl_hdr, &rxmsg[1], sizeof(acl_hdr));
|
buf = bt_buf_get_tx(BT_BUF_ACL_OUT, K_NO_WAIT,
|
||||||
|
&rxmsg[1], sizeof(acl_hdr));
|
||||||
buf = net_buf_alloc(&acl_tx_pool, K_NO_WAIT);
|
|
||||||
if (buf) {
|
if (buf) {
|
||||||
bt_buf_set_type(buf, BT_BUF_ACL_OUT);
|
|
||||||
net_buf_add_mem(buf, &acl_hdr,
|
|
||||||
sizeof(acl_hdr));
|
|
||||||
net_buf_add_mem(buf, &rxmsg[5],
|
net_buf_add_mem(buf, &rxmsg[5],
|
||||||
sys_le16_to_cpu(acl_hdr.len));
|
sys_le16_to_cpu(acl_hdr.len));
|
||||||
} else {
|
} else {
|
||||||
|
@ -315,8 +286,7 @@ void main(void)
|
||||||
k_thread_name_set(&bt_tx_thread_data, "bt_tx_thread");
|
k_thread_name_set(&bt_tx_thread_data, "bt_tx_thread");
|
||||||
|
|
||||||
/* Send a vendor event to announce that the slave is initialized */
|
/* Send a vendor event to announce that the slave is initialized */
|
||||||
buf = net_buf_alloc(&cmd_tx_pool, K_FOREVER);
|
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
|
||||||
bt_buf_set_type(buf, BT_BUF_EVT);
|
|
||||||
evt_hdr = net_buf_add(buf, sizeof(*evt_hdr));
|
evt_hdr = net_buf_add(buf, sizeof(*evt_hdr));
|
||||||
evt_hdr->evt = BT_HCI_EVT_VENDOR;
|
evt_hdr->evt = BT_HCI_EVT_VENDOR;
|
||||||
evt_hdr->len = 2U;
|
evt_hdr->len = 2U;
|
||||||
|
|
|
@ -33,29 +33,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||||
static struct device *hci_uart_dev;
|
static struct device *hci_uart_dev;
|
||||||
static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE);
|
static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE);
|
||||||
static struct k_thread tx_thread_data;
|
static struct k_thread tx_thread_data;
|
||||||
|
|
||||||
/* HCI command buffers */
|
|
||||||
#define CMD_BUF_SIZE BT_BUF_RX_SIZE
|
|
||||||
NET_BUF_POOL_FIXED_DEFINE(cmd_tx_pool, CONFIG_BT_HCI_CMD_COUNT, CMD_BUF_SIZE,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_TX_BUFFER_SIZE)
|
|
||||||
#define BT_L2CAP_MTU (CONFIG_BT_CTLR_TX_BUFFER_SIZE - BT_L2CAP_HDR_SIZE)
|
|
||||||
#else
|
|
||||||
#define BT_L2CAP_MTU 65 /* 64-byte public key + opcode */
|
|
||||||
#endif /* CONFIG_BT_CTLR */
|
|
||||||
|
|
||||||
/** Data size needed for ACL buffers */
|
|
||||||
#define BT_BUF_ACL_SIZE BT_L2CAP_BUF_SIZE(BT_L2CAP_MTU)
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_TX_BUFFERS)
|
|
||||||
#define TX_BUF_COUNT CONFIG_BT_CTLR_TX_BUFFERS
|
|
||||||
#else
|
|
||||||
#define TX_BUF_COUNT 6
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NET_BUF_POOL_FIXED_DEFINE(acl_tx_pool, TX_BUF_COUNT, BT_BUF_ACL_SIZE, NULL);
|
|
||||||
|
|
||||||
static K_FIFO_DEFINE(tx_queue);
|
static K_FIFO_DEFINE(tx_queue);
|
||||||
|
|
||||||
#define H4_CMD 0x01
|
#define H4_CMD 0x01
|
||||||
|
@ -115,11 +92,8 @@ static struct net_buf *h4_cmd_recv(int *remaining)
|
||||||
|
|
||||||
*remaining = hdr.param_len;
|
*remaining = hdr.param_len;
|
||||||
|
|
||||||
buf = net_buf_alloc(&cmd_tx_pool, K_NO_WAIT);
|
buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, &hdr, sizeof(hdr));
|
||||||
if (buf) {
|
if (!buf) {
|
||||||
bt_buf_set_type(buf, BT_BUF_CMD);
|
|
||||||
net_buf_add_mem(buf, &hdr, sizeof(hdr));
|
|
||||||
} else {
|
|
||||||
LOG_ERR("No available command buffers!");
|
LOG_ERR("No available command buffers!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,11 +110,8 @@ static struct net_buf *h4_acl_recv(int *remaining)
|
||||||
/* We can ignore the return value since we pass len == min */
|
/* We can ignore the return value since we pass len == min */
|
||||||
h4_read(hci_uart_dev, (void *)&hdr, sizeof(hdr), sizeof(hdr));
|
h4_read(hci_uart_dev, (void *)&hdr, sizeof(hdr), sizeof(hdr));
|
||||||
|
|
||||||
buf = net_buf_alloc(&acl_tx_pool, K_NO_WAIT);
|
buf = bt_buf_get_tx(BT_BUF_ACL_OUT, K_NO_WAIT, &hdr, sizeof(hdr));
|
||||||
if (buf) {
|
if (!buf) {
|
||||||
bt_buf_set_type(buf, BT_BUF_ACL_OUT);
|
|
||||||
net_buf_add_mem(buf, &hdr, sizeof(hdr));
|
|
||||||
} else {
|
|
||||||
LOG_ERR("No available ACL buffers!");
|
LOG_ERR("No available ACL buffers!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <drivers/bluetooth/hci_driver.h>
|
#include <drivers/bluetooth/hci_driver.h>
|
||||||
#include <bluetooth/hci_raw.h>
|
#include <bluetooth/hci_raw.h>
|
||||||
|
#include <bluetooth/l2cap.h>
|
||||||
|
|
||||||
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
|
||||||
#define LOG_MODULE_NAME bt_hci_raw
|
#define LOG_MODULE_NAME bt_hci_raw
|
||||||
|
@ -37,6 +38,9 @@ static u8_t raw_mode;
|
||||||
NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, CONFIG_BT_RX_BUF_COUNT,
|
NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, CONFIG_BT_RX_BUF_COUNT,
|
||||||
BT_BUF_RX_SIZE, NULL);
|
BT_BUF_RX_SIZE, NULL);
|
||||||
|
|
||||||
|
NET_BUF_POOL_FIXED_DEFINE(hci_tx_pool, CONFIG_BT_HCI_CMD_COUNT + BT_BUF_TX_SIZE,
|
||||||
|
BT_BUF_TX_SIZE, NULL);
|
||||||
|
|
||||||
struct bt_dev_raw bt_dev;
|
struct bt_dev_raw bt_dev;
|
||||||
struct bt_hci_raw_cmd_ext *cmd_ext;
|
struct bt_hci_raw_cmd_ext *cmd_ext;
|
||||||
static size_t cmd_ext_size;
|
static size_t cmd_ext_size;
|
||||||
|
@ -65,11 +69,86 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, s32_t timeout)
|
||||||
{
|
{
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
|
|
||||||
buf = net_buf_alloc(&hci_rx_pool, timeout);
|
switch (type) {
|
||||||
|
case BT_BUF_EVT:
|
||||||
|
case BT_BUF_ACL_IN:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BT_ERR("Invalid type: %u", type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (buf) {
|
buf = net_buf_alloc(&hci_rx_pool, timeout);
|
||||||
net_buf_reserve(buf, BT_BUF_RESERVE);
|
if (!buf) {
|
||||||
bt_buf_set_type(buf, type);
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buf_reserve(buf, BT_BUF_RESERVE);
|
||||||
|
bt_buf_set_type(buf, type);
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_HCI_RAW_H4) &&
|
||||||
|
raw_mode == BT_HCI_RAW_MODE_H4) {
|
||||||
|
switch (type) {
|
||||||
|
case BT_BUF_EVT:
|
||||||
|
net_buf_push_u8(buf, H4_EVT);
|
||||||
|
break;
|
||||||
|
case BT_BUF_ACL_IN:
|
||||||
|
net_buf_push_u8(buf, H4_ACL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERR("Invalid H4 type %u", type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct net_buf *bt_buf_get_tx(enum bt_buf_type type, s32_t timeout,
|
||||||
|
const void *data, size_t size)
|
||||||
|
{
|
||||||
|
struct net_buf *buf;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case BT_BUF_CMD:
|
||||||
|
case BT_BUF_ACL_OUT:
|
||||||
|
break;
|
||||||
|
case BT_BUF_H4:
|
||||||
|
if (IS_ENABLED(CONFIG_BT_HCI_RAW_H4) &&
|
||||||
|
raw_mode == BT_HCI_RAW_MODE_H4) {
|
||||||
|
switch (((u8_t *)data)[0]) {
|
||||||
|
case H4_CMD:
|
||||||
|
type = BT_BUF_CMD;
|
||||||
|
break;
|
||||||
|
case H4_ACL:
|
||||||
|
type = BT_BUF_ACL_OUT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERR("Unknown H4 type %u", type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust data pointer to discard the header */
|
||||||
|
data = (u8_t *)data + 1;
|
||||||
|
size--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Fallthrough */
|
||||||
|
default:
|
||||||
|
BT_ERR("Invalid type: %u", type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = net_buf_alloc(&hci_tx_pool, timeout);
|
||||||
|
if (!buf) {
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buf_reserve(buf, BT_BUF_RESERVE);
|
||||||
|
bt_buf_set_type(buf, type);
|
||||||
|
|
||||||
|
if (data && size) {
|
||||||
|
net_buf_add_mem(buf, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
|
@ -85,39 +164,10 @@ struct net_buf *bt_buf_get_evt(u8_t evt, bool discardable, s32_t timeout)
|
||||||
return bt_buf_get_rx(BT_BUF_EVT, timeout);
|
return bt_buf_get_rx(BT_BUF_EVT, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bt_h4_recv(struct net_buf *buf)
|
|
||||||
{
|
|
||||||
BT_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len);
|
|
||||||
|
|
||||||
switch (bt_buf_get_type(buf)) {
|
|
||||||
case BT_BUF_ACL_IN:
|
|
||||||
net_buf_push_u8(buf, H4_ACL);
|
|
||||||
break;
|
|
||||||
case BT_BUF_EVT:
|
|
||||||
net_buf_push_u8(buf, H4_EVT);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
BT_ERR("Unknown type %u", bt_buf_get_type(buf));
|
|
||||||
net_buf_unref(buf);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bt_recv(struct net_buf *buf)
|
int bt_recv(struct net_buf *buf)
|
||||||
{
|
{
|
||||||
BT_DBG("buf %p len %u", buf, buf->len);
|
BT_DBG("buf %p len %u", buf, buf->len);
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_HCI_RAW_H4) &&
|
|
||||||
raw_mode == BT_HCI_RAW_MODE_H4) {
|
|
||||||
int err = bt_h4_recv(buf);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bt_monitor_send(bt_monitor_opcode(buf), buf->data, buf->len);
|
bt_monitor_send(bt_monitor_opcode(buf), buf->data, buf->len);
|
||||||
|
|
||||||
/* Queue to RAW rx queue */
|
/* Queue to RAW rx queue */
|
||||||
|
@ -131,29 +181,6 @@ int bt_recv_prio(struct net_buf *buf)
|
||||||
return bt_recv(buf);
|
return bt_recv(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bt_h4_send(struct net_buf *buf)
|
|
||||||
{
|
|
||||||
u8_t type;
|
|
||||||
|
|
||||||
type = net_buf_pull_u8(buf);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case H4_CMD:
|
|
||||||
bt_buf_set_type(buf, BT_BUF_CMD);
|
|
||||||
break;
|
|
||||||
case H4_ACL:
|
|
||||||
bt_buf_set_type(buf, BT_BUF_ACL_OUT);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG_ERR("Unknown H4 type %u", type);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bt_cmd_complete_ext(u16_t op, u8_t status)
|
static void bt_cmd_complete_ext(u16_t op, u8_t status)
|
||||||
{
|
{
|
||||||
struct net_buf *buf;
|
struct net_buf *buf;
|
||||||
|
@ -227,15 +254,6 @@ int bt_send(struct net_buf *buf)
|
||||||
{
|
{
|
||||||
BT_DBG("buf %p len %u", buf, buf->len);
|
BT_DBG("buf %p len %u", buf, buf->len);
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_HCI_RAW_H4) &&
|
|
||||||
raw_mode == BT_HCI_RAW_MODE_H4) {
|
|
||||||
int err = bt_h4_send(buf);
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bt_monitor_send(bt_monitor_opcode(buf), buf->data, buf->len);
|
bt_monitor_send(bt_monitor_opcode(buf), buf->data, buf->len);
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_HCI_RAW_CMD_EXT) &&
|
if (IS_ENABLED(CONFIG_BT_HCI_RAW_CMD_EXT) &&
|
||||||
|
|
|
@ -28,41 +28,6 @@ LOG_MODULE_REGISTER(usb_bluetooth);
|
||||||
static K_FIFO_DEFINE(rx_queue);
|
static K_FIFO_DEFINE(rx_queue);
|
||||||
static K_FIFO_DEFINE(tx_queue);
|
static K_FIFO_DEFINE(tx_queue);
|
||||||
|
|
||||||
/* HCI command buffers */
|
|
||||||
#define CMD_BUF_SIZE BT_BUF_RX_SIZE
|
|
||||||
NET_BUF_POOL_DEFINE(rx_pool, CONFIG_BT_HCI_CMD_COUNT, CMD_BUF_SIZE,
|
|
||||||
sizeof(u8_t), NULL);
|
|
||||||
|
|
||||||
/* ACL data TX buffers */
|
|
||||||
#if defined(CONFIG_USB_DEVICE_BLUETOOTH_VS_H4)
|
|
||||||
#if defined(CONFIG_BT_CTLR_TX_BUFFERS)
|
|
||||||
#define ACL_BUF_COUNT (CONFIG_BT_HCI_CMD_COUNT + CONFIG_BT_CTLR_TX_BUFFERS)
|
|
||||||
#else
|
|
||||||
#define ACL_BUF_COUNT (CONFIG_BT_HCI_CMD_COUNT + 4)
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#if defined(CONFIG_BT_CTLR_TX_BUFFERS)
|
|
||||||
#define ACL_BUF_COUNT CONFIG_BT_CTLR_TX_BUFFERS
|
|
||||||
#else
|
|
||||||
#define ACL_BUF_COUNT 4
|
|
||||||
#endif
|
|
||||||
#endif /* CONFIG_USB_DEVICE_BLUETOOTH_VS_H4 */
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_TX_BUFFER_SIZE)
|
|
||||||
#define BT_L2CAP_MTU (CONFIG_BT_CTLR_TX_BUFFER_SIZE - BT_L2CAP_HDR_SIZE)
|
|
||||||
#else
|
|
||||||
#define BT_L2CAP_MTU 64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Data size needed for ACL buffers */
|
|
||||||
#if defined(CONFIG_USB_DEVICE_BLUETOOTH_VS_H4)
|
|
||||||
#define BT_BUF_ACL_SIZE MAX(BT_BUF_RX_SIZE, BT_L2CAP_BUF_SIZE(BT_L2CAP_MTU))
|
|
||||||
#else
|
|
||||||
#define BT_BUF_ACL_SIZE BT_L2CAP_BUF_SIZE(BT_L2CAP_MTU)
|
|
||||||
#endif
|
|
||||||
NET_BUF_POOL_DEFINE(acl_rx_pool, ACL_BUF_COUNT, BT_BUF_ACL_SIZE,
|
|
||||||
sizeof(u8_t), NULL);
|
|
||||||
|
|
||||||
#define BLUETOOTH_INT_EP_ADDR 0x81
|
#define BLUETOOTH_INT_EP_ADDR 0x81
|
||||||
#define BLUETOOTH_OUT_EP_ADDR 0x02
|
#define BLUETOOTH_OUT_EP_ADDR 0x02
|
||||||
#define BLUETOOTH_IN_EP_ADDR 0x82
|
#define BLUETOOTH_IN_EP_ADDR 0x82
|
||||||
|
@ -205,26 +170,30 @@ static void hci_rx_thread(void)
|
||||||
|
|
||||||
static void acl_read_cb(u8_t ep, int size, void *priv)
|
static void acl_read_cb(u8_t ep, int size, void *priv)
|
||||||
{
|
{
|
||||||
struct net_buf *buf = priv;
|
static u8_t data[BLUETOOTH_BULK_EP_MPS];
|
||||||
|
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
buf->len += size;
|
struct net_buf *buf;
|
||||||
bt_buf_set_type(buf, BT_BUF_ACL_OUT);
|
|
||||||
|
if (IS_ENABLED(CONFIG_USB_DEVICE_BLUETOOTH_VS_H4) &&
|
||||||
|
bt_hci_raw_get_mode() == BT_HCI_RAW_MODE_H4) {
|
||||||
|
buf = bt_buf_get_tx(BT_BUF_H4, K_FOREVER, data, size);
|
||||||
|
} else {
|
||||||
|
buf = bt_buf_get_tx(BT_BUF_ACL_OUT, K_FOREVER, data,
|
||||||
|
size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
LOG_ERR("Cannot get free TX buffer\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
net_buf_put(&rx_queue, buf);
|
net_buf_put(&rx_queue, buf);
|
||||||
buf = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf) {
|
|
||||||
net_buf_unref(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = net_buf_alloc(&acl_rx_pool, K_FOREVER);
|
|
||||||
|
|
||||||
net_buf_reserve(buf, BT_BUF_RESERVE);
|
|
||||||
|
|
||||||
/* Start a new read transfer */
|
/* Start a new read transfer */
|
||||||
usb_transfer(bluetooth_ep_data[HCI_OUT_EP_IDX].ep_addr, buf->data,
|
usb_transfer(bluetooth_ep_data[HCI_OUT_EP_IDX].ep_addr, data,
|
||||||
BT_BUF_ACL_SIZE, USB_TRANS_READ, acl_read_cb, buf);
|
BT_BUF_ACL_SIZE, USB_TRANS_READ, acl_read_cb, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bluetooth_status_cb(struct usb_cfg_data *cfg,
|
static void bluetooth_status_cb(struct usb_cfg_data *cfg,
|
||||||
|
@ -331,22 +300,12 @@ static int bluetooth_class_handler(struct usb_setup_packet *setup,
|
||||||
|
|
||||||
LOG_DBG("len %u", *len);
|
LOG_DBG("len %u", *len);
|
||||||
|
|
||||||
if (!*len || *len > CMD_BUF_SIZE) {
|
buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, *data, *len);
|
||||||
LOG_ERR("Incorrect length: %d\n", *len);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = net_buf_alloc(&rx_pool, K_NO_WAIT);
|
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
LOG_ERR("Cannot get free buffer\n");
|
LOG_ERR("Cannot get free buffer\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
net_buf_reserve(buf, BT_BUF_RESERVE);
|
|
||||||
bt_buf_set_type(buf, BT_BUF_CMD);
|
|
||||||
|
|
||||||
net_buf_add_mem(buf, *data, *len);
|
|
||||||
|
|
||||||
net_buf_put(&rx_queue, buf);
|
net_buf_put(&rx_queue, buf);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -26,30 +26,13 @@ LOG_MODULE_REGISTER(usb_bt_h4);
|
||||||
static K_FIFO_DEFINE(rx_queue);
|
static K_FIFO_DEFINE(rx_queue);
|
||||||
static K_FIFO_DEFINE(tx_queue);
|
static K_FIFO_DEFINE(tx_queue);
|
||||||
|
|
||||||
/* ACL data TX buffers */
|
|
||||||
#if defined(CONFIG_BT_CTLR_TX_BUFFERS)
|
|
||||||
#define BUF_COUNT (CONFIG_BT_HCI_CMD_COUNT + CONFIG_BT_CTLR_TX_BUFFERS)
|
|
||||||
#else
|
|
||||||
#define BUF_COUNT (CONFIG_BT_HCI_CMD_COUNT + 4)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(CONFIG_BT_CTLR_TX_BUFFER_SIZE)
|
|
||||||
#define BT_L2CAP_MTU (CONFIG_BT_CTLR_TX_BUFFER_SIZE - BT_L2CAP_HDR_SIZE)
|
|
||||||
#else
|
|
||||||
#define BT_L2CAP_MTU 64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Data size needed for CMD and ACL buffers */
|
|
||||||
#define BUF_SIZE MAX(BT_BUF_RX_SIZE, BT_L2CAP_BUF_SIZE(BT_L2CAP_MTU))
|
|
||||||
NET_BUF_POOL_DEFINE(rx_pool, BUF_COUNT, BUF_SIZE, sizeof(u8_t), NULL);
|
|
||||||
|
|
||||||
#define BT_H4_OUT_EP_ADDR 0x01
|
#define BT_H4_OUT_EP_ADDR 0x01
|
||||||
#define BT_H4_IN_EP_ADDR 0x81
|
#define BT_H4_IN_EP_ADDR 0x81
|
||||||
|
|
||||||
#define BT_H4_OUT_EP_IDX 0
|
#define BT_H4_OUT_EP_IDX 0
|
||||||
#define BT_H4_IN_EP_IDX 1
|
#define BT_H4_IN_EP_IDX 1
|
||||||
|
|
||||||
#define BT_H4_BULK_EP_MPS MIN(BUF_SIZE, USB_MAX_FS_BULK_MPS)
|
#define BT_H4_BULK_EP_MPS MIN(BT_BUF_TX_SIZE, USB_MAX_FS_BULK_MPS)
|
||||||
|
|
||||||
/* HCI RX/TX threads */
|
/* HCI RX/TX threads */
|
||||||
static K_THREAD_STACK_DEFINE(rx_thread_stack, 512);
|
static K_THREAD_STACK_DEFINE(rx_thread_stack, 512);
|
||||||
|
@ -111,25 +94,23 @@ static struct usb_ep_cfg_data bt_h4_ep_data[] = {
|
||||||
|
|
||||||
static void bt_h4_read(u8_t ep, int size, void *priv)
|
static void bt_h4_read(u8_t ep, int size, void *priv)
|
||||||
{
|
{
|
||||||
struct net_buf *buf = priv;
|
static u8_t data[BT_H4_BULK_EP_MPS];
|
||||||
|
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
buf->len += size;
|
struct net_buf *buf;
|
||||||
|
|
||||||
|
buf = bt_buf_get_tx(BT_BUF_H4, K_FOREVER, data, size);
|
||||||
|
if (!buf) {
|
||||||
|
LOG_ERR("Cannot get free TX buffer\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
net_buf_put(&rx_queue, buf);
|
net_buf_put(&rx_queue, buf);
|
||||||
buf = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buf) {
|
|
||||||
net_buf_unref(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
buf = net_buf_alloc(&rx_pool, K_FOREVER);
|
|
||||||
|
|
||||||
net_buf_reserve(buf, BT_BUF_RESERVE);
|
|
||||||
|
|
||||||
/* Start a new read transfer */
|
/* Start a new read transfer */
|
||||||
usb_transfer(bt_h4_ep_data[BT_H4_OUT_EP_IDX].ep_addr, buf->data,
|
usb_transfer(bt_h4_ep_data[BT_H4_OUT_EP_IDX].ep_addr, data,
|
||||||
BUF_SIZE, USB_TRANS_READ, bt_h4_read, buf);
|
BT_H4_BULK_EP_MPS, USB_TRANS_READ, bt_h4_read, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hci_tx_thread(void)
|
static void hci_tx_thread(void)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue