Bluetooth: hci_raw: Add support for using H:4 transport

This adds 2 config options which enables hci_raw to work in
H:4 mode and enable it by default automatically.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Luiz Augusto von Dentz 2020-03-18 17:09:20 -07:00 committed by Johan Hedberg
commit b3ee8be80d
6 changed files with 167 additions and 122 deletions

View file

@ -32,6 +32,41 @@ extern "C" {
*/
int bt_send(struct net_buf *buf);
enum {
/** Passthrough mode
*
* While in this mode the buffers are passed as is between the stack
* and the driver.
*/
BT_HCI_RAW_MODE_PASSTHROUGH = 0x00,
/** H:4 mode
*
* While in this mode H:4 headers will added into the buffers
* according to the buffer type when coming from the stack and will be
* removed and used to set the buffer type.
*/
BT_HCI_RAW_MODE_H4 = 0x01,
};
/** @brief Set Bluetooth RAW channel mode
*
* Set access mode of Bluetooth RAW channel.
*
* @param mode Access mode.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_hci_raw_set_mode(u8_t mode);
/** @brief Get Bluetooth RAW channel mode
*
* Get access mode of Bluetooth RAW channel.
*
* @return Access mode.
*/
u8_t bt_hci_raw_get_mode(void);
/** @brief Enable Bluetooth RAW channel
*
* Enable Bluetooth RAW HCI channel.

View file

@ -49,10 +49,23 @@ config BT_HCI_RAW
This option allows to access Bluetooth controller
from the application with the RAW HCI protocol.
config BT_HCI_RAW_H4
bool "RAW HCI H:4 transport"
help
This option enables HCI RAW access to work over an H:4
transport, note that it still need to be selected at runtime.
config BT_HCI_RAW_H4_ENABLE
bool "RAW HCI H:4 transport enable"
depends on BT_HCI_RAW_H4
help
This option enables use of H:4 transport for HCI RAW access at
build time.
config BT_HCI_RAW_RESERVE
int "Buffer headroom needed for HCI transport"
depends on BT_HCI_RAW
default 1 if USB_DEVICE_BT_H4
default 1 if BT_HCI_RAW_H4
default 0
help
This option is used by the HCI raw transport implementation to

View file

@ -20,8 +20,19 @@
#include "monitor.h"
#include "hci_raw_internal.h"
#define H4_CMD 0x01
#define H4_ACL 0x02
#define H4_SCO 0x03
#define H4_EVT 0x04
static struct k_fifo *raw_rx;
#if defined(CONFIG_BT_HCI_RAW_H4_ENABLE)
static u8_t raw_mode = BT_HCI_RAW_MODE_H4;
#else
static u8_t raw_mode;
#endif
NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, CONFIG_BT_RX_BUF_COUNT,
BT_BUF_RX_SIZE, NULL);
@ -71,10 +82,39 @@ struct net_buf *bt_buf_get_evt(u8_t evt, bool discardable, s32_t 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)
{
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);
/* Queue to RAW rx queue */
@ -88,10 +128,42 @@ int bt_recv_prio(struct net_buf *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;
}
int bt_send(struct net_buf *buf)
{
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);
if (IS_ENABLED(CONFIG_BT_TINYCRYPT_ECC)) {
@ -101,6 +173,31 @@ int bt_send(struct net_buf *buf)
return bt_dev.drv->send(buf);
}
int bt_hci_raw_set_mode(u8_t mode)
{
BT_DBG("mode %u", mode);
if (IS_ENABLED(CONFIG_BT_HCI_RAW_H4)) {
switch (mode) {
case BT_HCI_RAW_MODE_PASSTHROUGH:
case BT_HCI_RAW_MODE_H4:
raw_mode = mode;
return 0;
}
}
return -EINVAL;
}
u8_t bt_hci_raw_get_mode(void)
{
if (IS_ENABLED(CONFIG_BT_HCI_RAW_H4)) {
return raw_mode;
}
return BT_HCI_RAW_MODE_PASSTHROUGH;
}
int bt_enable_raw(struct k_fifo *rx_queue)
{
const struct bt_hci_driver *drv = bt_dev.drv;

View file

@ -94,6 +94,7 @@ config USB_DEVICE_BLUETOOTH
config USB_DEVICE_BLUETOOTH_VS_H4
bool "Enable USB Bluetooth H4 vendor command"
depends on USB_DEVICE_BLUETOOTH
select BT_HCI_RAW_H4
help
Enables vendor command to switch to H:4 transport using the bulk
endpoint.
@ -102,6 +103,8 @@ config USB_DEVICE_BT_H4
bool "USB Bluetooth H4 Device Class Driver"
select BT
select BT_HCI_RAW
select BT_HCI_RAW_H4
select BT_HCI_RAW_H4_ENABLE
help
USB Bluetooth H4 device class driver

View file

@ -77,7 +77,6 @@ static K_THREAD_STACK_DEFINE(rx_thread_stack, 512);
static struct k_thread rx_thread_data;
static K_THREAD_STACK_DEFINE(tx_thread_stack, 512);
static struct k_thread tx_thread_data;
static u8_t mode = BT_HCI_VS_USB_H2_MODE;
struct usb_bluetooth_config {
struct usb_if_descriptor if0;
@ -151,34 +150,6 @@ static struct usb_ep_cfg_data bluetooth_ep_data[] = {
},
};
#define H4_CMD 0x01
#define H4_ACL 0x02
#define H4_SCO 0x03
#define H4_EVT 0x04
static void usb_h4_send(struct net_buf *buf)
{
LOG_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:
LOG_ERR("Unknown type %u", bt_buf_get_type(buf));
net_buf_unref(buf);
return;
}
usb_transfer_sync(bluetooth_ep_data[HCI_IN_EP_IDX].ep_addr, buf->data,
buf->len, USB_TRANS_WRITE);
net_buf_unref(buf);
}
static void hci_tx_thread(void)
{
LOG_DBG("Start USB Bluetooth thread");
@ -189,9 +160,9 @@ static void hci_tx_thread(void)
buf = net_buf_get(&tx_queue, K_FOREVER);
if (IS_ENABLED(CONFIG_USB_DEVICE_BLUETOOTH_VS_H4) &&
mode == BT_HCI_VS_USB_H4_MODE) {
usb_h4_send(buf);
continue;
bt_hci_raw_get_mode() == BT_HCI_RAW_MODE_H4) {
/* Force to sent over bulk if H4 is selected */
bt_buf_set_type(buf, BT_BUF_ACL_IN);
}
switch (bt_buf_get_type(buf)) {
@ -216,43 +187,16 @@ static void hci_tx_thread(void)
}
}
static void usb_h4_recv(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;
}
LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len);
if (bt_send(buf)) {
LOG_ERR("Error sending to driver");
net_buf_unref(buf);
}
}
static void hci_rx_thread(void)
{
while (true) {
struct net_buf *buf;
int err;
buf = net_buf_get(&rx_queue, K_FOREVER);
if (IS_ENABLED(CONFIG_USB_DEVICE_BLUETOOTH_VS_H4) &&
mode == BT_HCI_VS_USB_H4_MODE) {
usb_h4_recv(buf);
} else if (bt_send(buf)) {
err = bt_send(buf);
if (err) {
LOG_ERR("Error sending to driver");
net_buf_unref(buf);
}
@ -358,26 +302,26 @@ static u8_t vs_read_usb_transport_mode(struct net_buf *buf)
static u8_t vs_set_usb_transport_mode(struct net_buf *buf)
{
struct bt_hci_cp_vs_set_usb_transport_mode *cp;
u8_t mode;
cp = net_buf_pull_mem(buf, sizeof(*cp));
if (mode == cp->mode) {
return BT_HCI_ERR_INVALID_PARAM;
}
switch (cp->mode) {
case BT_HCI_VS_USB_H2_MODE:
mode = BT_HCI_RAW_MODE_PASSTHROUGH;
break;
case BT_HCI_VS_USB_H4_MODE:
mode = BT_HCI_RAW_MODE_H4;
break;
default:
LOG_DBG("Invalid mode: %u", cp->mode);
return BT_HCI_ERR_INVALID_PARAM;
}
mode = cp->mode;
LOG_DBG("mode %u", mode);
bt_hci_raw_set_mode(mode);
return BT_HCI_ERR_SUCCESS;
}

View file

@ -98,11 +98,6 @@ USBD_CLASS_DESCR_DEFINE(primary, 0) struct usb_bt_h4_config bt_h4_cfg = {
},
};
#define H4_CMD 0x01
#define H4_ACL 0x02
#define H4_SCO 0x03
#define H4_EVT 0x04
static struct usb_ep_cfg_data bt_h4_ep_data[] = {
{
.ep_cb = usb_transfer_ep_callback,
@ -137,29 +132,6 @@ static void bt_h4_read(u8_t ep, int size, void *priv)
BUF_SIZE, USB_TRANS_READ, bt_h4_read, buf);
}
static void usb_h4_send(struct net_buf *buf)
{
LOG_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:
LOG_ERR("Unknown type %u", bt_buf_get_type(buf));
net_buf_unref(buf);
return;
}
usb_transfer_sync(bt_h4_ep_data[BT_H4_IN_EP_IDX].ep_addr,
buf->data, buf->len, USB_TRANS_WRITE);
net_buf_unref(buf);
}
static void hci_tx_thread(void)
{
LOG_DBG("Start USB Bluetooth thread");
@ -168,32 +140,10 @@ static void hci_tx_thread(void)
struct net_buf *buf;
buf = net_buf_get(&tx_queue, K_FOREVER);
usb_h4_send(buf);
}
}
static void usb_h4_recv(struct net_buf *buf)
{
u8_t type;
usb_transfer_sync(bt_h4_ep_data[BT_H4_IN_EP_IDX].ep_addr,
buf->data, buf->len, USB_TRANS_WRITE);
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;
}
LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len);
if (bt_send(buf)) {
LOG_ERR("Error sending to driver");
net_buf_unref(buf);
}
}
@ -204,7 +154,10 @@ static void hci_rx_thread(void)
struct net_buf *buf;
buf = net_buf_get(&rx_queue, K_FOREVER);
usb_h4_recv(buf);
if (bt_send(buf)) {
LOG_ERR("Error sending to driver");
net_buf_unref(buf);
}
}
}