|  | /* hci_stm32wb0.c - HCI driver for stm32wb0x */ | 
|  |  | 
|  | /* | 
|  | * Copyright (c) 2024 STMicroelectronics | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #include <zephyr/init.h> | 
|  | #include <zephyr/sys/byteorder.h> | 
|  | #include <zephyr/bluetooth/hci_types.h> | 
|  | #include <zephyr/drivers/bluetooth.h> | 
|  | #include "bleplat_cntr.h" | 
|  | #include "ble_stack.h" | 
|  | #include "stm32wb0x_hal_radio_timer.h" | 
|  | #include "miscutil.h" | 
|  | #include "pka_manager.h" | 
|  | #include "app_conf.h" | 
|  | #include "dtm_cmd_db.h" | 
|  | #include "dm_alloc.h" | 
|  | #include "aci_adv_nwk.h" | 
|  | #include "app_common.h" | 
|  | #include "hw_rng.h" | 
|  | #include "hw_aes.h" | 
|  | #include "hw_pka.h" | 
|  |  | 
|  | #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL | 
|  | #include <zephyr/logging/log.h> | 
|  | LOG_MODULE_REGISTER(bt_driver); | 
|  |  | 
|  | #define DT_DRV_COMPAT st_hci_stm32wb0 | 
|  |  | 
|  | /* Max HS startup time expressed in system time (1953 us / 2.4414 us) */ | 
|  | #define MAX_HS_STARTUP_TIME 320 | 
|  | #define BLE_WKUP_PRIO       0 | 
|  | #define BLE_WKUP_FLAGS      0 | 
|  | #define BLE_TX_RX_PRIO      0 | 
|  | #define BLE_TX_RX_FLAGS     0 | 
|  | #define CPU_WKUP_PRIO       1 | 
|  | #define CPU_WKUP_FLAGS      0 | 
|  | #define BLE_ERROR_PRIO      3 | 
|  | #define BLE_ERROR_FLAGS     0 | 
|  | #define BLE_RXTX_SEQ_PRIO   3 | 
|  | #define BLE_RXTX_SEQ_FLAGS  0 | 
|  | #define PKA_PRIO	    2 | 
|  | #define PKA_FLAGS	    0 | 
|  |  | 
|  | #define MAX_EVENT_SIZE		 259 | 
|  | #define MAX_ISO_DATA_LOAD_LENGTH 512 | 
|  |  | 
|  | #define PACKET_TYPE	     0 | 
|  | #define EVT_HEADER_TYPE      0 | 
|  | #define EVT_HEADER_EVENT     1 | 
|  | #define EVT_HEADER_SIZE      2 | 
|  | #define EVT_LE_META_SUBEVENT 3 | 
|  | #define EVT_VENDOR_CODE_LSB  3 | 
|  | #define EVT_VENDOR_CODE_MSB  4 | 
|  |  | 
|  | static uint32_t __noinit dyn_alloc_a[BLE_DYN_ALLOC_SIZE >> 2]; | 
|  | static uint8_t buffer_out_mem[MAX_EVENT_SIZE]; | 
|  | static struct k_work_delayable hal_radio_timer_work, ble_stack_work; | 
|  |  | 
|  | static struct net_buf *get_rx(uint8_t *msg); | 
|  | static PKA_HandleTypeDef hpka; | 
|  |  | 
|  | #if CONFIG_BT_EXT_ADV | 
|  | static uint32_t __noinit aci_adv_nwk_buffer[CFG_BLE_ADV_NWK_BUFFER_SIZE >> 2]; | 
|  | #endif /* CONFIG_BT_EXT_ADV */ | 
|  |  | 
|  | struct hci_data { | 
|  | bt_hci_recv_t recv; | 
|  | }; | 
|  |  | 
|  | /* Dummy implementation */ | 
|  | int BLEPLAT_NvmGet(void) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void blestack_process(struct k_work *work) | 
|  | { | 
|  | BLE_STACK_Tick(); | 
|  | if (BLE_STACK_SleepCheck() == 0) { | 
|  | k_work_reschedule(&ble_stack_work, K_NO_WAIT); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void vtimer_process(struct k_work *work) | 
|  | { | 
|  | HAL_RADIO_TIMER_Tick(); | 
|  | } | 
|  |  | 
|  | /* "If, since the last power-on or reset, the Host has ever issued a legacy | 
|  | * advertising command and then issues an extended advertising command, or | 
|  | * has ever issued an extended advertising command and then issues a legacy | 
|  | * advertising command, the Controller shall return the error code Command | 
|  | * Disallowed (0x0C)." | 
|  | * This function returns 1 if an error has to be given. | 
|  | */ | 
|  | static uint8_t check_legacy_extended_call(uint16_t opcode, uint8_t *buffer_out) | 
|  | { | 
|  | static bool legacy_cmd_issued, extended_cmd_issued; | 
|  | bool allowed = true; | 
|  |  | 
|  | if (IN_RANGE(opcode, BT_HCI_OP_LE_SET_ADV_PARAM, BT_HCI_OP_LE_CREATE_CONN)) { | 
|  | if (extended_cmd_issued) { | 
|  | allowed = false; /* Error */ | 
|  | LOG_ERR("Extended not allowed"); | 
|  | } else { | 
|  | legacy_cmd_issued = true; | 
|  | allowed = true; /* OK */ | 
|  | } | 
|  | } else if ((opcode >= BT_HCI_OP_LE_SET_EXT_ADV_PARAM) && | 
|  | (opcode <= BT_HCI_OP_LE_READ_PER_ADV_LIST_SIZE)) { | 
|  | if (legacy_cmd_issued) { | 
|  | allowed = false; /* Error */ | 
|  | LOG_ERR("Legacy not allowed"); | 
|  | } else { | 
|  | extended_cmd_issued = true; | 
|  | allowed = true; /* OK */ | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!allowed) { | 
|  | struct bt_hci_evt_hdr *evt_header = (struct bt_hci_evt_hdr *)(buffer_out + 1); | 
|  |  | 
|  | *buffer_out = BT_HCI_H4_EVT; | 
|  | if (opcode == BT_HCI_OP_LE_CREATE_CONN || opcode == BT_HCI_OP_LE_EXT_CREATE_CONN || | 
|  | opcode == BT_HCI_OP_LE_PER_ADV_CREATE_SYNC) { | 
|  | struct bt_hci_evt_cmd_status *params = | 
|  | (struct bt_hci_evt_cmd_status *)(buffer_out + 3); | 
|  |  | 
|  | evt_header->evt = BT_HCI_EVT_CMD_STATUS; | 
|  | evt_header->len = 4; | 
|  | params->status = BT_HCI_ERR_CMD_DISALLOWED; | 
|  | params->ncmd = 1; | 
|  | params->opcode = sys_cpu_to_le16(opcode); | 
|  | } else { | 
|  | struct bt_hci_evt_cmd_complete *params = | 
|  | (struct bt_hci_evt_cmd_complete *)(buffer_out + 3); | 
|  |  | 
|  | evt_header->evt = BT_HCI_EVT_CMD_COMPLETE; | 
|  | evt_header->len = 4; | 
|  | params->ncmd = 1; | 
|  | params->opcode = sys_cpu_to_le16(opcode); | 
|  | buffer_out[6] = BT_HCI_ERR_CMD_DISALLOWED; | 
|  | } | 
|  | return 7; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Process Commands */ | 
|  | static uint16_t process_command(uint8_t *buffer, uint16_t buffer_in_length, uint8_t *buffer_out, | 
|  | uint16_t buffer_out_max_length) | 
|  | { | 
|  | uint32_t i; | 
|  | uint16_t ret_val; | 
|  | uint16_t op_code; | 
|  | uint8_t *buffer_in = buffer + sizeof(struct bt_hci_cmd_hdr); | 
|  | struct bt_hci_cmd_hdr *hdr = (struct bt_hci_cmd_hdr *)buffer; | 
|  |  | 
|  | buffer_in_length -= sizeof(struct bt_hci_cmd_hdr); | 
|  | op_code = hdr->opcode; | 
|  | ret_val = check_legacy_extended_call(op_code, buffer_out); | 
|  | if (ret_val != 0) { | 
|  | LOG_ERR("ret_val: %d", ret_val); | 
|  | return ret_val; | 
|  | } | 
|  |  | 
|  | for (i = 0; hci_command_table[i].opcode != 0; i++) { | 
|  | if (op_code == hci_command_table[i].opcode) { | 
|  | ret_val = hci_command_table[i].execute(buffer_in, buffer_in_length, | 
|  | buffer_out, buffer_out_max_length); | 
|  | /* add get crash handler */ | 
|  | return ret_val; | 
|  | } | 
|  | } | 
|  |  | 
|  | struct bt_hci_evt_hdr *evt_header = (struct bt_hci_evt_hdr *)(buffer_out + 1); | 
|  | struct bt_hci_evt_cmd_status *params = (struct bt_hci_evt_cmd_status *)(buffer_out + 3); | 
|  |  | 
|  | *buffer_out = BT_HCI_H4_EVT; | 
|  | evt_header->evt = BT_HCI_EVT_CMD_STATUS; | 
|  | evt_header->len = 4; | 
|  | params->status = BT_HCI_ERR_UNKNOWN_CMD; | 
|  | params->ncmd = 1; | 
|  | params->opcode = sys_cpu_to_le16(op_code); | 
|  | return 7; | 
|  | } | 
|  |  | 
|  | void send_event(uint8_t *buffer_out, uint16_t buffer_out_length, int8_t overflow_index) | 
|  | { | 
|  | ARG_UNUSED(buffer_out_length); | 
|  | ARG_UNUSED(overflow_index); | 
|  |  | 
|  | const struct device *dev = DEVICE_DT_GET(DT_DRV_INST(0)); | 
|  | struct hci_data *hci = dev->data; | 
|  | /* Construct net_buf from event data */ | 
|  | struct net_buf *buf = get_rx(buffer_out); | 
|  |  | 
|  | if (buf) { | 
|  | /* Handle the received HCI data */ | 
|  | LOG_DBG("New event %p len %u type %u", buf, buf->len, bt_buf_get_type(buf)); | 
|  | hci->recv(dev, buf); | 
|  | } else { | 
|  | LOG_ERR("Buf is null"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void HAL_RADIO_TIMER_TxRxWakeUpCallback(void) | 
|  | { | 
|  | k_work_schedule(&hal_radio_timer_work, K_NO_WAIT); | 
|  | k_work_schedule(&ble_stack_work, K_NO_WAIT); | 
|  | } | 
|  |  | 
|  | void HAL_RADIO_TIMER_CpuWakeUpCallback(void) | 
|  | { | 
|  | k_work_schedule(&hal_radio_timer_work, K_NO_WAIT); | 
|  | k_work_schedule(&ble_stack_work, K_NO_WAIT); | 
|  | } | 
|  |  | 
|  | void HAL_RADIO_TxRxCallback(uint32_t flags) | 
|  | { | 
|  | BLE_STACK_RadioHandler(flags); | 
|  | k_work_schedule(&ble_stack_work, K_NO_WAIT); | 
|  | k_work_schedule(&hal_radio_timer_work, K_NO_WAIT); | 
|  | } | 
|  |  | 
|  | ISR_DIRECT_DECLARE(RADIO_TIMER_TXRX_WKUP_IRQHandler) | 
|  | { | 
|  | HAL_RADIO_TIMER_TXRX_WKUP_IRQHandler(); | 
|  | ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */ | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | ISR_DIRECT_DECLARE(RADIO_TXRX_IRQHandler) | 
|  | { | 
|  | HAL_RADIO_TXRX_IRQHandler(); | 
|  | ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */ | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | ISR_DIRECT_DECLARE(RADIO_TXRX_SEQ_IRQHandler) | 
|  | { | 
|  | HAL_RADIO_TXRX_SEQ_IRQHandler(); | 
|  | ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */ | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | ISR_DIRECT_DECLARE(RADIO_TIMER_CPU_WKUP_IRQHandler) | 
|  | { | 
|  | HAL_RADIO_TIMER_TimeoutCallback(); | 
|  | HAL_RADIO_TIMER_CpuWakeUpCallback(); | 
|  | ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */ | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | ISR_DIRECT_DECLARE(RADIO_TIMER_ERROR_IRQHandler) | 
|  | { | 
|  | volatile uint32_t debug_cmd; | 
|  |  | 
|  | BLUE->DEBUGCMDREG |= 1; | 
|  | /* If the device is configured with CLK_SYS = 64MHz | 
|  | * and BLE clock = 16MHz, a register read is necessary | 
|  | * to ensure interrupt register is properly cleared | 
|  | * due to AHB down converter latency | 
|  | */ | 
|  | debug_cmd = BLUE->DEBUGCMDREG; | 
|  | LOG_ERR("Timer error"); | 
|  | ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */ | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Function called from PKA_IRQHandler() context. */ | 
|  | void PKAMGR_IRQCallback(void) | 
|  | { | 
|  | k_work_schedule(&ble_stack_work, K_NO_WAIT); | 
|  | } | 
|  |  | 
|  | static int _PKA_IRQHandler(void *args) | 
|  | { | 
|  | ARG_UNUSED(args); | 
|  |  | 
|  | HAL_PKA_IRQHandler(&hpka); | 
|  | ISR_DIRECT_PM(); /* PM done after servicing interrupt for best latency */ | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static void ble_isr_installer(void) | 
|  | { | 
|  | IRQ_DIRECT_CONNECT(RADIO_TIMER_TXRX_WKUP_IRQn, BLE_WKUP_PRIO, | 
|  | RADIO_TIMER_TXRX_WKUP_IRQHandler, BLE_WKUP_FLAGS); | 
|  | IRQ_DIRECT_CONNECT(RADIO_TXRX_IRQn, BLE_TX_RX_PRIO, RADIO_TXRX_IRQHandler, BLE_TX_RX_FLAGS); | 
|  | IRQ_DIRECT_CONNECT(RADIO_TIMER_CPU_WKUP_IRQn, CPU_WKUP_PRIO, | 
|  | RADIO_TIMER_CPU_WKUP_IRQHandler, CPU_WKUP_FLAGS); | 
|  | IRQ_DIRECT_CONNECT(RADIO_TXRX_SEQ_IRQn, BLE_RXTX_SEQ_PRIO, RADIO_TXRX_SEQ_IRQHandler, | 
|  | BLE_RXTX_SEQ_FLAGS); | 
|  | IRQ_DIRECT_CONNECT(RADIO_TIMER_ERROR_IRQn, BLE_ERROR_PRIO, RADIO_TIMER_ERROR_IRQHandler, | 
|  | BLE_ERROR_FLAGS); | 
|  | IRQ_CONNECT(PKA_IRQn, PKA_PRIO, _PKA_IRQHandler, NULL, PKA_FLAGS); | 
|  | } | 
|  |  | 
|  | static struct net_buf *get_rx(uint8_t *msg) | 
|  | { | 
|  | bool discardable = false; | 
|  | k_timeout_t timeout = K_FOREVER; | 
|  | struct net_buf *buf; | 
|  | int len; | 
|  |  | 
|  | switch (msg[PACKET_TYPE]) { | 
|  | case BT_HCI_H4_EVT: | 
|  | if (msg[EVT_HEADER_EVENT] == BT_HCI_EVT_LE_META_EVENT && | 
|  | (msg[EVT_LE_META_SUBEVENT] == BT_HCI_EVT_LE_ADVERTISING_REPORT)) { | 
|  | discardable = true; | 
|  | timeout = K_NO_WAIT; | 
|  | } | 
|  | buf = bt_buf_get_evt(msg[EVT_HEADER_EVENT], discardable, timeout); | 
|  | if (!buf) { | 
|  | LOG_DBG("Discard adv report due to insufficient buf"); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | len = sizeof(struct bt_hci_evt_hdr) + msg[EVT_HEADER_SIZE]; | 
|  | if (len > net_buf_tailroom(buf)) { | 
|  | LOG_ERR("Event too long: %d", len); | 
|  | net_buf_unref(buf); | 
|  | return NULL; | 
|  | } | 
|  | net_buf_add_mem(buf, &msg[1], len); | 
|  | break; | 
|  | case BT_HCI_H4_ACL: | 
|  | struct bt_hci_acl_hdr acl_hdr; | 
|  |  | 
|  | buf = bt_buf_get_rx(BT_BUF_ACL_IN, timeout); | 
|  | memcpy(&acl_hdr, &msg[1], sizeof(acl_hdr)); | 
|  | len = sizeof(acl_hdr) + sys_le16_to_cpu(acl_hdr.len); | 
|  | if (len > net_buf_tailroom(buf)) { | 
|  | LOG_ERR("ACL too long: %d", len); | 
|  | net_buf_unref(buf); | 
|  | return NULL; | 
|  | } | 
|  | net_buf_add_mem(buf, &msg[1], len); | 
|  | break; | 
|  | case BT_HCI_H4_ISO: | 
|  | struct bt_hci_iso_hdr iso_hdr; | 
|  |  | 
|  | buf = bt_buf_get_rx(BT_BUF_ISO_IN, timeout); | 
|  | if (buf) { | 
|  | memcpy(&iso_hdr, &msg[1], sizeof(iso_hdr)); | 
|  | len = sizeof(iso_hdr) + sys_le16_to_cpu(iso_hdr.len); | 
|  | } else { | 
|  | LOG_ERR("No available ISO buffers!"); | 
|  | return NULL; | 
|  | } | 
|  | if (len > net_buf_tailroom(buf)) { | 
|  | LOG_ERR("ISO too long: %d", len); | 
|  | net_buf_unref(buf); | 
|  | return NULL; | 
|  | } | 
|  | net_buf_add_mem(buf, &msg[1], len); | 
|  | break; | 
|  | default: | 
|  | LOG_ERR("Unknown BT buf type %d", msg[0]); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return buf; | 
|  | } | 
|  |  | 
|  | static int bt_hci_stm32wb0_send(const struct device *dev, struct net_buf *buf) | 
|  | { | 
|  | int ret = 0; | 
|  | uint8_t *hci_buffer = buf->data; | 
|  |  | 
|  | ARG_UNUSED(dev); | 
|  |  | 
|  | switch (bt_buf_get_type(buf)) { | 
|  | case BT_BUF_ACL_OUT: { | 
|  | uint16_t connection_handle; | 
|  | uint16_t data_len; | 
|  | uint8_t *pdu; | 
|  | uint8_t	pb_flag; | 
|  | uint8_t	bc_flag; | 
|  |  | 
|  | connection_handle = ((hci_buffer[1] & 0x0F) << 8) + hci_buffer[0]; | 
|  | data_len = (hci_buffer[3] << 8) + hci_buffer[2]; | 
|  | pdu = hci_buffer + 4; | 
|  | pb_flag = (hci_buffer[1] >> 4) & 0x3; | 
|  | bc_flag = (hci_buffer[1] >> 6) & 0x3; | 
|  | hci_tx_acl_data(connection_handle, pb_flag, bc_flag, data_len, pdu); | 
|  | break; | 
|  | } | 
|  | #if defined(CONFIG_BT_ISO) | 
|  | case BT_BUF_ISO_OUT: { | 
|  | uint16_t connection_handle; | 
|  | uint16_t iso_data_load_len; | 
|  | uint8_t *iso_data_load; | 
|  | uint8_t	pb_flag; | 
|  | uint8_t	ts_flag; | 
|  |  | 
|  | connection_handle = sys_get_le16(hci_buffer) & 0x0FFF; | 
|  | iso_data_load_len = sys_get_le16(hci_buffer + 2) & 0x3FFF; | 
|  | pb_flag = (hci_buffer[1] >> 4) & 0x3; | 
|  | ts_flag = (hci_buffer[1] >> 6) & 0x1; | 
|  | iso_data_load = &hci_buffer[4]; | 
|  | hci_tx_iso_data(connection_handle, pb_flag, ts_flag, iso_data_load_len, | 
|  | iso_data_load); | 
|  | break; | 
|  | } | 
|  | #endif /* CONFIG_BT_ISO */ | 
|  | case BT_BUF_CMD: | 
|  | process_command(hci_buffer, buf->len, buffer_out_mem, sizeof(buffer_out_mem)); | 
|  | send_event(buffer_out_mem, 0, 0); | 
|  | break; | 
|  | default: | 
|  | LOG_ERR("Unsupported type"); | 
|  | return -EINVAL; | 
|  | } | 
|  | net_buf_unref(buf); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static int bt_hci_stm32wb0_open(const struct device *dev, bt_hci_recv_t recv) | 
|  | { | 
|  | struct hci_data *data = dev->data; | 
|  | RADIO_TIMER_InitTypeDef VTIMER_InitStruct = {MAX_HS_STARTUP_TIME, 0, 0}; | 
|  | RADIO_HandleTypeDef hradio = {0}; | 
|  | BLE_STACK_InitTypeDef BLE_STACK_InitParams = { | 
|  | .BLEStartRamAddress = (uint8_t *)dyn_alloc_a, | 
|  | .TotalBufferSize = BLE_DYN_ALLOC_SIZE, | 
|  | .NumAttrRecords = CFG_BLE_NUM_GATT_ATTRIBUTES, | 
|  | .MaxNumOfClientProcs = CFG_BLE_NUM_OF_CONCURRENT_GATT_CLIENT_PROC, | 
|  | .NumOfRadioTasks = CFG_BLE_NUM_RADIO_TASKS, | 
|  | .NumOfEATTChannels = CFG_BLE_NUM_EATT_CHANNELS, | 
|  | .NumBlockCount = CFG_BLE_MBLOCKS_COUNT, | 
|  | .ATT_MTU = CFG_BLE_ATT_MTU_MAX, | 
|  | .MaxConnEventLength = CFG_BLE_CONN_EVENT_LENGTH_MAX, | 
|  | .SleepClockAccuracy = CFG_BLE_SLEEP_CLOCK_ACCURACY, | 
|  | .NumOfAdvDataSet = CFG_BLE_NUM_ADV_SETS, | 
|  | .NumOfSubeventsPAwR = CFG_BLE_NUM_PAWR_SUBEVENTS, | 
|  | .MaxPAwRSubeventDataCount = CFG_BLE_PAWR_SUBEVENT_DATA_COUNT_MAX, | 
|  | .NumOfAuxScanSlots = CFG_BLE_NUM_AUX_SCAN_SLOTS, | 
|  | .FilterAcceptListSizeLog2 = CFG_BLE_FILTER_ACCEPT_LIST_SIZE_LOG2, | 
|  | .L2CAP_MPS = CFG_BLE_COC_MPS_MAX, | 
|  | .L2CAP_NumChannels = CFG_BLE_COC_NBR_MAX, | 
|  | .NumOfSyncSlots = CFG_BLE_NUM_SYNC_SLOTS, | 
|  | .CTE_MaxNumAntennaIDs = CFG_BLE_NUM_CTE_ANTENNA_IDS_MAX, | 
|  | .CTE_MaxNumIQSamples = CFG_BLE_NUM_CTE_IQ_SAMPLES_MAX, | 
|  | .NumOfSyncBIG = CFG_BLE_NUM_SYNC_BIG_MAX, | 
|  | .NumOfBrcBIG = CFG_BLE_NUM_BRC_BIG_MAX, | 
|  | .NumOfSyncBIS = CFG_BLE_NUM_SYNC_BIS_MAX, | 
|  | .NumOfBrcBIS = CFG_BLE_NUM_BRC_BIS_MAX, | 
|  | .NumOfCIG = CFG_BLE_NUM_CIG_MAX, | 
|  | .NumOfCIS = CFG_BLE_NUM_CIS_MAX, | 
|  | .isr0_fifo_size = CFG_BLE_ISR0_FIFO_SIZE, | 
|  | .isr1_fifo_size = CFG_BLE_ISR1_FIFO_SIZE, | 
|  | .user_fifo_size = CFG_BLE_USER_FIFO_SIZE | 
|  | }; | 
|  |  | 
|  | ble_isr_installer(); | 
|  | hradio.Instance = RADIO; | 
|  | HAL_RADIO_Init(&hradio); | 
|  | HAL_RADIO_TIMER_Init(&VTIMER_InitStruct); | 
|  |  | 
|  | HW_RNG_Init(); | 
|  | HW_AES_Init(); | 
|  | hpka.Instance = PKA; | 
|  | HAL_PKA_Init(&hpka); | 
|  | HW_PKA_Init(); | 
|  | if (BLE_STACK_Init(&BLE_STACK_InitParams)) { | 
|  | LOG_ERR("BLE Init Failed...."); | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | #if CONFIG_BT_EXT_ADV | 
|  | dm_init(CFG_BLE_ADV_NWK_BUFFER_SIZE, aci_adv_nwk_buffer); | 
|  | #endif /* CONFIG_BT_EXT_ADV */ | 
|  |  | 
|  | aci_adv_nwk_init(); | 
|  |  | 
|  | data->recv = recv; | 
|  | k_work_init_delayable(&hal_radio_timer_work, vtimer_process); | 
|  | k_work_init_delayable(&ble_stack_work, blestack_process); | 
|  | k_work_schedule(&ble_stack_work, K_NO_WAIT); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static DEVICE_API(bt_hci, drv) = { | 
|  | .open = bt_hci_stm32wb0_open, | 
|  | .send = bt_hci_stm32wb0_send, | 
|  | }; | 
|  |  | 
|  | #define HCI_DEVICE_INIT(inst) \ | 
|  | static struct hci_data hci_data_##inst = { \ | 
|  | }; \ | 
|  | DEVICE_DT_INST_DEFINE(inst, NULL, NULL, &hci_data_##inst, NULL, \ | 
|  | POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &drv) | 
|  |  | 
|  | /* Only one instance supported */ | 
|  | HCI_DEVICE_INIT(0) |