From 7a7b5e5779d5e3ab97e48f0544b350b877eeb3b8 Mon Sep 17 00:00:00 2001 From: chengkai Date: Fri, 26 Aug 2022 19:47:25 +0800 Subject: [PATCH] wireless/bluetooth:add bt bridge codes Signed-off-by: chengkai --- drivers/wireless/bluetooth/Kconfig | 6 + drivers/wireless/bluetooth/Make.defs | 4 + drivers/wireless/bluetooth/bt_bridge.c | 548 +++++++++++++++++++ include/nuttx/wireless/bluetooth/bt_bridge.h | 46 ++ 4 files changed, 604 insertions(+) create mode 100644 drivers/wireless/bluetooth/bt_bridge.c create mode 100644 include/nuttx/wireless/bluetooth/bt_bridge.h diff --git a/drivers/wireless/bluetooth/Kconfig b/drivers/wireless/bluetooth/Kconfig index 185242c5f8..926492db77 100644 --- a/drivers/wireless/bluetooth/Kconfig +++ b/drivers/wireless/bluetooth/Kconfig @@ -53,6 +53,12 @@ config BLUETOOTH_UART_DUMP endif # BLUETOOTH_UART +config BLUETOOTH_BRIDGE + bool "Bluetooth BT/BLE Dual Mode Bridge Driver" + default n + ---help--- + Enable Bluetooth BT/BLE Dual Mode Bridge Driver. + config BLUETOOTH_NULL bool "NULL Bluetooth device" default n diff --git a/drivers/wireless/bluetooth/Make.defs b/drivers/wireless/bluetooth/Make.defs index 4273eb3bd4..f3b37b4fd2 100644 --- a/drivers/wireless/bluetooth/Make.defs +++ b/drivers/wireless/bluetooth/Make.defs @@ -40,6 +40,10 @@ CSRCS += bt_uart_bcm4343x.c endif endif +ifeq ($(CONFIG_BLUETOOTH_BRIDGE),y) +CSRCS += bt_bridge.c +endif + ifeq ($(CONFIG_BLUETOOTH_NULL),y) CSRCS += bt_null.c endif diff --git a/drivers/wireless/bluetooth/bt_bridge.c b/drivers/wireless/bluetooth/bt_bridge.c new file mode 100644 index 0000000000..88e025b360 --- /dev/null +++ b/drivers/wireless/bluetooth/bt_bridge.c @@ -0,0 +1,548 @@ +/**************************************************************************** + * drivers/wireless/bluetooth/bt_bridge.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define BT_FILTER_CONN_COUNT 16 +#define BT_FILTER_OPCODE_COUNT 16 + +#define BT_FILTER_TYPE_BT 0 +#define BT_FILTER_TYPE_BLE 1 +#define BT_FILTER_TYPE_COUNT 2 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct bt_filter_s +{ + int type; + uint16_t opcode[BT_FILTER_OPCODE_COUNT]; + uint16_t handle[BT_FILTER_CONN_COUNT]; +}; + +struct bt_bridge_device_s +{ + struct bt_driver_s driver; + struct bt_filter_s filter; + FAR struct bt_bridge_s *bridge; +}; + +struct bt_bridge_s +{ + struct bt_bridge_device_s device[BT_FILTER_TYPE_COUNT]; + FAR struct bt_driver_s *driver; + uint8_t refs; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const uint8_t g_bt_filter_bt_evt_table[] = +{ + BT_HCI_EVT_INQUIRY_COMPLETE, + BT_HCI_EVT_CONN_COMPLETE, + BT_HCI_EVT_CONN_REQUEST, + BT_HCI_EVT_AUTH_COMPLETE, + BT_HCI_EVT_REMOTE_NAME_REQ_COMPLETE, + BT_HCI_EVT_REMOTE_FEATURES, + BT_HCI_EVT_ROLE_CHANGE, + BT_HCI_EVT_PIN_CODE_REQ, + BT_HCI_EVT_LINK_KEY_NOTIFY, + BT_HCI_EVT_LINK_KEY_REQ, + BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI, + BT_HCI_EVT_REMOTE_EXT_FEATURES, + BT_HCI_EVT_SYNC_CONN_COMPLETE, + BT_HCI_EVT_EXTENDED_INQUIRY_RESULT, + BT_HCI_EVT_IO_CAPA_RESP, + BT_HCI_EVT_IO_CAPA_REQ, + BT_HCI_EVT_SSP_COMPLETE, + BT_HCI_EVT_USER_CONFIRM_REQ, + BT_HCI_EVT_USER_PASSKEY_REQ, + BT_HCI_EVT_USER_PASSKEY_NOTIFY, + BT_HCI_EVT_PAGE_SCAN_REP_MODE_CHNG, + BT_HCI_EVT_CONN_PKT_TYPE_CHANGE, + BT_HCI_EVT_READ_CLOCK_OFF_COMP, + BT_HCI_EVT_MAX_SLOTS_CHANGED, + BT_HCI_EVT_MODE_CHANGE, + BT_HCI_EVT_QOS_SETUP_COMP, + BT_HCI_EVT_LINK_SUPER_TOUT_CHANGED, +}; + +static const uint8_t g_bt_filter_ble_evt_table[] = +{ + BT_HCI_EVT_LE_META_EVENT, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static bool bt_filter_set(FAR uint16_t *array, int size, uint16_t old, + uint16_t new, uint16_t mask) +{ + int i; + + for (i = 0; i < size; i++) + { + if (array[i] == old) + { + array[i] = new & mask; + return true; + } + } + + return false; +} + +static bool bt_filter_set_handle(FAR uint16_t *handle, int size, + uint16_t old, uint16_t new) +{ + return bt_filter_set(handle, size, old, new, 0xfff); +} + +static bool bt_filter_alloc_handle(FAR struct bt_filter_s *filter, + uint16_t handle) +{ + return bt_filter_set_handle(filter->handle, BT_FILTER_CONN_COUNT, + 0, handle); +} + +static bool bt_filter_free_handle(FAR struct bt_filter_s *filter, + uint16_t handle) +{ + return bt_filter_set_handle(filter->handle, BT_FILTER_CONN_COUNT, + handle, 0); +} + +static bool bt_filter_has_handle(FAR struct bt_filter_s *filter, + uint16_t handle) +{ + return bt_filter_set_handle(filter->handle, BT_FILTER_CONN_COUNT, + handle, handle); +} + +static bool bt_filter_set_opcode(FAR uint16_t *opcode, int size, + uint16_t old, uint16_t new) +{ + return bt_filter_set(opcode, size, old, new, 0xffff); +} + +static bool bt_filter_alloc_opcode(FAR struct bt_filter_s *filter, + uint16_t opcode) +{ + return bt_filter_set_opcode(filter->opcode, BT_FILTER_OPCODE_COUNT, + 0, opcode); +} + +static bool bt_filter_free_opcode(FAR struct bt_filter_s *filter, + uint16_t opcode) +{ + return bt_filter_set_opcode(filter->opcode, BT_FILTER_OPCODE_COUNT, + opcode, 0); +} + +static bool bt_filter_can_recv(FAR struct bt_filter_s *filter, + enum bt_buf_type_e type, + FAR const uint8_t *buffer, size_t buflen) +{ + FAR const uint8_t *evt_table; + int size; + int i; + + if (type == BT_EVT) + { + if (filter->type == BT_FILTER_TYPE_BLE) + { + evt_table = g_bt_filter_bt_evt_table; + size = sizeof(g_bt_filter_bt_evt_table); + } + else + { + evt_table = g_bt_filter_ble_evt_table; + size = sizeof(g_bt_filter_ble_evt_table); + } + + for (i = 0; i < size; i++) + { + if (buffer[0] == evt_table[i]) + { + return false; + } + } + + switch (buffer[0]) + { + case BT_HCI_EVT_LE_META_EVENT: + if (buffer[2] == BT_HCI_EVT_LE_CONN_COMPLETE) + { + FAR struct bt_hci_evt_le_conn_complete_s *evt; + + evt = (FAR void *)&buffer[3]; + if (evt->status == 0) + { + return bt_filter_alloc_handle(filter, evt->handle); + } + } + else if (buffer[2] == BT_HCI_EVT_LE_ENH_CONN_COMPLETE) + { + FAR struct bt_hci_evt_le_enh_conn_complete_s *evt; + + evt = (FAR void *)&buffer[3]; + if (evt->status == 0) + { + return bt_filter_alloc_handle(filter, evt->handle); + } + } + break; + case BT_HCI_EVT_CONN_COMPLETE: + { + FAR struct bt_hci_evt_conn_complete_s *evt; + + evt = (FAR void *)&buffer[2]; + if (evt->status == 0) + { + return bt_filter_alloc_handle(filter, evt->handle); + } + } + break; + case BT_HCI_EVT_NUM_COMPLETED_PACKETS: + { + FAR struct bt_hci_evt_num_completed_packets_s *evt; + + evt = (FAR void *)&buffer[2]; + return bt_filter_has_handle(filter, evt->h[0].handle); + } + break; + case BT_HCI_EVT_REMOTE_VERSION_INFO: + { + FAR struct bt_hci_evt_remote_version_info_s *evt; + + evt = (FAR void *)&buffer[2]; + return bt_filter_has_handle(filter, evt->handle); + } + break; + case BT_HCI_EVT_ENCRYPT_CHANGE: + { + FAR struct bt_hci_evt_encrypt_change_s *evt; + + evt = (FAR void *)&buffer[2]; + return bt_filter_has_handle(filter, evt->handle); + } + break; + case BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE: + { + FAR struct bt_hci_evt_encrypt_key_refresh_complete_s *evt; + + evt = (FAR void *)&buffer[2]; + return bt_filter_has_handle(filter, evt->handle); + } + break; + case BT_HCI_EVT_DISCONN_COMPLETE: + { + FAR struct bt_hci_evt_disconn_complete_s *evt; + + evt = (FAR void *)&buffer[2]; + return bt_filter_free_handle(filter, evt->handle); + } + break; + case BT_HCI_EVT_CMD_COMPLETE: + { + FAR struct hci_evt_cmd_complete_s *evt; + uint8_t ogf; + + evt = (FAR void *)&buffer[2]; + ogf = evt->opcode >> 10; + + if (BT_OGF_BASEBAND == ogf || BT_OGF_LINK_CTRL == ogf + || BT_OGF_INFO == ogf || BT_OGF_LE == ogf) + { + return bt_filter_free_opcode(filter, evt->opcode); + } + else if (BT_OGF_LINK_POLICY == ogf || BT_OGF_STATUS == ogf) + { + if (filter->type == BT_FILTER_TYPE_BLE) + { + return false; + } + } + } + break; + case BT_HCI_EVT_CMD_STATUS: + { + FAR struct bt_hci_evt_cmd_status_s *stat; + uint8_t ogf; + + stat = (FAR void *)&buffer[2]; + ogf = stat->opcode >> 10; + + if (BT_OGF_BASEBAND == ogf || BT_OGF_LINK_CTRL == ogf + || BT_OGF_INFO == ogf || BT_OGF_LE == ogf) + { + return bt_filter_free_opcode(filter, stat->opcode); + } + + if (BT_OGF_LINK_POLICY == ogf || BT_OGF_STATUS == ogf) + { + if (filter->type == BT_FILTER_TYPE_BLE) + { + return false; + } + } + } + break; + } + } + else if (type == BT_ACL_IN) + { + FAR struct bt_hci_acl_hdr_s *acl = (FAR void *)&buffer[0]; + + return bt_filter_has_handle(filter, acl->handle); + } + + return true; +} + +static bool bt_filter_can_send(FAR struct bt_filter_s *filter, + enum bt_buf_type_e type, + FAR uint8_t *buffer, size_t buflen) +{ + uint16_t opcode; + uint8_t ogf; + int i; + + if (type == BT_CMD) + { + opcode = (uint16_t)buffer[1] << 8 | (uint16_t)buffer[0]; + ogf = buffer[1] >> 2; + + switch (opcode) + { + case BT_HCI_OP_SET_EVENT_MASK: + { + /* Override the all event bits roughly to avoid the + * bt/ble host specific mask deliver to controller. + */ + + memset(&buffer[3], 0xff, 7); + buffer[10] = 0x3f; + } + break; + } + + if (BT_OGF_BASEBAND == ogf || BT_OGF_LINK_CTRL == ogf + || BT_OGF_INFO == ogf || BT_OGF_LE == ogf) + { + if (!bt_filter_alloc_opcode(filter, opcode)) + { + nerr("Unable to set opcode 0x%04x.\n", opcode); + + for (i = 0; i < BT_FILTER_OPCODE_COUNT; i++) + { + nerr("PENDING opcode: %04x.\n", filter->opcode[i]); + } + + memset(filter->opcode, 0, sizeof(filter->opcode)); + + bt_filter_alloc_opcode(filter, opcode); + } + } + } + + return true; +} + +static int bt_bridge_open(FAR struct bt_driver_s *drv) +{ + FAR struct bt_bridge_device_s *device = + (FAR struct bt_bridge_device_s *)drv; + FAR struct bt_bridge_s *bridge = device->bridge; + FAR struct bt_driver_s *driver = bridge->driver; + + if (atomic_fetch_add(&bridge->refs, 1) == 0) + { + int ret = driver->open(driver); + if (ret < 0) + { + atomic_fetch_sub(&bridge->refs, 1); + } + + return ret; + }; + + return OK; +} + +static int bt_bridge_send(FAR struct bt_driver_s *drv, + enum bt_buf_type_e type, + FAR void *data, size_t len) +{ + FAR struct bt_bridge_device_s *device = + (FAR struct bt_bridge_device_s *)drv; + FAR struct bt_bridge_s *bridge = device->bridge; + FAR struct bt_driver_s *driver = bridge->driver; + irqstate_t flags; + + flags = enter_critical_section(); + if (bt_filter_can_send(&device->filter, type, data, len)) + { + leave_critical_section(flags); + return driver->send(driver, type, data, len); + } + + leave_critical_section(flags); + return 0; +} + +static void bt_bridge_close(FAR struct bt_driver_s *drv) +{ + FAR struct bt_bridge_device_s *device = + (FAR struct bt_bridge_device_s *)drv; + FAR struct bt_bridge_s *bridge = device->bridge; + FAR struct bt_driver_s *driver = bridge->driver; + + if (atomic_fetch_sub(&bridge->refs, 1) == 1) + { + driver->close(driver); + }; +} + +static int bt_bridge_receive(FAR struct bt_driver_s *drv, + enum bt_buf_type_e type, + FAR void *data, size_t len) +{ + FAR struct bt_bridge_s *bridge = (FAR struct bt_bridge_s *)drv->priv; + FAR struct bt_bridge_device_s *device; + FAR struct bt_driver_s *driver; + irqstate_t flags; + int i; + + flags = enter_critical_section(); + for (i = 0; i < BT_FILTER_TYPE_COUNT; i++) + { + device = &bridge->device[i]; + driver = &device->driver; + if (bt_filter_can_recv(&device->filter, type, data, len)) + { + leave_critical_section(flags); + return bt_netdev_receive(driver, type, data, len); + } + } + + leave_critical_section(flags); + return 0; +} + +static int bt_bridge_ioctl(FAR struct bt_driver_s *drv, int cmd, + unsigned long arg) +{ + FAR struct bt_bridge_device_s *device = + (FAR struct bt_bridge_device_s *)drv; + FAR struct bt_bridge_s *bridge = device->bridge; + int ret; + + + if (bridge->driver->ioctl) + { + ret = bridge->driver->ioctl(drv, cmd, arg); + } + else + { + ret = -ENOTTY; + } + + return ret; +} + +static void bt_device_init(FAR struct bt_bridge_s *bridge, + FAR struct bt_driver_s **drv, uint8_t type) +{ + FAR struct bt_bridge_device_s *device = &bridge->device[type]; + FAR struct bt_driver_s *driver = &device->driver; + + device->bridge = bridge; + device->filter.type = type; + + *drv = &device->driver; + + driver->head_reserve = bridge->driver->head_reserve; + driver->open = bt_bridge_open; + driver->send = bt_bridge_send; + driver->close = bt_bridge_close; + driver->ioctl = bt_bridge_ioctl; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: bt_bridge_register + * + * Description: + * Register the Bluetooth BT/BLE dual mode bridge driver + * + ****************************************************************************/ + +int bt_bridge_register(FAR struct bt_driver_s *hcidrv, + FAR struct bt_driver_s **btdrv, + FAR struct bt_driver_s **bledrv) +{ + FAR struct bt_bridge_s *bridge; + + if (!hcidrv || !btdrv || !bledrv) + { + return -EINVAL; + } + + bridge = (FAR struct bt_bridge_s *)kmm_zalloc(sizeof(struct bt_bridge_s)); + if (!bridge) + { + return -ENOMEM; + } + + bridge->driver = hcidrv; + + hcidrv->receive = bt_bridge_receive; + hcidrv->priv = bridge; + + bt_device_init(bridge, btdrv, BT_FILTER_TYPE_BT); + bt_device_init(bridge, bledrv, BT_FILTER_TYPE_BLE); + + return OK; +} diff --git a/include/nuttx/wireless/bluetooth/bt_bridge.h b/include/nuttx/wireless/bluetooth/bt_bridge.h new file mode 100644 index 0000000000..323b6b3796 --- /dev/null +++ b/include/nuttx/wireless/bluetooth/bt_bridge.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * include/nuttx/wireless/bluetooth/bt_bridge.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_WIRELESS_BLUETOOTH_BT_BRIDGE_H +#define __INCLUDE_NUTTX_WIRELESS_BLUETOOTH_BT_BRIDGE_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: bt_bridge_register + * + * Description: + * Register the Bluetooth BT/BLE dual mode bridge driver + * + ****************************************************************************/ + +int bt_bridge_register(FAR struct bt_driver_s *hcidrv, + FAR struct bt_driver_s **btdrv, + FAR struct bt_driver_s **bledrv); + +#endif /* __INCLUDE_NUTTX_WIRELESS_BLUETOOTH_BT_BRIDGE_H */