Bluetooth: controller: Update to new HCI driver API

Update the native controller to the new HCI driver API. The devicetree
node is placed under existing `radio` nodes, which seemed like the most
intuitive option.

Signed-off-by: Johan Hedberg <johan.hedberg@gmail.com>
This commit is contained in:
Johan Hedberg 2024-05-05 18:12:49 +03:00 committed by Anas Nashif
parent 3482a3be53
commit 44e0f5fee3
17 changed files with 145 additions and 36 deletions

View file

@ -19,9 +19,14 @@
zephyr,shell-uart = &lpuart0; zephyr,shell-uart = &lpuart0;
zephyr,uart-pipe = &lpuart0; zephyr,uart-pipe = &lpuart0;
zephyr,code-partition = &slot0_partition; zephyr,code-partition = &slot0_partition;
zephyr,bt-hci = &bt_hci_controller;
}; };
}; };
&bt_hci_controller {
status = "okay";
};
&m4_flash { &m4_flash {
/* /*
* For more information, see: * For more information, see:

View file

@ -12,7 +12,7 @@
menuconfig BT_DRIVERS menuconfig BT_DRIVERS
bool "Bluetooth drivers" bool "Bluetooth drivers"
default y default y
depends on BT && !BT_CTLR depends on BT
if BT_DRIVERS if BT_DRIVERS

View file

@ -5,6 +5,7 @@
/ { / {
chosen { chosen {
zephyr,bt-hci = &bt_hci_controller;
zephyr,entropy = &rng; zephyr,entropy = &rng;
zephyr,flash-controller = &flash_controller; zephyr,flash-controller = &flash_controller;
}; };
@ -73,6 +74,11 @@
reg = <0x40001000 0x1000>; reg = <0x40001000 0x1000>;
interrupts = <1 NRF_DEFAULT_IRQ_PRIORITY>; interrupts = <1 NRF_DEFAULT_IRQ_PRIORITY>;
status = "okay"; status = "okay";
bt_hci_controller: bt_hci_controller {
compatible = "zephyr,bt-hci-ll-sw-split";
status = "okay";
};
}; };
uart0: uart@40002000 { uart0: uart@40002000 {

View file

@ -9,6 +9,7 @@
/ { / {
chosen { chosen {
zephyr,bt-hci = &bt_hci_controller;
zephyr,entropy = &rng; zephyr,entropy = &rng;
zephyr,flash-controller = &flash_controller; zephyr,flash-controller = &flash_controller;
}; };
@ -86,6 +87,11 @@
interrupts = <1 NRF_DEFAULT_IRQ_PRIORITY>; interrupts = <1 NRF_DEFAULT_IRQ_PRIORITY>;
status = "okay"; status = "okay";
ble-2mbps-supported; ble-2mbps-supported;
bt_hci_controller: bt_hci_controller {
compatible = "zephyr,bt-hci-ll-sw-split";
status = "okay";
};
}; };
uart0: uart@40002000 { uart0: uart@40002000 {

View file

@ -5,6 +5,7 @@
/ { / {
chosen { chosen {
zephyr,bt-hci = &bt_hci_controller;
zephyr,entropy = &rng; zephyr,entropy = &rng;
zephyr,flash-controller = &flash_controller; zephyr,flash-controller = &flash_controller;
}; };
@ -90,6 +91,11 @@
interrupts = <1 NRF_DEFAULT_IRQ_PRIORITY>; interrupts = <1 NRF_DEFAULT_IRQ_PRIORITY>;
status = "okay"; status = "okay";
ble-2mbps-supported; ble-2mbps-supported;
bt_hci_controller: bt_hci_controller {
compatible = "zephyr,bt-hci-ll-sw-split";
status = "okay";
};
}; };
uart0: uart@40002000 { uart0: uart@40002000 {

View file

@ -9,6 +9,7 @@
/ { / {
chosen { chosen {
zephyr,bt-hci = &bt_hci_controller;
zephyr,entropy = &rng; zephyr,entropy = &rng;
zephyr,flash-controller = &flash_controller; zephyr,flash-controller = &flash_controller;
}; };
@ -102,6 +103,11 @@
compatible = "nordic,nrf-ieee802154"; compatible = "nordic,nrf-ieee802154";
status = "disabled"; status = "disabled";
}; };
bt_hci_controller: bt_hci_controller {
compatible = "zephyr,bt-hci-ll-sw-split";
status = "okay";
};
}; };
uart0: uart@40002000 { uart0: uart@40002000 {

View file

@ -10,6 +10,7 @@
/ { / {
chosen { chosen {
zephyr,bt-hci = &bt_hci_controller;
zephyr,entropy = &rng; zephyr,entropy = &rng;
zephyr,flash-controller = &flash_controller; zephyr,flash-controller = &flash_controller;
}; };
@ -98,6 +99,11 @@
compatible = "nordic,nrf-ieee802154"; compatible = "nordic,nrf-ieee802154";
status = "disabled"; status = "disabled";
}; };
bt_hci_controller: bt_hci_controller {
compatible = "zephyr,bt-hci-ll-sw-split";
status = "okay";
};
}; };
uart0: uart@40002000 { uart0: uart@40002000 {

View file

@ -5,6 +5,7 @@
/ { / {
chosen { chosen {
zephyr,bt-hci = &bt_hci_controller;
zephyr,entropy = &rng; zephyr,entropy = &rng;
zephyr,flash-controller = &flash_controller; zephyr,flash-controller = &flash_controller;
}; };
@ -90,6 +91,11 @@
interrupts = <1 NRF_DEFAULT_IRQ_PRIORITY>; interrupts = <1 NRF_DEFAULT_IRQ_PRIORITY>;
status = "okay"; status = "okay";
ble-2mbps-supported; ble-2mbps-supported;
bt_hci_controller: bt_hci_controller {
compatible = "zephyr,bt-hci-ll-sw-split";
status = "okay";
};
}; };
uart0: uart@40002000 { uart0: uart@40002000 {

View file

@ -9,6 +9,7 @@
/ { / {
chosen { chosen {
zephyr,bt-hci = &bt_hci_controller;
zephyr,entropy = &rng; zephyr,entropy = &rng;
zephyr,flash-controller = &flash_controller; zephyr,flash-controller = &flash_controller;
}; };
@ -97,6 +98,11 @@
compatible = "nordic,nrf-ieee802154"; compatible = "nordic,nrf-ieee802154";
status = "disabled"; status = "disabled";
}; };
bt_hci_controller: bt_hci_controller {
compatible = "zephyr,bt-hci-ll-sw-split";
status = "okay";
};
}; };
uart0: uart@40002000 { uart0: uart@40002000 {

View file

@ -5,6 +5,7 @@
/ { / {
chosen { chosen {
zephyr,bt-hci = &bt_hci_controller;
zephyr,entropy = &rng; zephyr,entropy = &rng;
zephyr,flash-controller = &flash_controller; zephyr,flash-controller = &flash_controller;
}; };
@ -92,6 +93,11 @@
compatible = "nordic,nrf-ieee802154"; compatible = "nordic,nrf-ieee802154";
status = "disabled"; status = "disabled";
}; };
bt_hci_controller: bt_hci_controller {
compatible = "zephyr,bt-hci-ll-sw-split";
status = "okay";
};
}; };
uart0: uart@40002000 { uart0: uart@40002000 {

View file

@ -9,6 +9,7 @@
/ { / {
chosen { chosen {
zephyr,bt-hci = &bt_hci_controller;
zephyr,entropy = &rng; zephyr,entropy = &rng;
zephyr,flash-controller = &flash_controller; zephyr,flash-controller = &flash_controller;
}; };
@ -100,6 +101,11 @@
compatible = "nordic,nrf-ieee802154"; compatible = "nordic,nrf-ieee802154";
status = "disabled"; status = "disabled";
}; };
bt_hci_controller: bt_hci_controller {
compatible = "zephyr,bt-hci-ll-sw-split";
status = "okay";
};
}; };
rng: random@41009000 { rng: random@41009000 {

View file

@ -17,6 +17,10 @@ cpuflpr_vevif: &cpuflpr_vevif_remote {};
/delete-node/ &cpuflpr_clic; /delete-node/ &cpuflpr_clic;
/ { / {
chosen {
zephyr,bt-hci = &bt_hci_controller;
};
soc { soc {
compatible = "simple-bus"; compatible = "simple-bus";
interrupt-parent = <&cpuapp_nvic>; interrupt-parent = <&cpuapp_nvic>;
@ -29,6 +33,10 @@ cpuflpr_vevif: &cpuflpr_vevif_remote {};
}; };
}; };
&bt_hci_controller {
status = "okay";
};
&cpuapp_ppb { &cpuapp_ppb {
compatible = "simple-bus"; compatible = "simple-bus";
ranges; ranges;

View file

@ -0,0 +1,13 @@
description: Bluetooth HCI provided by the native Zephyr Bluetooth Controller
compatible: "zephyr,bt-hci-ll-sw-split"
include: bt-hci.yaml
properties:
bt-hci-name:
default: "Controller"
bt-hci-bus:
default: "BT_HCI_BUS_VIRTUAL"
bt-hci-quirks:
default: ["BT_HCI_QUIRK_NO_AUTO_DLE"]

View file

@ -264,6 +264,11 @@
compatible = "nordic,nrf-ieee802154"; compatible = "nordic,nrf-ieee802154";
status = "disabled"; status = "disabled";
}; };
bt_hci_controller: bt_hci_controller {
compatible = "zephyr,bt-hci-ll-sw-split";
status = "disabled";
};
}; };
dppic20: dppic@c2000 { dppic20: dppic@c2000 {

View file

@ -524,5 +524,10 @@
write-block-size = <8>; write-block-size = <8>;
}; };
}; };
bt_hci_controller: bt_hci_controller {
compatible = "zephyr,bt-hci-ll-sw-split";
status = "disabled";
};
}; };
}; };

View file

@ -133,6 +133,7 @@ endchoice
config BT_CTLR_HCI config BT_CTLR_HCI
bool "Host Controller Interface (HCI)" bool "Host Controller Interface (HCI)"
default y default y
depends on DT_HAS_ZEPHYR_BT_HCI_LL_SW_SPLIT_ENABLED
help help
Enable the Host Controller interface (HCI) in the Controller. Enable the Host Controller interface (HCI) in the Controller.
This should almost always be enabled, except in a few special This should almost always be enabled, except in a few special

View file

@ -21,7 +21,7 @@
#include <zephyr/sys/byteorder.h> #include <zephyr/sys/byteorder.h>
#include <zephyr/bluetooth/hci_types.h> #include <zephyr/bluetooth/hci_types.h>
#include <zephyr/drivers/bluetooth/hci_driver.h> #include <zephyr/drivers/bluetooth.h>
#ifdef CONFIG_CLOCK_CONTROL_NRF #ifdef CONFIG_CLOCK_CONTROL_NRF
#include <zephyr/drivers/clock_control/nrf_clock_control.h> #include <zephyr/drivers/clock_control/nrf_clock_control.h>
@ -66,6 +66,12 @@
#include <zephyr/logging/log.h> #include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bt_ctlr_hci_driver); LOG_MODULE_REGISTER(bt_ctlr_hci_driver);
#define DT_DRV_COMPAT zephyr_bt_hci_ll_sw_split
struct hci_driver_data {
bt_hci_recv_t recv;
};
static struct k_sem sem_prio_recv; static struct k_sem sem_prio_recv;
static struct k_fifo recv_fifo; static struct k_fifo recv_fifo;
@ -120,8 +126,10 @@ static inline uint8_t bt_hci_evt_get_flags(uint8_t evt)
* tree) 'recv blocking' API to the normal single-receiver * tree) 'recv blocking' API to the normal single-receiver
* `bt_recv` API. * `bt_recv` API.
*/ */
static int bt_recv_prio(struct net_buf *buf) static int bt_recv_prio(const struct device *dev, struct net_buf *buf)
{ {
struct hci_driver_data *data = dev->data;
if (bt_buf_get_type(buf) == BT_BUF_EVT) { if (bt_buf_get_type(buf) == BT_BUF_EVT) {
struct bt_hci_evt_hdr *hdr = (void *)buf->data; struct bt_hci_evt_hdr *hdr = (void *)buf->data;
uint8_t evt_flags = bt_hci_evt_get_flags(hdr->evt); uint8_t evt_flags = bt_hci_evt_get_flags(hdr->evt);
@ -133,7 +141,7 @@ static int bt_recv_prio(struct net_buf *buf)
} }
} }
return bt_recv(buf); return data->recv(dev, buf);
} }
#if defined(CONFIG_BT_CTLR_ISO) #if defined(CONFIG_BT_CTLR_ISO)
@ -167,6 +175,8 @@ isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx,
const struct isoal_emitted_sdu_frag *sdu_frag, const struct isoal_emitted_sdu_frag *sdu_frag,
const struct isoal_emitted_sdu *sdu) const struct isoal_emitted_sdu *sdu)
{ {
const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0));
struct hci_driver_data *data = dev->data;
struct bt_hci_iso_sdu_ts_hdr *sdu_hdr; struct bt_hci_iso_sdu_ts_hdr *sdu_hdr;
uint16_t packet_status_flag; uint16_t packet_status_flag;
struct bt_hci_iso_hdr *hdr; struct bt_hci_iso_hdr *hdr;
@ -249,7 +259,7 @@ isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx,
hdr->len = sys_cpu_to_le16(len); hdr->len = sys_cpu_to_le16(len);
/* send fragment up the chain */ /* send fragment up the chain */
bt_recv(buf); data->recv(dev, buf);
} }
return ISOAL_STATUS_OK; return ISOAL_STATUS_OK;
@ -322,6 +332,8 @@ static struct net_buf *process_prio_evt(struct node_rx_pdu *node_rx,
*/ */
static void prio_recv_thread(void *p1, void *p2, void *p3) static void prio_recv_thread(void *p1, void *p2, void *p3)
{ {
const struct device *dev = p1;
while (1) { while (1) {
struct node_rx_pdu *node_rx; struct node_rx_pdu *node_rx;
struct net_buf *buf; struct net_buf *buf;
@ -358,7 +370,7 @@ static void prio_recv_thread(void *p1, void *p2, void *p3)
false, K_FOREVER); false, K_FOREVER);
hci_num_cmplt_encode(buf, handle, num_cmplt); hci_num_cmplt_encode(buf, handle, num_cmplt);
LOG_DBG("Num Complete: 0x%04x:%u", handle, num_cmplt); LOG_DBG("Num Complete: 0x%04x:%u", handle, num_cmplt);
bt_recv_prio(buf); bt_recv_prio(dev, buf);
k_yield(); k_yield();
#endif /* CONFIG_BT_CONN || CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */ #endif /* CONFIG_BT_CONN || CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
} }
@ -382,7 +394,7 @@ static void prio_recv_thread(void *p1, void *p2, void *p3)
ll_rx_mem_release((void **)&node_rx); ll_rx_mem_release((void **)&node_rx);
} }
bt_recv_prio(buf); bt_recv_prio(dev, buf);
/* bt_recv_prio would not release normal evt /* bt_recv_prio would not release normal evt
* buf. * buf.
*/ */
@ -661,6 +673,9 @@ static inline struct net_buf *process_hbuf(struct node_rx_pdu *n)
*/ */
static void recv_thread(void *p1, void *p2, void *p3) static void recv_thread(void *p1, void *p2, void *p3)
{ {
const struct device *dev = p1;
struct hci_driver_data *data = dev->data;
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
/* @todo: check if the events structure really needs to be static */ /* @todo: check if the events structure really needs to be static */
static struct k_poll_event events[2] = { static struct k_poll_event events[2] = {
@ -719,7 +734,7 @@ static void recv_thread(void *p1, void *p2, void *p3)
LOG_DBG("Packet in: type:%u len:%u", bt_buf_get_type(frag), LOG_DBG("Packet in: type:%u len:%u", bt_buf_get_type(frag),
frag->len); frag->len);
bt_recv(frag); data->recv(dev, frag);
} else { } else {
net_buf_unref(frag); net_buf_unref(frag);
} }
@ -729,7 +744,7 @@ static void recv_thread(void *p1, void *p2, void *p3)
} }
} }
static int cmd_handle(struct net_buf *buf) static int cmd_handle(const struct device *dev, struct net_buf *buf)
{ {
struct node_rx_pdu *node_rx = NULL; struct node_rx_pdu *node_rx = NULL;
struct net_buf *evt; struct net_buf *evt;
@ -737,7 +752,7 @@ static int cmd_handle(struct net_buf *buf)
evt = hci_cmd_handle(buf, (void **) &node_rx); evt = hci_cmd_handle(buf, (void **) &node_rx);
if (evt) { if (evt) {
LOG_DBG("Replying with event of %u bytes", evt->len); LOG_DBG("Replying with event of %u bytes", evt->len);
bt_recv_prio(evt); bt_recv_prio(dev, evt);
if (node_rx) { if (node_rx) {
LOG_DBG("RX node enqueue"); LOG_DBG("RX node enqueue");
@ -750,7 +765,7 @@ static int cmd_handle(struct net_buf *buf)
} }
#if defined(CONFIG_BT_CONN) #if defined(CONFIG_BT_CONN)
static int acl_handle(struct net_buf *buf) static int acl_handle(const struct device *dev, struct net_buf *buf)
{ {
struct net_buf *evt; struct net_buf *evt;
int err; int err;
@ -758,7 +773,7 @@ static int acl_handle(struct net_buf *buf)
err = hci_acl_handle(buf, &evt); err = hci_acl_handle(buf, &evt);
if (evt) { if (evt) {
LOG_DBG("Replying with event of %u bytes", evt->len); LOG_DBG("Replying with event of %u bytes", evt->len);
bt_recv_prio(evt); bt_recv_prio(dev, evt);
} }
return err; return err;
@ -766,7 +781,7 @@ static int acl_handle(struct net_buf *buf)
#endif /* CONFIG_BT_CONN */ #endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO)
static int iso_handle(struct net_buf *buf) static int iso_handle(const struct device *dev, struct net_buf *buf)
{ {
struct net_buf *evt; struct net_buf *evt;
int err; int err;
@ -774,14 +789,14 @@ static int iso_handle(struct net_buf *buf)
err = hci_iso_handle(buf, &evt); err = hci_iso_handle(buf, &evt);
if (evt) { if (evt) {
LOG_DBG("Replying with event of %u bytes", evt->len); LOG_DBG("Replying with event of %u bytes", evt->len);
bt_recv_prio(evt); bt_recv_prio(dev, evt);
} }
return err; return err;
} }
#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */ #endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
static int hci_driver_send(struct net_buf *buf) static int hci_driver_send(const struct device *dev, struct net_buf *buf)
{ {
uint8_t type; uint8_t type;
int err; int err;
@ -797,15 +812,15 @@ static int hci_driver_send(struct net_buf *buf)
switch (type) { switch (type) {
#if defined(CONFIG_BT_CONN) #if defined(CONFIG_BT_CONN)
case BT_BUF_ACL_OUT: case BT_BUF_ACL_OUT:
err = acl_handle(buf); err = acl_handle(dev, buf);
break; break;
#endif /* CONFIG_BT_CONN */ #endif /* CONFIG_BT_CONN */
case BT_BUF_CMD: case BT_BUF_CMD:
err = cmd_handle(buf); err = cmd_handle(dev, buf);
break; break;
#if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO) #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO)
case BT_BUF_ISO_OUT: case BT_BUF_ISO_OUT:
err = iso_handle(buf); err = iso_handle(dev, buf);
break; break;
#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */ #endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
default: default:
@ -822,8 +837,9 @@ static int hci_driver_send(struct net_buf *buf)
return err; return err;
} }
static int hci_driver_open(void) static int hci_driver_open(const struct device *dev, bt_hci_recv_t recv)
{ {
struct hci_driver_data *data = dev->data;
uint32_t err; uint32_t err;
DEBUG_INIT(); DEBUG_INIT();
@ -837,6 +853,8 @@ static int hci_driver_open(void)
return err; return err;
} }
data->recv = recv;
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL) #if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
k_poll_signal_init(&hbuf_signal); k_poll_signal_init(&hbuf_signal);
hci_init(&hbuf_signal); hci_init(&hbuf_signal);
@ -846,13 +864,13 @@ static int hci_driver_open(void)
k_thread_create(&prio_recv_thread_data, prio_recv_thread_stack, k_thread_create(&prio_recv_thread_data, prio_recv_thread_stack,
K_KERNEL_STACK_SIZEOF(prio_recv_thread_stack), K_KERNEL_STACK_SIZEOF(prio_recv_thread_stack),
prio_recv_thread, NULL, NULL, NULL, prio_recv_thread, (void *)dev, NULL, NULL,
K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO), 0, K_NO_WAIT); K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO), 0, K_NO_WAIT);
k_thread_name_set(&prio_recv_thread_data, "BT RX pri"); k_thread_name_set(&prio_recv_thread_data, "BT RX pri");
k_thread_create(&recv_thread_data, recv_thread_stack, k_thread_create(&recv_thread_data, recv_thread_stack,
K_KERNEL_STACK_SIZEOF(recv_thread_stack), K_KERNEL_STACK_SIZEOF(recv_thread_stack),
recv_thread, NULL, NULL, NULL, recv_thread, (void *)dev, NULL, NULL,
K_PRIO_COOP(CONFIG_BT_RX_PRIO), 0, K_NO_WAIT); K_PRIO_COOP(CONFIG_BT_RX_PRIO), 0, K_NO_WAIT);
k_thread_name_set(&recv_thread_data, "BT RX"); k_thread_name_set(&recv_thread_data, "BT RX");
@ -861,8 +879,10 @@ static int hci_driver_open(void)
return 0; return 0;
} }
static int hci_driver_close(void) static int hci_driver_close(const struct device *dev)
{ {
struct hci_driver_data *data = dev->data;
/* Resetting the LL stops all roles */ /* Resetting the LL stops all roles */
ll_deinit(); ll_deinit();
@ -872,24 +892,22 @@ static int hci_driver_close(void)
/* Abort RX thread */ /* Abort RX thread */
k_thread_abort(&recv_thread_data); k_thread_abort(&recv_thread_data);
/* Clear the (host) receive callback */
data->recv = NULL;
return 0; return 0;
} }
static const struct bt_hci_driver drv = { static const struct bt_hci_driver_api hci_driver_api = {
.name = "Controller", .open = hci_driver_open,
.bus = BT_HCI_DRIVER_BUS_VIRTUAL,
.quirks = BT_QUIRK_NO_AUTO_DLE,
.open = hci_driver_open,
.close = hci_driver_close, .close = hci_driver_close,
.send = hci_driver_send, .send = hci_driver_send,
}; };
static int hci_driver_init(void) #define BT_HCI_CONTROLLER_INIT(inst) \
{ static struct hci_driver_data data_##inst; \
DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &data_##inst, NULL, POST_KERNEL, \
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &hci_driver_api)
bt_hci_driver_register(&drv); /* Only a single instance is supported */
BT_HCI_CONTROLLER_INIT(0)
return 0;
}
SYS_INIT(hci_driver_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);