diff --git a/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts b/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts index af7f0d673bed..5d6e0dd7d883 100644 --- a/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts +++ b/boards/arduino/giga_r1/arduino_giga_r1_stm32h747xx_m7.dts @@ -18,7 +18,7 @@ zephyr,console = &usart1; zephyr,shell-uart = &usart1; zephyr,uart-mcumgr = &usart1; - zephyr,bt-uart = &uart7; + zephyr,bt-hci = &bt_hci_uart; zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,canbus = &fdcan2; @@ -97,12 +97,17 @@ status = "okay"; hw-flow-control; - murata-1dx { - compatible = "infineon,cyw43xxx-bt-hci"; - bt-reg-on-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>; - bt-host-wake-gpios = <&gpiog 3 GPIO_ACTIVE_HIGH>; - bt-dev-wake-gpios = <&gpioh 7 GPIO_ACTIVE_HIGH>; - fw-download-speed = <115200>; + bt_hci_uart: bt_hci_uart { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + + murata-1dx { + compatible = "infineon,cyw43xxx-bt-hci"; + bt-reg-on-gpios = <&gpioa 10 GPIO_ACTIVE_HIGH>; + bt-host-wake-gpios = <&gpiog 3 GPIO_ACTIVE_HIGH>; + bt-dev-wake-gpios = <&gpioh 7 GPIO_ACTIVE_HIGH>; + fw-download-speed = <115200>; + }; }; }; diff --git a/boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w.dts b/boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w.dts index 7997344dd540..b9e74ac685d0 100644 --- a/boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w.dts +++ b/boards/infineon/cy8cproto_062_4343w/cy8cproto_062_4343w.dts @@ -25,7 +25,7 @@ zephyr,flash = &flash0; zephyr,console = &uart5; zephyr,shell-uart = &uart5; - zephyr,bt_uart = &uart2; + zephyr,bt-hci = &bt_hci_uart; }; }; @@ -58,17 +58,22 @@ uart2: &scb2 { /* HW Flow control must be enabled for HCI H4 */ hw-flow-control; - bt-hci { - status = "okay"; - compatible = "infineon,cyw43xxx-bt-hci"; - bt-reg-on-gpios = <&gpio_prt3 4 (GPIO_ACTIVE_HIGH)>; - - /* Configuration UART speeds for firmware download (fw-download-speed) and - * HCI operation (hci-operation-speed). - * If hci-operation-speed or fw-download-speed are not defined in bt-hci{...} - * node, cyw43xx driver will use bus/current-speed as default speed. - */ - fw-download-speed = <3000000>; + bt_hci_uart: bt_hci_uart { + compatible = "zephyr,bt-hci-uart"; + + murata-1dx { + status = "okay"; + compatible = "infineon,cyw43xxx-bt-hci"; + bt-reg-on-gpios = <&gpio_prt3 4 (GPIO_ACTIVE_HIGH)>; + + /* Configuration UART speeds for firmware download (fw-download-speed) + * and HCI operation (hci-operation-speed). + * If hci-operation-speed or fw-download-speed are not defined in + * bt-hci{...} node, cyw43xx driver will use bus/current-speed as + * default speed. + */ + fw-download-speed = <3000000>; + }; }; }; diff --git a/boards/ite/it82xx2_evb/it82xx2_evb.dts b/boards/ite/it82xx2_evb/it82xx2_evb.dts index bd623e969c54..29e8ad721c88 100644 --- a/boards/ite/it82xx2_evb/it82xx2_evb.dts +++ b/boards/ite/it82xx2_evb/it82xx2_evb.dts @@ -25,7 +25,7 @@ chosen { zephyr,console = &uart1; zephyr,shell-uart = &uart1; - zephyr,bt-uart = &uart2; + zephyr,bt-hci = &bt_hci_uart; zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,flash-controller = &flashctrl; @@ -115,6 +115,11 @@ status = "okay"; current-speed = <460800>; clock-frequency = <1843200>; + + bt_hci_uart: bt_hci_uart { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + }; }; &ite_uart1_wrapper { diff --git a/boards/ite/it8xxx2_evb/it8xxx2_evb.dts b/boards/ite/it8xxx2_evb/it8xxx2_evb.dts index c111e9092aa1..0ee42f981f08 100644 --- a/boards/ite/it8xxx2_evb/it8xxx2_evb.dts +++ b/boards/ite/it8xxx2_evb/it8xxx2_evb.dts @@ -25,7 +25,7 @@ chosen { zephyr,console = &uart1; zephyr,shell-uart = &uart1; - zephyr,bt-uart = &uart2; + zephyr,bt-hci = &bt_hci_uart; zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,flash-controller = &flashctrl; @@ -105,6 +105,11 @@ status = "okay"; current-speed = <460800>; clock-frequency = <1843200>; + + bt_hci_uart: bt_hci_uart { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + }; }; &ite_uart1_wrapper { status = "okay"; diff --git a/boards/nxp/hexiwear/hexiwear_mk64f12.dts b/boards/nxp/hexiwear/hexiwear_mk64f12.dts index 91961b19ad02..18cc0a370452 100644 --- a/boards/nxp/hexiwear/hexiwear_mk64f12.dts +++ b/boards/nxp/hexiwear/hexiwear_mk64f12.dts @@ -28,7 +28,7 @@ zephyr,code-partition = &slot0_partition; zephyr,console = &uart0; zephyr,shell-uart = &uart0; - zephyr,bt-uart = &uart4; + zephyr,bt-hci = &bt_hci_uart; }; leds { @@ -153,6 +153,11 @@ current-speed = <115200>; pinctrl-0 = <&uart4_default>; pinctrl-names = "default"; + + bt_hci_uart: bt_hci_uart { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + }; }; &gpioa { diff --git a/boards/qemu/cortex_m3/qemu_cortex_m3.dts b/boards/qemu/cortex_m3/qemu_cortex_m3.dts index 2e0bd95755f2..b035736a9f7b 100644 --- a/boards/qemu/cortex_m3/qemu_cortex_m3.dts +++ b/boards/qemu/cortex_m3/qemu_cortex_m3.dts @@ -20,7 +20,7 @@ zephyr,flash = &flash0; zephyr,console = &uart0; zephyr,shell-uart = &uart0; - zephyr,bt-uart = &uart2; + zephyr,bt-hci = &bt_hci_uart; zephyr,uart-pipe = &uart1; zephyr,bt-mon-uart = &uart2; }; @@ -39,6 +39,11 @@ &uart2 { status = "okay"; current-speed = <115200>; + + bt_hci_uart: bt_hci_uart { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + }; }; ð { diff --git a/boards/qemu/x86/qemu_x86.dts b/boards/qemu/x86/qemu_x86.dts index 023c551eb47a..907e8a1ec1cb 100644 --- a/boards/qemu/x86/qemu_x86.dts +++ b/boards/qemu/x86/qemu_x86.dts @@ -37,8 +37,8 @@ zephyr,sram = &dram0; zephyr,flash = &flash0; zephyr,console = &uart0; + zephyr,bt-hci = &bt_hci_uart; zephyr,shell-uart = &uart0; - zephyr,bt-uart = &uart1; zephyr,uart-pipe = &uart1; zephyr,bt-mon-uart = &uart1; zephyr,code-partition = &slot0_partition; @@ -125,6 +125,11 @@ &uart1 { status = "okay"; current-speed = <115200>; + + bt_hci_uart: bt_hci_uart { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + }; }; &hpet { diff --git a/boards/shields/frdm_kw41z/frdm_kw41z.overlay b/boards/shields/frdm_kw41z/frdm_kw41z.overlay index 3807b2f6a2da..8e9f14fbfb43 100644 --- a/boards/shields/frdm_kw41z/frdm_kw41z.overlay +++ b/boards/shields/frdm_kw41z/frdm_kw41z.overlay @@ -6,11 +6,16 @@ / { chosen { - zephyr,bt-uart = &arduino_serial; + zephyr,bt-hci = &bt_hci_uart; }; }; &arduino_serial { status = "okay"; current-speed = <115200>; + + bt_hci_uart: bt_hci_uart { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + }; }; diff --git a/boards/st/b_u585i_iot02a/b_u585i_iot02a.dts b/boards/st/b_u585i_iot02a/b_u585i_iot02a.dts index c2df9e5aa5af..b452f4b3eba3 100644 --- a/boards/st/b_u585i_iot02a/b_u585i_iot02a.dts +++ b/boards/st/b_u585i_iot02a/b_u585i_iot02a.dts @@ -19,7 +19,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; - zephyr,bt-uart=&uart4; + zephyr,bt-hci = &bt_hci_uart; }; aliases { @@ -81,4 +81,9 @@ pinctrl-names = "default"; current-speed = <100000>; status = "okay"; + + bt_hci_uart: bt_hci_uart { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + }; }; diff --git a/boards/up-bridge-the-gap/up_squared/up_squared.dts b/boards/up-bridge-the-gap/up_squared/up_squared.dts index beb83af8b199..2e8e763115f6 100644 --- a/boards/up-bridge-the-gap/up_squared/up_squared.dts +++ b/boards/up-bridge-the-gap/up_squared/up_squared.dts @@ -25,7 +25,7 @@ zephyr,sram = &dram0; zephyr,console = &uart0; zephyr,shell-uart = &uart0; - zephyr,bt-uart = &uart1; + zephyr,bt-hci = &bt_hci_uart; zephyr,uart-pipe = &uart1; zephyr,bt-mon-uart = &uart1; }; @@ -49,3 +49,10 @@ }; }; }; + +&uart1 { + bt_hci_uart: bt_hci_uart { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + }; +}; diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 282eda93e972..0a42284c4c89 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -17,6 +17,8 @@ choice BT_HCI_BUS_TYPE config BT_H4 bool "H:4 UART" select BT_UART + default y + depends on DT_HAS_ZEPHYR_BT_HCI_UART_ENABLED help Bluetooth H:4 UART driver. Requires hardware flow control lines to be available. diff --git a/drivers/bluetooth/hci/cyw43xxx.c b/drivers/bluetooth/hci/cyw43xxx.c index 8da6192610db..252b40129d7a 100644 --- a/drivers/bluetooth/hci/cyw43xxx.c +++ b/drivers/bluetooth/hci/cyw43xxx.c @@ -25,11 +25,11 @@ LOG_MODULE_REGISTER(cyw43xxx_driver); #include -BUILD_ASSERT(DT_PROP(DT_CHOSEN(zephyr_bt_uart), hw_flow_control) == 1, - "hw_flow_control must be enabled for HCI H4 UART"); - #define DT_DRV_COMPAT infineon_cyw43xxx_bt_hci +BUILD_ASSERT(DT_PROP(DT_INST_GPARENT(0), hw_flow_control) == 1, + "hw_flow_control must be enabled for HCI H4 UART"); + /* BT settling time after power on */ #define BT_POWER_ON_SETTLING_TIME_MS (500u) diff --git a/drivers/bluetooth/hci/h4.c b/drivers/bluetooth/hci/h4.c index 16b28b52586a..412214c7f322 100644 --- a/drivers/bluetooth/hci/h4.c +++ b/drivers/bluetooth/hci/h4.c @@ -20,7 +20,7 @@ #include #include -#include +#include #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL #include @@ -30,168 +30,183 @@ LOG_MODULE_REGISTER(bt_driver); #include "../util.h" -static K_KERNEL_STACK_DEFINE(rx_thread_stack, CONFIG_BT_DRV_RX_STACK_SIZE); -static struct k_thread rx_thread_data; +#define DT_DRV_COMPAT zephyr_bt_hci_uart -static struct { - struct net_buf *buf; - struct k_fifo fifo; +struct h4_data { + struct { + struct net_buf *buf; + struct k_fifo fifo; - uint16_t remaining; - uint16_t discard; + uint16_t remaining; + uint16_t discard; - bool have_hdr; - bool discardable; + bool have_hdr; + bool discardable; - uint8_t hdr_len; + uint8_t hdr_len; - uint8_t type; - union { - struct bt_hci_evt_hdr evt; - struct bt_hci_acl_hdr acl; - struct bt_hci_iso_hdr iso; - uint8_t hdr[4]; - }; -} rx = { - .fifo = Z_FIFO_INITIALIZER(rx.fifo), -}; + uint8_t type; + union { + struct bt_hci_evt_hdr evt; + struct bt_hci_acl_hdr acl; + struct bt_hci_iso_hdr iso; + uint8_t hdr[4]; + }; + } rx; -static struct { - uint8_t type; - struct net_buf *buf; - struct k_fifo fifo; -} tx = { - .fifo = Z_FIFO_INITIALIZER(tx.fifo), + struct { + uint8_t type; + struct net_buf *buf; + struct k_fifo fifo; + } tx; + + bt_hci_recv_t recv; }; -static const struct device *const h4_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_uart)); +struct h4_config { + const struct device *uart; + k_thread_stack_t *rx_thread_stack; + size_t rx_thread_stack_size; + struct k_thread *rx_thread; +}; -static inline void h4_get_type(void) +static inline void h4_get_type(const struct device *dev) { + const struct h4_config *cfg = dev->config; + struct h4_data *h4 = dev->data; + /* Get packet type */ - if (uart_fifo_read(h4_dev, &rx.type, 1) != 1) { + if (uart_fifo_read(cfg->uart, &h4->rx.type, 1) != 1) { LOG_WRN("Unable to read H:4 packet type"); - rx.type = BT_HCI_H4_NONE; + h4->rx.type = BT_HCI_H4_NONE; return; } - switch (rx.type) { + switch (h4->rx.type) { case BT_HCI_H4_EVT: - rx.remaining = sizeof(rx.evt); - rx.hdr_len = rx.remaining; + h4->rx.remaining = sizeof(h4->rx.evt); + h4->rx.hdr_len = h4->rx.remaining; break; case BT_HCI_H4_ACL: - rx.remaining = sizeof(rx.acl); - rx.hdr_len = rx.remaining; + h4->rx.remaining = sizeof(h4->rx.acl); + h4->rx.hdr_len = h4->rx.remaining; break; case BT_HCI_H4_ISO: if (IS_ENABLED(CONFIG_BT_ISO)) { - rx.remaining = sizeof(rx.iso); - rx.hdr_len = rx.remaining; + h4->rx.remaining = sizeof(h4->rx.iso); + h4->rx.hdr_len = h4->rx.remaining; break; } __fallthrough; default: - LOG_ERR("Unknown H:4 type 0x%02x", rx.type); - rx.type = BT_HCI_H4_NONE; + LOG_ERR("Unknown H:4 type 0x%02x", h4->rx.type); + h4->rx.type = BT_HCI_H4_NONE; } } -static void h4_read_hdr(void) +static void h4_read_hdr(const struct device *dev) { - int bytes_read = rx.hdr_len - rx.remaining; + const struct h4_config *cfg = dev->config; + struct h4_data *h4 = dev->data; + int bytes_read = h4->rx.hdr_len - h4->rx.remaining; int ret; - ret = uart_fifo_read(h4_dev, rx.hdr + bytes_read, rx.remaining); + ret = uart_fifo_read(cfg->uart, h4->rx.hdr + bytes_read, h4->rx.remaining); if (unlikely(ret < 0)) { LOG_ERR("Unable to read from UART (ret %d)", ret); } else { - rx.remaining -= ret; + h4->rx.remaining -= ret; } } -static inline void get_acl_hdr(void) +static inline void get_acl_hdr(const struct device *dev) { - h4_read_hdr(); + struct h4_data *h4 = dev->data; - if (!rx.remaining) { - struct bt_hci_acl_hdr *hdr = &rx.acl; + h4_read_hdr(dev); - rx.remaining = sys_le16_to_cpu(hdr->len); - LOG_DBG("Got ACL header. Payload %u bytes", rx.remaining); - rx.have_hdr = true; + if (!h4->rx.remaining) { + struct bt_hci_acl_hdr *hdr = &h4->rx.acl; + + h4->rx.remaining = sys_le16_to_cpu(hdr->len); + LOG_DBG("Got ACL header. Payload %u bytes", h4->rx.remaining); + h4->rx.have_hdr = true; } } -static inline void get_iso_hdr(void) +static inline void get_iso_hdr(const struct device *dev) { - h4_read_hdr(); + struct h4_data *h4 = dev->data; + + h4_read_hdr(dev); - if (!rx.remaining) { - struct bt_hci_iso_hdr *hdr = &rx.iso; + if (!h4->rx.remaining) { + struct bt_hci_iso_hdr *hdr = &h4->rx.iso; - rx.remaining = bt_iso_hdr_len(sys_le16_to_cpu(hdr->len)); - LOG_DBG("Got ISO header. Payload %u bytes", rx.remaining); - rx.have_hdr = true; + h4->rx.remaining = bt_iso_hdr_len(sys_le16_to_cpu(hdr->len)); + LOG_DBG("Got ISO header. Payload %u bytes", h4->rx.remaining); + h4->rx.have_hdr = true; } } -static inline void get_evt_hdr(void) +static inline void get_evt_hdr(const struct device *dev) { - struct bt_hci_evt_hdr *hdr = &rx.evt; + struct h4_data *h4 = dev->data; + + struct bt_hci_evt_hdr *hdr = &h4->rx.evt; - h4_read_hdr(); + h4_read_hdr(dev); - if (rx.hdr_len == sizeof(*hdr) && rx.remaining < sizeof(*hdr)) { - switch (rx.evt.evt) { + if (h4->rx.hdr_len == sizeof(*hdr) && h4->rx.remaining < sizeof(*hdr)) { + switch (h4->rx.evt.evt) { case BT_HCI_EVT_LE_META_EVENT: - rx.remaining++; - rx.hdr_len++; + h4->rx.remaining++; + h4->rx.hdr_len++; break; #if defined(CONFIG_BT_CLASSIC) case BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI: case BT_HCI_EVT_EXTENDED_INQUIRY_RESULT: - rx.discardable = true; + h4->rx.discardable = true; break; #endif } } - if (!rx.remaining) { - if (rx.evt.evt == BT_HCI_EVT_LE_META_EVENT && - (rx.hdr[sizeof(*hdr)] == BT_HCI_EVT_LE_ADVERTISING_REPORT)) { + if (!h4->rx.remaining) { + if (h4->rx.evt.evt == BT_HCI_EVT_LE_META_EVENT && + (h4->rx.hdr[sizeof(*hdr)] == BT_HCI_EVT_LE_ADVERTISING_REPORT)) { LOG_DBG("Marking adv report as discardable"); - rx.discardable = true; + h4->rx.discardable = true; } - rx.remaining = hdr->len - (rx.hdr_len - sizeof(*hdr)); + h4->rx.remaining = hdr->len - (h4->rx.hdr_len - sizeof(*hdr)); LOG_DBG("Got event header. Payload %u bytes", hdr->len); - rx.have_hdr = true; + h4->rx.have_hdr = true; } } -static inline void copy_hdr(struct net_buf *buf) +static inline void copy_hdr(struct h4_data *h4) { - net_buf_add_mem(buf, rx.hdr, rx.hdr_len); + net_buf_add_mem(h4->rx.buf, h4->rx.hdr, h4->rx.hdr_len); } -static void reset_rx(void) +static void reset_rx(struct h4_data *h4) { - rx.type = BT_HCI_H4_NONE; - rx.remaining = 0U; - rx.have_hdr = false; - rx.hdr_len = 0U; - rx.discardable = false; + h4->rx.type = BT_HCI_H4_NONE; + h4->rx.remaining = 0U; + h4->rx.have_hdr = false; + h4->rx.hdr_len = 0U; + h4->rx.discardable = false; } -static struct net_buf *get_rx(k_timeout_t timeout) +static struct net_buf *get_rx(struct h4_data *h4, k_timeout_t timeout) { - LOG_DBG("type 0x%02x, evt 0x%02x", rx.type, rx.evt.evt); + LOG_DBG("type 0x%02x, evt 0x%02x", h4->rx.type, h4->rx.evt.evt); - switch (rx.type) { + switch (h4->rx.type) { case BT_HCI_H4_EVT: - return bt_buf_get_evt(rx.evt.evt, rx.discardable, timeout); + return bt_buf_get_evt(h4->rx.evt.evt, h4->rx.discardable, timeout); case BT_HCI_H4_ACL: return bt_buf_get_rx(BT_BUF_ACL_IN, timeout); case BT_HCI_H4_ISO: @@ -205,42 +220,44 @@ static struct net_buf *get_rx(k_timeout_t timeout) static void rx_thread(void *p1, void *p2, void *p3) { + const struct device *dev = p1; + const struct h4_config *cfg = dev->config; + struct h4_data *h4 = dev->data; struct net_buf *buf; - ARG_UNUSED(p1); ARG_UNUSED(p2); ARG_UNUSED(p3); LOG_DBG("started"); while (1) { - LOG_DBG("rx.buf %p", rx.buf); + LOG_DBG("rx.buf %p", h4->rx.buf); /* We can only do the allocation if we know the initial * header, since Command Complete/Status events must use the * original command buffer (if available). */ - if (rx.have_hdr && !rx.buf) { - rx.buf = get_rx(K_FOREVER); - LOG_DBG("Got rx.buf %p", rx.buf); - if (rx.remaining > net_buf_tailroom(rx.buf)) { + if (h4->rx.have_hdr && !h4->rx.buf) { + h4->rx.buf = get_rx(h4, K_FOREVER); + LOG_DBG("Got rx.buf %p", h4->rx.buf); + if (h4->rx.remaining > net_buf_tailroom(h4->rx.buf)) { LOG_ERR("Not enough space in buffer"); - rx.discard = rx.remaining; - reset_rx(); + h4->rx.discard = h4->rx.remaining; + reset_rx(h4); } else { - copy_hdr(rx.buf); + copy_hdr(h4); } } /* Let the ISR continue receiving new packets */ - uart_irq_rx_enable(h4_dev); + uart_irq_rx_enable(cfg->uart); - buf = net_buf_get(&rx.fifo, K_FOREVER); + buf = net_buf_get(&h4->rx.fifo, K_FOREVER); do { - uart_irq_rx_enable(h4_dev); + uart_irq_rx_enable(cfg->uart); LOG_DBG("Calling bt_recv(%p)", buf); - bt_recv(buf); + h4->recv(dev, buf); /* Give other threads a chance to run if the ISR * is receiving data so fast that rx.fifo never @@ -248,8 +265,8 @@ static void rx_thread(void *p1, void *p2, void *p3) */ k_yield(); - uart_irq_rx_disable(h4_dev); - buf = net_buf_get(&rx.fifo, K_NO_WAIT); + uart_irq_rx_disable(cfg->uart); + buf = net_buf_get(&h4->rx.fifo, K_NO_WAIT); } while (buf); } } @@ -268,87 +285,93 @@ static size_t h4_discard(const struct device *uart, size_t len) return err; } -static inline void read_payload(void) +static inline void read_payload(const struct device *dev) { + const struct h4_config *cfg = dev->config; + struct h4_data *h4 = dev->data; struct net_buf *buf; int read; - if (!rx.buf) { + if (!h4->rx.buf) { size_t buf_tailroom; - rx.buf = get_rx(K_NO_WAIT); - if (!rx.buf) { - if (rx.discardable) { - LOG_WRN("Discarding event 0x%02x", rx.evt.evt); - rx.discard = rx.remaining; - reset_rx(); + h4->rx.buf = get_rx(h4, K_NO_WAIT); + if (!h4->rx.buf) { + if (h4->rx.discardable) { + LOG_WRN("Discarding event 0x%02x", h4->rx.evt.evt); + h4->rx.discard = h4->rx.remaining; + reset_rx(h4); return; } LOG_WRN("Failed to allocate, deferring to rx_thread"); - uart_irq_rx_disable(h4_dev); + uart_irq_rx_disable(cfg->uart); return; } - LOG_DBG("Allocated rx.buf %p", rx.buf); + LOG_DBG("Allocated rx.buf %p", h4->rx.buf); - buf_tailroom = net_buf_tailroom(rx.buf); - if (buf_tailroom < rx.remaining) { - LOG_ERR("Not enough space in buffer %u/%zu", rx.remaining, buf_tailroom); - rx.discard = rx.remaining; - reset_rx(); + buf_tailroom = net_buf_tailroom(h4->rx.buf); + if (buf_tailroom < h4->rx.remaining) { + LOG_ERR("Not enough space in buffer %u/%zu", h4->rx.remaining, + buf_tailroom); + h4->rx.discard = h4->rx.remaining; + reset_rx(h4); return; } - copy_hdr(rx.buf); + copy_hdr(h4); } - read = uart_fifo_read(h4_dev, net_buf_tail(rx.buf), rx.remaining); + read = uart_fifo_read(cfg->uart, net_buf_tail(h4->rx.buf), h4->rx.remaining); if (unlikely(read < 0)) { LOG_ERR("Failed to read UART (err %d)", read); return; } - net_buf_add(rx.buf, read); - rx.remaining -= read; + net_buf_add(h4->rx.buf, read); + h4->rx.remaining -= read; - LOG_DBG("got %d bytes, remaining %u", read, rx.remaining); - LOG_DBG("Payload (len %u): %s", rx.buf->len, bt_hex(rx.buf->data, rx.buf->len)); + LOG_DBG("got %d bytes, remaining %u", read, h4->rx.remaining); + LOG_DBG("Payload (len %u): %s", h4->rx.buf->len, + bt_hex(h4->rx.buf->data, h4->rx.buf->len)); - if (rx.remaining) { + if (h4->rx.remaining) { return; } - buf = rx.buf; - rx.buf = NULL; + buf = h4->rx.buf; + h4->rx.buf = NULL; - if (rx.type == BT_HCI_H4_EVT) { + if (h4->rx.type == BT_HCI_H4_EVT) { bt_buf_set_type(buf, BT_BUF_EVT); } else { bt_buf_set_type(buf, BT_BUF_ACL_IN); } - reset_rx(); + reset_rx(h4); LOG_DBG("Putting buf %p to rx fifo", buf); - net_buf_put(&rx.fifo, buf); + net_buf_put(&h4->rx.fifo, buf); } -static inline void read_header(void) +static inline void read_header(const struct device *dev) { - switch (rx.type) { + struct h4_data *h4 = dev->data; + + switch (h4->rx.type) { case BT_HCI_H4_NONE: - h4_get_type(); + h4_get_type(dev); return; case BT_HCI_H4_EVT: - get_evt_hdr(); + get_evt_hdr(dev); break; case BT_HCI_H4_ACL: - get_acl_hdr(); + get_acl_hdr(dev); break; case BT_HCI_H4_ISO: if (IS_ENABLED(CONFIG_BT_ISO)) { - get_iso_hdr(); + get_iso_hdr(dev); break; } __fallthrough; @@ -357,41 +380,43 @@ static inline void read_header(void) return; } - if (rx.have_hdr && rx.buf) { - if (rx.remaining > net_buf_tailroom(rx.buf)) { + if (h4->rx.have_hdr && h4->rx.buf) { + if (h4->rx.remaining > net_buf_tailroom(h4->rx.buf)) { LOG_ERR("Not enough space in buffer"); - rx.discard = rx.remaining; - reset_rx(); + h4->rx.discard = h4->rx.remaining; + reset_rx(h4); } else { - copy_hdr(rx.buf); + copy_hdr(h4); } } } -static inline void process_tx(void) +static inline void process_tx(const struct device *dev) { + const struct h4_config *cfg = dev->config; + struct h4_data *h4 = dev->data; int bytes; - if (!tx.buf) { - tx.buf = net_buf_get(&tx.fifo, K_NO_WAIT); - if (!tx.buf) { + if (!h4->tx.buf) { + h4->tx.buf = net_buf_get(&h4->tx.fifo, K_NO_WAIT); + if (!h4->tx.buf) { LOG_ERR("TX interrupt but no pending buffer!"); - uart_irq_tx_disable(h4_dev); + uart_irq_tx_disable(cfg->uart); return; } } - if (!tx.type) { - switch (bt_buf_get_type(tx.buf)) { + if (!h4->tx.type) { + switch (bt_buf_get_type(h4->tx.buf)) { case BT_BUF_ACL_OUT: - tx.type = BT_HCI_H4_ACL; + h4->tx.type = BT_HCI_H4_ACL; break; case BT_BUF_CMD: - tx.type = BT_HCI_H4_CMD; + h4->tx.type = BT_HCI_H4_CMD; break; case BT_BUF_ISO_OUT: if (IS_ENABLED(CONFIG_BT_ISO)) { - tx.type = BT_HCI_H4_ISO; + h4->tx.type = BT_HCI_H4_ISO; break; } __fallthrough; @@ -400,73 +425,79 @@ static inline void process_tx(void) goto done; } - bytes = uart_fifo_fill(h4_dev, &tx.type, 1); + bytes = uart_fifo_fill(cfg->uart, &h4->tx.type, 1); if (bytes != 1) { LOG_WRN("Unable to send H:4 type"); - tx.type = BT_HCI_H4_NONE; + h4->tx.type = BT_HCI_H4_NONE; return; } } - bytes = uart_fifo_fill(h4_dev, tx.buf->data, tx.buf->len); + bytes = uart_fifo_fill(cfg->uart, h4->tx.buf->data, h4->tx.buf->len); if (unlikely(bytes < 0)) { LOG_ERR("Unable to write to UART (err %d)", bytes); } else { - net_buf_pull(tx.buf, bytes); + net_buf_pull(h4->tx.buf, bytes); } - if (tx.buf->len) { + if (h4->tx.buf->len) { return; } done: - tx.type = BT_HCI_H4_NONE; - net_buf_unref(tx.buf); - tx.buf = net_buf_get(&tx.fifo, K_NO_WAIT); - if (!tx.buf) { - uart_irq_tx_disable(h4_dev); + h4->tx.type = BT_HCI_H4_NONE; + net_buf_unref(h4->tx.buf); + h4->tx.buf = net_buf_get(&h4->tx.fifo, K_NO_WAIT); + if (!h4->tx.buf) { + uart_irq_tx_disable(cfg->uart); } } -static inline void process_rx(void) +static inline void process_rx(const struct device *dev) { - LOG_DBG("remaining %u discard %u have_hdr %u rx.buf %p len %u", rx.remaining, rx.discard, - rx.have_hdr, rx.buf, rx.buf ? rx.buf->len : 0); + const struct h4_config *cfg = dev->config; + struct h4_data *h4 = dev->data; + + LOG_DBG("remaining %u discard %u have_hdr %u rx.buf %p len %u", + h4->rx.remaining, h4->rx.discard, h4->rx.have_hdr, h4->rx.buf, + h4->rx.buf ? h4->rx.buf->len : 0); - if (rx.discard) { - rx.discard -= h4_discard(h4_dev, rx.discard); + if (h4->rx.discard) { + h4->rx.discard -= h4_discard(cfg->uart, h4->rx.discard); return; } - if (rx.have_hdr) { - read_payload(); + if (h4->rx.have_hdr) { + read_payload(dev); } else { - read_header(); + read_header(dev); } } -static void bt_uart_isr(const struct device *unused, void *user_data) +static void bt_uart_isr(const struct device *uart, void *user_data) { - ARG_UNUSED(unused); - ARG_UNUSED(user_data); + struct device *dev = user_data; - while (uart_irq_update(h4_dev) && uart_irq_is_pending(h4_dev)) { - if (uart_irq_tx_ready(h4_dev)) { - process_tx(); + while (uart_irq_update(uart) && uart_irq_is_pending(uart)) { + if (uart_irq_tx_ready(uart)) { + process_tx(dev); } - if (uart_irq_rx_ready(h4_dev)) { - process_rx(); + if (uart_irq_rx_ready(uart)) { + process_rx(dev); } } } -static int h4_send(struct net_buf *buf) +static int h4_send(const struct device *dev, struct net_buf *buf) { + const struct h4_config *cfg = dev->config; + struct h4_data *h4 = dev->data; + LOG_DBG("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len); - net_buf_put(&tx.fifo, buf); - uart_irq_tx_enable(h4_dev); + net_buf_put(&h4->tx.fifo, buf); + uart_irq_tx_enable(cfg->uart); return 0; } @@ -477,32 +508,36 @@ static int h4_send(struct net_buf *buf) * * @return 0 on success, negative error value on failure */ -int __weak bt_hci_transport_setup(const struct device *dev) +int __weak bt_hci_transport_setup(const struct device *uart) { - h4_discard(h4_dev, 32); + h4_discard(uart, 32); return 0; } -static int h4_open(void) +static int h4_open(const struct device *dev, bt_hci_recv_t recv) { + const struct h4_config *cfg = dev->config; + struct h4_data *h4 = dev->data; int ret; k_tid_t tid; LOG_DBG(""); - uart_irq_rx_disable(h4_dev); - uart_irq_tx_disable(h4_dev); + uart_irq_rx_disable(cfg->uart); + uart_irq_tx_disable(cfg->uart); - ret = bt_hci_transport_setup(h4_dev); + ret = bt_hci_transport_setup(cfg->uart); if (ret < 0) { return -EIO; } - uart_irq_callback_set(h4_dev, bt_uart_isr); + h4->recv = recv; + + uart_irq_callback_user_data_set(cfg->uart, bt_uart_isr, (void *)dev); - tid = k_thread_create(&rx_thread_data, rx_thread_stack, - K_KERNEL_STACK_SIZEOF(rx_thread_stack), - rx_thread, NULL, NULL, NULL, + tid = k_thread_create(cfg->rx_thread, cfg->rx_thread_stack, + cfg->rx_thread_stack_size, + rx_thread, (void *)dev, NULL, NULL, K_PRIO_COOP(CONFIG_BT_RX_PRIO), 0, K_NO_WAIT); k_thread_name_set(tid, "bt_rx_thread"); @@ -511,8 +546,10 @@ static int h4_open(void) } #if defined(CONFIG_BT_HCI_SETUP) -static int h4_setup(const struct bt_hci_setup_params *params) +static int h4_setup(const struct device *dev, const struct bt_hci_setup_params *params) { + const struct h4_config *cfg = dev->config; + ARG_UNUSED(params); /* Extern bt_h4_vnd_setup function. @@ -523,30 +560,36 @@ static int h4_setup(const struct bt_hci_setup_params *params) */ extern int bt_h4_vnd_setup(const struct device *dev); - return bt_h4_vnd_setup(h4_dev); + return bt_h4_vnd_setup(cfg->uart); } #endif -static const struct bt_hci_driver drv = { - .name = "H:4", - .bus = BT_HCI_DRIVER_BUS_UART, - .open = h4_open, - .send = h4_send, +static const struct bt_hci_driver_api h4_driver_api = { + .open = h4_open, + .send = h4_send, #if defined(CONFIG_BT_HCI_SETUP) - .setup = h4_setup + .setup = h4_setup, #endif }; -static int bt_uart_init(void) -{ - - if (!device_is_ready(h4_dev)) { - return -ENODEV; - } - - bt_hci_driver_register(&drv); - - return 0; -} - -SYS_INIT(bt_uart_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE); +#define BT_UART_DEVICE_INIT(inst) \ + static K_KERNEL_STACK_DEFINE(rx_thread_stack_##inst, CONFIG_BT_DRV_RX_STACK_SIZE); \ + static struct k_thread rx_thread_##inst; \ + static const struct h4_config h4_config_##inst = { \ + .uart = DEVICE_DT_GET(DT_INST_PARENT(inst)), \ + .rx_thread_stack = rx_thread_stack_##inst, \ + .rx_thread_stack_size = K_KERNEL_STACK_SIZEOF(rx_thread_stack_##inst), \ + .rx_thread = &rx_thread_##inst, \ + }; \ + static struct h4_data h4_data_##inst = { \ + .rx = { \ + .fifo = Z_FIFO_INITIALIZER(h4_data_##inst.rx.fifo), \ + }, \ + .tx = { \ + .fifo = Z_FIFO_INITIALIZER(h4_data_##inst.tx.fifo), \ + }, \ + }; \ + DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &h4_data_##inst, &h4_config_##inst, \ + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &h4_driver_api) + +DT_INST_FOREACH_STATUS_OKAY(BT_UART_DEVICE_INIT) diff --git a/dts/bindings/bluetooth/zephyr,bt-hci-uart.yaml b/dts/bindings/bluetooth/zephyr,bt-hci-uart.yaml new file mode 100644 index 000000000000..d14f8e303564 --- /dev/null +++ b/dts/bindings/bluetooth/zephyr,bt-hci-uart.yaml @@ -0,0 +1,13 @@ +# UART Bluetooth HCI device + +description: Bluetooth HCI behind a UART device (H:4) + +compatible: "zephyr,bt-hci-uart" + +include: bt-hci.yaml + +properties: + bt-hci-name: + default: "H:4" + bt-hci-bus: + default: "BT_HCI_BUS_UART" diff --git a/tests/bsim/bluetooth/ll/conn/prj_split_hci_uart.conf b/tests/bsim/bluetooth/ll/conn/prj_split_hci_uart.conf index 58844e5a9510..4c39731af6a4 100644 --- a/tests/bsim/bluetooth/ll/conn/prj_split_hci_uart.conf +++ b/tests/bsim/bluetooth/ll/conn/prj_split_hci_uart.conf @@ -15,4 +15,3 @@ CONFIG_BT_L2CAP_TX_BUF_COUNT=6 CONFIG_BT_HCI=y CONFIG_BT_CTLR=n -CONFIG_BT_H4=y