Bluetooth: Add basic host-side support for HCI vendor extensions

Add skeleton for HCI vendor extenstions and convert the nRF5x-specific
static address setting to use the HCI VS commands instead.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2017-10-17 12:06:12 +03:00 committed by Johan Hedberg
commit aaeff3c165
2 changed files with 148 additions and 19 deletions

View file

@ -23,6 +23,7 @@
#include <bluetooth/conn.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_vs.h>
#include <bluetooth/hci_driver.h>
#include <bluetooth/storage.h>
@ -3713,29 +3714,33 @@ static int set_static_addr(void)
}
}
#if defined(CONFIG_SOC_FAMILY_NRF5)
/* Read address from nRF5-specific storage
* Non-initialized FICR values default to 0xFF, skip if no address
* present. Also if a public address lives in FICR, do not use in this
* function.
*/
if (((NRF_FICR->DEVICEADDR[0] != UINT32_MAX) ||
((NRF_FICR->DEVICEADDR[1] & UINT16_MAX) != UINT16_MAX)) &&
(NRF_FICR->DEVICEADDRTYPE & 0x01)) {
#if defined(CONFIG_BT_HCI_VS_EXT)
/* Check for VS_Read_Static_Addresses support */
if (bt_dev.vs_commands[1] & BIT(0)) {
struct bt_hci_rp_vs_read_static_addrs *rp;
struct net_buf *rsp;
bt_dev.id_addr.type = BT_ADDR_LE_RANDOM;
sys_put_le32(NRF_FICR->DEVICEADDR[0], &bt_dev.id_addr.a.val[0]);
sys_put_le16(NRF_FICR->DEVICEADDR[1], &bt_dev.id_addr.a.val[4]);
/* The FICR value is a just a random number, with no knowledge
* of the Bluetooth Specification requirements for random
* static addresses.
*/
BT_ADDR_SET_STATIC(&bt_dev.id_addr.a);
err = bt_hci_cmd_send_sync(BT_HCI_OP_VS_READ_STATIC_ADDRS,
NULL, &rsp);
if (err) {
BT_WARN("Failed to read static addresses");
goto generate;
}
goto set_addr;
rp = (void *)rsp->data;
if (rp->num_addrs) {
bt_dev.id_addr.type = BT_ADDR_LE_RANDOM;
bt_addr_copy(&bt_dev.id_addr.a, &rp->a[0].bdaddr);
goto set_addr;
} else {
BT_WARN("No static addresses stored in controller");
}
} else {
BT_WARN("Read Static Addresses command not available");
}
#endif /* CONFIG_SOC_FAMILY_NRF5 */
#endif
generate:
BT_DBG("Generating new static random address");
err = bt_addr_le_create_static(&bt_dev.id_addr);
@ -3803,6 +3808,112 @@ static inline void show_dev_info(void)
}
#endif /* CONFIG_BT_DEBUG */
#if defined(CONFIG_BT_HCI_VS_EXT)
#if defined(CONFIG_BT_DEBUG)
static const char *vs_hw_platform(u16_t platform)
{
static const char * const plat_str[] = {
"reserved", "Intel Corporation", "Nordic Semiconductor",
"NXP Semiconductors" };
if (platform < ARRAY_SIZE(plat_str)) {
return plat_str[platform];
}
return "unknown";
}
static const char *vs_hw_variant(u16_t platform, u16_t variant)
{
static const char * const nordic_str[] = {
"reserved", "nRF51x", "nRF52x"
};
if (platform != BT_HCI_VS_HW_PLAT_NORDIC) {
return "unknown";
}
if (variant < ARRAY_SIZE(nordic_str)) {
return nordic_str[variant];
}
return "unknown";
}
static const char *vs_fw_variant(u8_t variant)
{
static const char * const var_str[] = {
"Standard Bluetooth controller",
"Vendor specific controller",
"Firmware loader",
"Rescue image",
};
if (variant < ARRAY_SIZE(var_str)) {
return var_str[variant];
}
return "unknown";
}
#endif /* CONFIG_BT_DEBUG */
static void hci_vs_init(void)
{
union {
struct bt_hci_rp_vs_read_version_info *info;
struct bt_hci_rp_vs_read_supported_commands *cmds;
struct bt_hci_rp_vs_read_supported_features *feat;
} rp;
struct net_buf *rsp;
int err;
err = bt_hci_cmd_send_sync(BT_HCI_OP_VS_READ_VERSION_INFO, NULL, &rsp);
if (err) {
BT_WARN("Vendor HCI extensions not available");
return;
}
#if defined(CONFIG_BT_DEBUG)
rp.info = (void *)rsp->data;
BT_INFO("HW Platform: %s (0x%04x)",
vs_hw_platform(sys_le16_to_cpu(rp.info->hw_platform)),
sys_le16_to_cpu(rp.info->hw_platform));
BT_INFO("HW Variant: %s (0x%04x)",
vs_hw_variant(sys_le16_to_cpu(rp.info->hw_platform),
sys_le16_to_cpu(rp.info->hw_variant)),
sys_le16_to_cpu(rp.info->hw_variant));
BT_INFO("Firmware: %s (0x%02x) Version %u.%u Build %u",
vs_fw_variant(rp.info->fw_variant), rp.info->fw_variant,
rp.info->fw_version, sys_le16_to_cpu(rp.info->fw_revision),
sys_le32_to_cpu(rp.info->fw_build));
#endif /* CONFIG_BT_DEBUG */
net_buf_unref(rsp);
err = bt_hci_cmd_send_sync(BT_HCI_OP_VS_READ_SUPPORTED_COMMANDS,
NULL, &rsp);
if (err) {
BT_WARN("Failed to read supported vendor features");
return;
}
rp.cmds = (void *)rsp->data;
memcpy(bt_dev.vs_commands, rp.cmds->commands, BT_DEV_VS_CMDS_MAX);
net_buf_unref(rsp);
err = bt_hci_cmd_send_sync(BT_HCI_OP_VS_READ_SUPPORTED_FEATURES,
NULL, &rsp);
if (err) {
BT_WARN("Failed to read supported vendor commands");
return;
}
rp.feat = (void *)rsp->data;
memcpy(bt_dev.vs_features, rp.feat->features, BT_DEV_VS_FEAT_MAX);
net_buf_unref(rsp);
}
#endif /* CONFIG_BT_HCI_VS_EXT */
static int hci_init(void)
{
int err;
@ -3832,6 +3943,10 @@ static int hci_init(void)
return err;
}
#if defined(CONFIG_BT_HCI_VS_EXT)
hci_vs_init();
#endif
if (!bt_addr_le_cmp(&bt_dev.id_addr, BT_ADDR_LE_ANY) ||
!bt_addr_le_cmp(&bt_dev.id_addr, BT_ADDR_LE_NONE)) {
BT_DBG("No public address. Trying to set static random.");

View file

@ -74,6 +74,14 @@ struct bt_dev_br {
};
#endif
/* The theoretical max for these is 8 and 64, but there's no point
* in allocating the full memory if we only support a small subset.
* These values must be updated whenever the host implementation is
* extended beyond the current values.
*/
#define BT_DEV_VS_FEAT_MAX 1
#define BT_DEV_VS_CMDS_MAX 2
/* State tracking for the local Bluetooth controller */
struct bt_dev {
/* Local Identity Address */
@ -95,6 +103,12 @@ struct bt_dev {
/* Supported commands */
u8_t supported_commands[64];
#if defined(CONFIG_BT_HCI_VS_EXT)
/* Vendor HCI support */
u8_t vs_features[BT_DEV_VS_FEAT_MAX];
u8_t vs_commands[BT_DEV_VS_CMDS_MAX];
#endif
struct k_work init;
ATOMIC_DEFINE(flags, BT_DEV_NUM_FLAGS);