diff --git a/include/bluetooth/hci_raw.h b/include/bluetooth/hci_raw.h index dba2d4af5fe..70aeeb71796 100644 --- a/include/bluetooth/hci_raw.h +++ b/include/bluetooth/hci_raw.h @@ -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. diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index d4021e592b8..f3f39d77587 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -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 diff --git a/subsys/bluetooth/host/hci_raw.c b/subsys/bluetooth/host/hci_raw.c index c71b96df745..b65ea68a4cb 100644 --- a/subsys/bluetooth/host/hci_raw.c +++ b/subsys/bluetooth/host/hci_raw.c @@ -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; diff --git a/subsys/usb/class/Kconfig b/subsys/usb/class/Kconfig index c5d6b6ddfff..1c8ffafeab5 100644 --- a/subsys/usb/class/Kconfig +++ b/subsys/usb/class/Kconfig @@ -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 diff --git a/subsys/usb/class/bluetooth.c b/subsys/usb/class/bluetooth.c index 284f63fbd7a..255d1e33593 100644 --- a/subsys/usb/class/bluetooth.c +++ b/subsys/usb/class/bluetooth.c @@ -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; } diff --git a/subsys/usb/class/bt_h4.c b/subsys/usb/class/bt_h4.c index e0971123529..d24f6e1c3df 100644 --- a/subsys/usb/class/bt_h4.c +++ b/subsys/usb/class/bt_h4.c @@ -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); + } } }