Encode the packet type as a H:4 payload prefix for buffers passing to & from HCI drivers. The existing bt_buf_set/get_type functions are deprecated, but kept compatible with the change, except that they can only be called once, since they modify the buffer payload. Signed-off-by: Johan Hedberg <johan.hedberg@silabs.com>
211 lines
4.7 KiB
C
211 lines
4.7 KiB
C
/* hci_userchan.c - HCI user channel Bluetooth handling */
|
|
|
|
/*
|
|
* Copyright (c) 2015-2016 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include <zephyr/bluetooth/buf.h>
|
|
#include <zephyr/bluetooth/hci.h>
|
|
#include <zephyr/bluetooth/hci_raw.h>
|
|
#include <zephyr/bluetooth/hci_types.h>
|
|
#include <zephyr/bluetooth/l2cap.h>
|
|
#include <zephyr/bluetooth/iso.h>
|
|
#include <zephyr/device.h>
|
|
#include <zephyr/devicetree.h>
|
|
#include <zephyr/drivers/bluetooth.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/logging/log.h>
|
|
#include <zephyr/net_buf.h>
|
|
#include <zephyr/sys/atomic.h>
|
|
#include <zephyr/sys/byteorder.h>
|
|
#include <zephyr/sys/util_macro.h>
|
|
#include <zephyr/sys_clock.h>
|
|
#include <zephyr/toolchain.h>
|
|
|
|
#include "common/hci_common_internal.h"
|
|
#include "hci_raw_internal.h"
|
|
#include "monitor.h"
|
|
|
|
#define LOG_LEVEL CONFIG_BT_HCI_CORE_LOG_LEVEL
|
|
LOG_MODULE_REGISTER(bt_hci_raw);
|
|
|
|
static struct k_fifo *raw_rx;
|
|
|
|
static bt_buf_rx_freed_cb_t buf_rx_freed_cb;
|
|
|
|
static void hci_rx_buf_destroy(struct net_buf *buf)
|
|
{
|
|
net_buf_destroy(buf);
|
|
|
|
if (buf_rx_freed_cb) {
|
|
/* bt_buf_get_rx is used for all types of RX buffers */
|
|
buf_rx_freed_cb(BT_BUF_EVT | BT_BUF_ACL_IN | BT_BUF_ISO_IN);
|
|
}
|
|
}
|
|
|
|
NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, BT_BUF_RX_SIZE, 0, hci_rx_buf_destroy);
|
|
NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, BT_BUF_CMD_TX_COUNT,
|
|
BT_BUF_CMD_SIZE(CONFIG_BT_BUF_CMD_TX_SIZE), 0, NULL);
|
|
NET_BUF_POOL_FIXED_DEFINE(hci_acl_pool, CONFIG_BT_BUF_ACL_TX_COUNT,
|
|
BT_BUF_ACL_SIZE(CONFIG_BT_BUF_ACL_TX_SIZE), 0, NULL);
|
|
#if defined(CONFIG_BT_ISO)
|
|
NET_BUF_POOL_FIXED_DEFINE(hci_iso_pool, CONFIG_BT_ISO_TX_BUF_COUNT,
|
|
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 0, NULL);
|
|
#endif /* CONFIG_BT_ISO */
|
|
|
|
#if DT_HAS_CHOSEN(zephyr_bt_hci)
|
|
#define BT_HCI_NODE DT_CHOSEN(zephyr_bt_hci)
|
|
#define BT_HCI_DEV DEVICE_DT_GET(BT_HCI_NODE)
|
|
#define BT_HCI_BUS BT_DT_HCI_BUS_GET(BT_HCI_NODE)
|
|
#define BT_HCI_NAME BT_DT_HCI_NAME_GET(BT_HCI_NODE)
|
|
#else
|
|
/* The zephyr,bt-hci chosen property is mandatory, except for unit tests */
|
|
BUILD_ASSERT(IS_ENABLED(CONFIG_ZTEST), "Missing DT chosen property for HCI");
|
|
#define BT_HCI_DEV NULL
|
|
#define BT_HCI_BUS 0
|
|
#define BT_HCI_NAME ""
|
|
#endif
|
|
|
|
struct bt_dev_raw bt_dev = {
|
|
.hci = BT_HCI_DEV,
|
|
};
|
|
|
|
struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout)
|
|
{
|
|
struct net_buf *buf;
|
|
|
|
switch (type) {
|
|
case BT_BUF_EVT:
|
|
case BT_BUF_ACL_IN:
|
|
case BT_BUF_ISO_IN:
|
|
break;
|
|
default:
|
|
LOG_ERR("Invalid rx type: %u", type);
|
|
return NULL;
|
|
}
|
|
|
|
buf = net_buf_alloc(&hci_rx_pool, timeout);
|
|
if (!buf) {
|
|
return buf;
|
|
}
|
|
|
|
net_buf_add_u8(buf, bt_buf_type_to_h4(type));
|
|
|
|
return buf;
|
|
}
|
|
|
|
void bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb_t cb)
|
|
{
|
|
buf_rx_freed_cb = cb;
|
|
}
|
|
|
|
struct net_buf *bt_buf_get_tx(enum bt_buf_type type, k_timeout_t timeout,
|
|
const void *data, size_t size)
|
|
{
|
|
struct net_buf_pool *pool;
|
|
struct net_buf *buf;
|
|
|
|
switch (type) {
|
|
case BT_BUF_CMD:
|
|
pool = &hci_cmd_pool;
|
|
break;
|
|
case BT_BUF_ACL_OUT:
|
|
pool = &hci_acl_pool;
|
|
break;
|
|
#if defined(CONFIG_BT_ISO)
|
|
case BT_BUF_ISO_OUT:
|
|
pool = &hci_iso_pool;
|
|
break;
|
|
#endif /* CONFIG_BT_ISO */
|
|
default:
|
|
LOG_ERR("Invalid tx type: %u", type);
|
|
return NULL;
|
|
}
|
|
|
|
buf = net_buf_alloc(pool, timeout);
|
|
if (!buf) {
|
|
return buf;
|
|
}
|
|
|
|
net_buf_add_u8(buf, bt_buf_type_to_h4(type));
|
|
|
|
if (data && size) {
|
|
if (net_buf_tailroom(buf) < size) {
|
|
net_buf_unref(buf);
|
|
return NULL;
|
|
}
|
|
|
|
net_buf_add_mem(buf, data, size);
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
struct net_buf *bt_buf_get_evt(uint8_t evt, bool discardable, k_timeout_t timeout)
|
|
{
|
|
return bt_buf_get_rx(BT_BUF_EVT, timeout);
|
|
}
|
|
|
|
int bt_hci_recv(const struct device *dev, struct net_buf *buf)
|
|
{
|
|
uint8_t type = buf->data[0];
|
|
|
|
ARG_UNUSED(dev);
|
|
|
|
LOG_DBG("buf %p len %u", buf, buf->len);
|
|
|
|
bt_monitor_send(bt_monitor_opcode(type, BT_MONITOR_RX), buf->data + 1, buf->len - 1);
|
|
|
|
k_fifo_put(raw_rx, buf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bt_send(struct net_buf *buf)
|
|
{
|
|
if (buf->len == 0) {
|
|
return BT_HCI_ERR_INVALID_PARAM;
|
|
}
|
|
|
|
LOG_DBG("buf %p type %u len %u", buf, buf->data[0], buf->len);
|
|
|
|
bt_monitor_send(bt_monitor_opcode(buf->data[0], BT_MONITOR_TX),
|
|
buf->data + 1, buf->len - 1);
|
|
|
|
return bt_hci_send(bt_dev.hci, buf);
|
|
}
|
|
|
|
int bt_enable_raw(struct k_fifo *rx_queue)
|
|
{
|
|
int err;
|
|
|
|
LOG_DBG("");
|
|
|
|
raw_rx = rx_queue;
|
|
|
|
if (!device_is_ready(bt_dev.hci)) {
|
|
LOG_ERR("HCI driver is not ready");
|
|
return -ENODEV;
|
|
}
|
|
|
|
bt_monitor_new_index(BT_MONITOR_TYPE_PRIMARY, BT_HCI_BUS, BT_ADDR_ANY, BT_HCI_NAME);
|
|
|
|
err = bt_hci_open(bt_dev.hci, bt_hci_recv);
|
|
if (err) {
|
|
LOG_ERR("HCI driver open failed (%d)", err);
|
|
return err;
|
|
}
|
|
|
|
LOG_INF("Lower HCI transport: %s", BT_HCI_NAME);
|
|
LOG_INF("Bluetooth enabled in RAW mode");
|
|
|
|
return 0;
|
|
}
|