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); 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 /** @brief Enable Bluetooth RAW channel
* *
* Enable Bluetooth RAW HCI channel. * Enable Bluetooth RAW HCI channel.

View file

@ -49,10 +49,23 @@ config BT_HCI_RAW
This option allows to access Bluetooth controller This option allows to access Bluetooth controller
from the application with the RAW HCI protocol. 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 config BT_HCI_RAW_RESERVE
int "Buffer headroom needed for HCI transport" int "Buffer headroom needed for HCI transport"
depends on BT_HCI_RAW depends on BT_HCI_RAW
default 1 if USB_DEVICE_BT_H4 default 1 if BT_HCI_RAW_H4
default 0 default 0
help help
This option is used by the HCI raw transport implementation to This option is used by the HCI raw transport implementation to

View file

@ -20,8 +20,19 @@
#include "monitor.h" #include "monitor.h"
#include "hci_raw_internal.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; 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, NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, CONFIG_BT_RX_BUF_COUNT,
BT_BUF_RX_SIZE, NULL); 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); 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 */
@ -88,10 +128,42 @@ 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;
}
int bt_send(struct net_buf *buf) 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_TINYCRYPT_ECC)) { if (IS_ENABLED(CONFIG_BT_TINYCRYPT_ECC)) {
@ -101,6 +173,31 @@ int bt_send(struct net_buf *buf)
return bt_dev.drv->send(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) int bt_enable_raw(struct k_fifo *rx_queue)
{ {
const struct bt_hci_driver *drv = bt_dev.drv; 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 config USB_DEVICE_BLUETOOTH_VS_H4
bool "Enable USB Bluetooth H4 vendor command" bool "Enable USB Bluetooth H4 vendor command"
depends on USB_DEVICE_BLUETOOTH depends on USB_DEVICE_BLUETOOTH
select BT_HCI_RAW_H4
help help
Enables vendor command to switch to H:4 transport using the bulk Enables vendor command to switch to H:4 transport using the bulk
endpoint. endpoint.
@ -102,6 +103,8 @@ config USB_DEVICE_BT_H4
bool "USB Bluetooth H4 Device Class Driver" bool "USB Bluetooth H4 Device Class Driver"
select BT select BT
select BT_HCI_RAW select BT_HCI_RAW
select BT_HCI_RAW_H4
select BT_HCI_RAW_H4_ENABLE
help help
USB Bluetooth H4 device class driver 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 struct k_thread rx_thread_data;
static K_THREAD_STACK_DEFINE(tx_thread_stack, 512); static K_THREAD_STACK_DEFINE(tx_thread_stack, 512);
static struct k_thread tx_thread_data; static struct k_thread tx_thread_data;
static u8_t mode = BT_HCI_VS_USB_H2_MODE;
struct usb_bluetooth_config { struct usb_bluetooth_config {
struct usb_if_descriptor if0; 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) static void hci_tx_thread(void)
{ {
LOG_DBG("Start USB Bluetooth thread"); LOG_DBG("Start USB Bluetooth thread");
@ -189,9 +160,9 @@ static void hci_tx_thread(void)
buf = net_buf_get(&tx_queue, K_FOREVER); buf = net_buf_get(&tx_queue, K_FOREVER);
if (IS_ENABLED(CONFIG_USB_DEVICE_BLUETOOTH_VS_H4) && if (IS_ENABLED(CONFIG_USB_DEVICE_BLUETOOTH_VS_H4) &&
mode == BT_HCI_VS_USB_H4_MODE) { bt_hci_raw_get_mode() == BT_HCI_RAW_MODE_H4) {
usb_h4_send(buf); /* Force to sent over bulk if H4 is selected */
continue; bt_buf_set_type(buf, BT_BUF_ACL_IN);
} }
switch (bt_buf_get_type(buf)) { 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) static void hci_rx_thread(void)
{ {
while (true) { while (true) {
struct net_buf *buf; struct net_buf *buf;
int err;
buf = net_buf_get(&rx_queue, K_FOREVER); buf = net_buf_get(&rx_queue, K_FOREVER);
if (IS_ENABLED(CONFIG_USB_DEVICE_BLUETOOTH_VS_H4) && err = bt_send(buf);
mode == BT_HCI_VS_USB_H4_MODE) { if (err) {
usb_h4_recv(buf);
} else if (bt_send(buf)) {
LOG_ERR("Error sending to driver"); LOG_ERR("Error sending to driver");
net_buf_unref(buf); 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) static u8_t vs_set_usb_transport_mode(struct net_buf *buf)
{ {
struct bt_hci_cp_vs_set_usb_transport_mode *cp; struct bt_hci_cp_vs_set_usb_transport_mode *cp;
u8_t mode;
cp = net_buf_pull_mem(buf, sizeof(*cp)); cp = net_buf_pull_mem(buf, sizeof(*cp));
if (mode == cp->mode) {
return BT_HCI_ERR_INVALID_PARAM;
}
switch (cp->mode) { switch (cp->mode) {
case BT_HCI_VS_USB_H2_MODE: case BT_HCI_VS_USB_H2_MODE:
mode = BT_HCI_RAW_MODE_PASSTHROUGH;
break;
case BT_HCI_VS_USB_H4_MODE: case BT_HCI_VS_USB_H4_MODE:
mode = BT_HCI_RAW_MODE_H4;
break; break;
default: default:
LOG_DBG("Invalid mode: %u", cp->mode); LOG_DBG("Invalid mode: %u", cp->mode);
return BT_HCI_ERR_INVALID_PARAM; return BT_HCI_ERR_INVALID_PARAM;
} }
mode = cp->mode;
LOG_DBG("mode %u", mode); LOG_DBG("mode %u", mode);
bt_hci_raw_set_mode(mode);
return BT_HCI_ERR_SUCCESS; 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[] = { static struct usb_ep_cfg_data bt_h4_ep_data[] = {
{ {
.ep_cb = usb_transfer_ep_callback, .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); 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) static void hci_tx_thread(void)
{ {
LOG_DBG("Start USB Bluetooth thread"); LOG_DBG("Start USB Bluetooth thread");
@ -168,32 +140,10 @@ static void hci_tx_thread(void)
struct net_buf *buf; struct net_buf *buf;
buf = net_buf_get(&tx_queue, K_FOREVER); buf = net_buf_get(&tx_queue, K_FOREVER);
usb_h4_send(buf);
}
}
static void usb_h4_recv(struct net_buf *buf) usb_transfer_sync(bt_h4_ep_data[BT_H4_IN_EP_IDX].ep_addr,
{ buf->data, buf->len, USB_TRANS_WRITE);
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); net_buf_unref(buf);
} }
} }
@ -204,7 +154,10 @@ static void hci_rx_thread(void)
struct net_buf *buf; struct net_buf *buf;
buf = net_buf_get(&rx_queue, K_FOREVER); 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);
}
} }
} }