From 56f470618f93014f5fbd797ab3dbaea200843439 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Sun, 5 May 2024 18:10:59 +0300 Subject: [PATCH] Bluetooth: drivers: Convert H4 (UART) HCI driver to new API Convert the H4 driver to the new HCI driver API. This includes updating also any boards that use the driver, i.e. adding the appropriate devicetree node and chosen property to them. The bsim HCI UART definitions are removed from dts, since these would conflict with the native controller HCI instance (see next commit). Signed-off-by: Johan Hedberg --- .../arduino_giga_r1_stm32h747xx_m7.dts | 19 +- boards/ite/it82xx2_evb/it82xx2_evb.dts | 7 +- boards/ite/it8xxx2_evb/it8xxx2_evb.dts | 7 +- boards/native/nrf_bsim/nrf52_bsim.dts | 2 - boards/nxp/hexiwear/hexiwear_mk64f12.dts | 7 +- boards/qemu/cortex_m3/qemu_cortex_m3.dts | 7 +- boards/qemu/x86/qemu_x86.dts | 7 +- boards/shields/frdm_kw41z/frdm_kw41z.overlay | 7 +- boards/st/b_u585i_iot02a/b_u585i_iot02a.dts | 7 +- .../up_squared/up_squared.dts | 9 +- drivers/bluetooth/hci/Kconfig | 1 + drivers/bluetooth/hci/h4.c | 463 ++++++++++-------- .../bluetooth/zephyr,bt-hci-uart.yaml | 13 + 13 files changed, 334 insertions(+), 222 deletions(-) create mode 100644 dts/bindings/bluetooth/zephyr,bt-hci-uart.yaml 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 4459780243b1b4b..9be5835e5363961 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; zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,canbus = &fdcan2; @@ -98,12 +98,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: bt_hci { + 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/ite/it82xx2_evb/it82xx2_evb.dts b/boards/ite/it82xx2_evb/it82xx2_evb.dts index bd623e969c54f66..925d7bbe0276471 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; zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,flash-controller = &flashctrl; @@ -115,6 +115,11 @@ status = "okay"; current-speed = <460800>; clock-frequency = <1843200>; + + bt_hci: bt_hci { + 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 c111e9092aa15d9..500442ff7fde1ea 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; zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,flash-controller = &flashctrl; @@ -105,6 +105,11 @@ status = "okay"; current-speed = <460800>; clock-frequency = <1843200>; + + bt_hci: bt_hci { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + }; }; &ite_uart1_wrapper { status = "okay"; diff --git a/boards/native/nrf_bsim/nrf52_bsim.dts b/boards/native/nrf_bsim/nrf52_bsim.dts index bb6321c4d531045..fcebaef448a491c 100644 --- a/boards/native/nrf_bsim/nrf52_bsim.dts +++ b/boards/native/nrf_bsim/nrf52_bsim.dts @@ -38,8 +38,6 @@ zephyr,flash = &flash0; /* UART used by the BT controller UART HCI driver by default: */ zephyr,bt-c2h-uart = &uart1; - /* UART used by the BT host UART HCI driver by default: */ - zephyr,bt-uart = &uart1; }; soc { diff --git a/boards/nxp/hexiwear/hexiwear_mk64f12.dts b/boards/nxp/hexiwear/hexiwear_mk64f12.dts index d530b6e9036a89d..c6b547ee3337e3a 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; }; leds { @@ -153,6 +153,11 @@ current-speed = <115200>; pinctrl-0 = <&uart4_default>; pinctrl-names = "default"; + + bt_hci: bt_hci { + 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 2e0bd95755f275a..232ac56900160c1 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; zephyr,uart-pipe = &uart1; zephyr,bt-mon-uart = &uart2; }; @@ -39,6 +39,11 @@ &uart2 { status = "okay"; current-speed = <115200>; + + bt_hci: bt_hci { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + }; }; ð { diff --git a/boards/qemu/x86/qemu_x86.dts b/boards/qemu/x86/qemu_x86.dts index fbe6042c1781cbc..831313a1e8d8e11 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; zephyr,shell-uart = &uart0; - zephyr,bt-uart = &uart1; zephyr,uart-pipe = &uart1; zephyr,bt-mon-uart = &uart1; zephyr,code-partition = &slot0_partition; @@ -126,6 +126,11 @@ &uart1 { status = "okay"; current-speed = <115200>; + + bt_hci: bt_hci { + 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 3807b2f6a2dabbf..653826d9fd7eb67 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; }; }; &arduino_serial { status = "okay"; current-speed = <115200>; + + bt_hci: bt_hci { + 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 33093d701b78dbc..e8e54e3560a9e89 100644 --- a/boards/st/b_u585i_iot02a/b_u585i_iot02a.dts +++ b/boards/st/b_u585i_iot02a/b_u585i_iot02a.dts @@ -17,7 +17,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zephyr,code-partition = &slot0_partition; - zephyr,bt-uart=&uart4; + zephyr,bt-hci = &bt_hci; }; aliases { @@ -71,4 +71,9 @@ pinctrl-names = "default"; current-speed = <100000>; status = "okay"; + + bt_hci: bt_hci { + 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 beb83af8b19966f..6c931fd273e1a04 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; zephyr,uart-pipe = &uart1; zephyr,bt-mon-uart = &uart1; }; @@ -49,3 +49,10 @@ }; }; }; + +&uart1 { + bt_hci: bt_hci { + compatible = "zephyr,bt-hci-uart"; + status = "okay"; + }; +}; diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index ad1d9da2df2a646..5d92ca055282aa2 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -17,6 +17,7 @@ choice BT_HCI_BUS_TYPE config BT_H4 bool "H:4 UART" select BT_UART + 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/h4.c b/drivers/bluetooth/hci/h4.c index 16b28b52586a3da..43184cad1bc11ae 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,184 @@ 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 { + struct bt_hci_info info; + 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; + + h4_read_hdr(dev); - if (!rx.remaining) { - struct bt_hci_acl_hdr *hdr = &rx.acl; + if (!h4->rx.remaining) { + struct bt_hci_acl_hdr *hdr = &h4->rx.acl; - rx.remaining = sys_le16_to_cpu(hdr->len); - LOG_DBG("Got ACL header. Payload %u bytes", rx.remaining); - rx.have_hdr = true; + 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; - if (!rx.remaining) { - struct bt_hci_iso_hdr *hdr = &rx.iso; + h4_read_hdr(dev); - 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; + if (!h4->rx.remaining) { + struct bt_hci_iso_hdr *hdr = &h4->rx.iso; + + 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 +221,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 +266,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 +286,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 +381,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 +426,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; - if (rx.discard) { - rx.discard -= h4_discard(h4_dev, rx.discard); + 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 (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; } @@ -479,30 +511,36 @@ static int h4_send(struct net_buf *buf) */ int __weak bt_hci_transport_setup(const struct device *dev) { - h4_discard(h4_dev, 32); + const struct h4_config *cfg = dev->config; + + h4_discard(cfg->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; - tid = k_thread_create(&rx_thread_data, rx_thread_stack, - K_KERNEL_STACK_SIZEOF(rx_thread_stack), - rx_thread, NULL, NULL, NULL, + uart_irq_callback_user_data_set(cfg->uart, bt_uart_isr, (void *)dev); + + 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"); @@ -510,8 +548,15 @@ static int h4_open(void) return 0; } +static void h4_get_info(const struct device *dev, struct bt_hci_info *info) +{ + const struct h4_config *config = dev->config; + + *info = config->info; +} + #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) { ARG_UNUSED(params); @@ -527,26 +572,34 @@ static int h4_setup(const struct bt_hci_setup_params *params) } #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 = { + .get_info = h4_get_info, + .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 = { \ + .info = BT_DT_HCI_INFO_INST_GET(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 000000000000000..04dca3ed508f892 --- /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: + const: "H:4" + bt-hci-bus: + const: "BT_HCI_BUS_UART"