/* * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include "esp_log.h" #include "esp_hci_transport.h" #include "esp_hci_internal.h" #include "esp_bt.h" typedef struct hci_transport_env { hci_transport_host_recv_fn *host_recv_cb; hci_driver_ops_t *driver_ops; } hci_transport_env_t; static hci_transport_env_t s_hci_transport_env; /* Functions for packets Rx. */ static int hci_transport_controller_packet_rx(hci_driver_data_type_t data_type, uint8_t *data) { if (data_type == HCI_DRIVER_TYPE_CMD) { r_ble_hci_trans_hs_cmd_tx(data); } if (data_type == HCI_DRIVER_TYPE_ACL) { r_ble_hci_trans_hs_acl_tx((struct os_mbuf *) data); } return 0; } static int hci_transport_host_packet_rx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length) { if (!s_hci_transport_env.host_recv_cb) { return -1; } return s_hci_transport_env.host_recv_cb((hci_trans_pkt_ind_t)data_type, data, length); } static int hci_transport_packet_rx(hci_driver_data_type_t data_type, uint8_t *data, uint32_t length, hci_driver_direction_t dir) { int rc; if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { return -1; } if (dir == HCI_DRIVER_DIR_C2H) { rc = hci_transport_host_packet_rx(data_type, data, length); } else { rc = hci_transport_controller_packet_rx(data_type, data); } return rc; } /* Functions for controller Tx. */ static int hci_transport_controller_tx_dummy(void *data, void *arg) { return -1; } static int hci_transport_controller_evt_tx(uint8_t *hci_ev, void *arg) { uint32_t len; if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { r_ble_hci_trans_buf_free(hci_ev); return -1; } len = hci_ev[1] + 2; return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_EVT, hci_ev, len, HCI_DRIVER_DIR_C2H); } static int hci_transport_controller_acl_tx(struct os_mbuf *om, void *arg) { uint16_t len; if (esp_bt_controller_get_status() != ESP_BT_CONTROLLER_STATUS_ENABLED) { os_mbuf_free_chain(om); return -1; } len = OS_MBUF_PKTHDR(om)->omp_len; return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_ACL, (uint8_t *)om, len, HCI_DRIVER_DIR_C2H); } /* Functions for host Tx. */ int hci_transport_host_cmd_tx(uint8_t *data, uint32_t length) { return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_CMD, data, length, HCI_DRIVER_DIR_H2C); } int hci_transport_host_acl_tx(uint8_t *data, uint32_t length) { return s_hci_transport_env.driver_ops->hci_driver_tx(HCI_DRIVER_TYPE_ACL, data, length, HCI_DRIVER_DIR_H2C); } int hci_transport_host_callback_register(hci_transport_host_recv_fn *callback) { s_hci_transport_env.host_recv_cb = callback; return 0; } int hci_transport_init(uint8_t hci_transport_mode) { int rc; hci_driver_ops_t *ops; memset(&s_hci_transport_env, 0, sizeof(hci_transport_env_t)); switch(hci_transport_mode) { #if CONFIG_BT_LE_HCI_INTERFACE_USE_RAM case HCI_TRANSPORT_VHCI: ops = &hci_driver_vhci_ops; break; #endif // CONFIG_BT_LE_HCI_INTERFACE_USE_RAM #if CONFIG_BT_LE_HCI_INTERFACE_USE_UART #if CONFIG_BT_LE_UART_HCI_DMA_MODE case HCI_TRANSPORT_UART_UHCI: ops = &hci_driver_uart_dma_ops; break; #else case HCI_TRANSPORT_UART_NO_DMA: ops = &hci_driver_uart_ops; break; #endif // CONFIG_BT_LE_UART_HCI_DMA_MODE #endif // CONFIG_BT_LE_HCI_INTERFACE_USE_UART default: assert(0); } rc = ops->hci_driver_init(hci_transport_packet_rx); if (rc) { goto error; } s_hci_transport_env.driver_ops = ops; r_ble_hci_trans_cfg_hs(hci_transport_controller_evt_tx, NULL, hci_transport_controller_acl_tx, NULL); return 0; error: hci_transport_deinit(); return rc; } void hci_transport_deinit(void) { hci_driver_ops_t *ops; r_ble_hci_trans_cfg_hs((esp_hci_internal_rx_cmd_fn *)hci_transport_controller_tx_dummy, NULL, (esp_hci_internal_rx_acl_fn *)hci_transport_controller_tx_dummy, NULL); ops = s_hci_transport_env.driver_ops; if (ops) { ops->hci_driver_deinit(); } memset(&s_hci_transport_env, 0, sizeof(hci_transport_env_t)); }