Bluetooth: controller: HCI commands to read codecs and controller delay
Implement HCI commands to read information about supported codecs and controller delay. * Read Local Supported Codecs command (v1 and v2) * Read Local Supported Codec Capabilities command * Read Local Supported Controller Delay command The following functions are implemented as "weak" symbols and should be overridden to fill in vendor-specific information into the above commands. * hci_vendor_read_std_codecs * hci_vendor_read_vs_codecs * hci_vendor_read_codec_capabilities * hci_vendor_read_ctlr_delay Signed-off-by: Wolfgang Puffitsch <wopu@demant.com>
This commit is contained in:
parent
9437a6a08d
commit
1547108b19
3 changed files with 286 additions and 0 deletions
|
@ -550,6 +550,12 @@ config BT_CTLR_SMI_TX_SETTING
|
|||
help
|
||||
Enable support for Bluetooth 5.0 SMI TX through a system setting.
|
||||
|
||||
config BT_CTLR_HCI_CODEC_AND_DELAY_INFO
|
||||
bool "Codecs and controller delay information commands"
|
||||
help
|
||||
Enable HCI commands to read information about supported
|
||||
codecs, codec capabilities, and controller delay.
|
||||
|
||||
source "subsys/bluetooth/controller/Kconfig.df"
|
||||
source "subsys/bluetooth/controller/Kconfig.ll_sw_split"
|
||||
|
||||
|
|
|
@ -749,6 +749,13 @@ static void read_supported_commands(struct net_buf *buf, struct net_buf **evt)
|
|||
|
||||
/* LE Read TX Power. */
|
||||
rp->commands[38] |= BIT(7);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_HCI_CODEC_AND_DELAY_INFO)
|
||||
/* Read Supported Codecs */
|
||||
rp->commands[29] |= BIT(5);
|
||||
/* Read Supported Codecs [v2], Codec Capabilities, Controller Delay */
|
||||
rp->commands[45] |= BIT(2) | BIT(3) | BIT(4);
|
||||
#endif /* CONFIG_BT_CTLR_HCI_CODEC_AND_DELAY_INFO */
|
||||
}
|
||||
|
||||
static void read_local_features(struct net_buf *buf, struct net_buf **evt)
|
||||
|
@ -774,6 +781,240 @@ static void read_bd_addr(struct net_buf *buf, struct net_buf **evt)
|
|||
ll_addr_get(0, &rp->bdaddr.val[0]);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_HCI_CODEC_AND_DELAY_INFO)
|
||||
uint8_t __weak hci_vendor_read_std_codecs(
|
||||
const struct bt_hci_std_codec_info_v2 **codecs)
|
||||
{
|
||||
ARG_UNUSED(codecs);
|
||||
|
||||
/* return number of supported codecs */
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t __weak hci_vendor_read_vs_codecs(
|
||||
const struct bt_hci_vs_codec_info_v2 **codecs)
|
||||
{
|
||||
ARG_UNUSED(codecs);
|
||||
|
||||
/* return number of supported codecs */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void read_codecs(struct net_buf *buf, struct net_buf **evt)
|
||||
{
|
||||
struct bt_hci_rp_read_codecs *rp;
|
||||
const struct bt_hci_std_codec_info_v2 *std_codec_info;
|
||||
const struct bt_hci_vs_codec_info_v2 *vs_codec_info;
|
||||
struct bt_hci_std_codecs *std_codecs;
|
||||
struct bt_hci_vs_codecs *vs_codecs;
|
||||
size_t std_codecs_bytes;
|
||||
size_t vs_codecs_bytes;
|
||||
uint8_t num_std_codecs;
|
||||
uint8_t num_vs_codecs;
|
||||
uint8_t i;
|
||||
|
||||
/* read standard codec information */
|
||||
num_std_codecs = hci_vendor_read_std_codecs(&std_codec_info);
|
||||
std_codecs_bytes = sizeof(struct bt_hci_std_codecs) +
|
||||
num_std_codecs * sizeof(struct bt_hci_std_codec_info);
|
||||
/* read vendor-specific codec information */
|
||||
num_vs_codecs = hci_vendor_read_vs_codecs(&vs_codec_info);
|
||||
vs_codecs_bytes = sizeof(struct bt_hci_vs_codecs) +
|
||||
num_vs_codecs * sizeof(struct bt_hci_vs_codec_info);
|
||||
|
||||
/* allocate response packet */
|
||||
rp = hci_cmd_complete(evt, sizeof(*rp) +
|
||||
std_codecs_bytes +
|
||||
vs_codecs_bytes);
|
||||
rp->status = 0x00;
|
||||
|
||||
/* copy standard codec information */
|
||||
std_codecs = (struct bt_hci_std_codecs *)&rp->codecs[0];
|
||||
std_codecs->num_codecs = num_std_codecs;
|
||||
for (i = 0; i < num_std_codecs; i++) {
|
||||
struct bt_hci_std_codec_info *codec;
|
||||
|
||||
codec = &std_codecs->codec_info[i];
|
||||
codec->codec_id = std_codec_info[i].codec_id;
|
||||
}
|
||||
|
||||
/* copy vendor specific codec information */
|
||||
vs_codecs = (struct bt_hci_vs_codecs *)&rp->codecs[std_codecs_bytes];
|
||||
vs_codecs->num_codecs = num_vs_codecs;
|
||||
for (i = 0; i < num_std_codecs; i++) {
|
||||
struct bt_hci_vs_codec_info *codec;
|
||||
|
||||
codec = &vs_codecs->codec_info[i];
|
||||
codec->company_id =
|
||||
sys_cpu_to_le16(vs_codec_info[i].company_id);
|
||||
codec->codec_id = sys_cpu_to_le16(vs_codec_info[i].codec_id);
|
||||
}
|
||||
}
|
||||
|
||||
static void read_codecs_v2(struct net_buf *buf, struct net_buf **evt)
|
||||
{
|
||||
struct bt_hci_rp_read_codecs_v2 *rp;
|
||||
const struct bt_hci_std_codec_info_v2 *std_codec_info;
|
||||
const struct bt_hci_vs_codec_info_v2 *vs_codec_info;
|
||||
struct bt_hci_std_codecs_v2 *std_codecs;
|
||||
struct bt_hci_vs_codecs_v2 *vs_codecs;
|
||||
size_t std_codecs_bytes;
|
||||
size_t vs_codecs_bytes;
|
||||
uint8_t num_std_codecs;
|
||||
uint8_t num_vs_codecs;
|
||||
uint8_t i;
|
||||
|
||||
/* read standard codec information */
|
||||
num_std_codecs = hci_vendor_read_std_codecs(&std_codec_info);
|
||||
std_codecs_bytes = sizeof(struct bt_hci_std_codecs_v2) +
|
||||
num_std_codecs * sizeof(struct bt_hci_std_codec_info_v2);
|
||||
/* read vendor-specific codec information */
|
||||
num_vs_codecs = hci_vendor_read_vs_codecs(&vs_codec_info);
|
||||
vs_codecs_bytes = sizeof(struct bt_hci_vs_codecs_v2) +
|
||||
num_vs_codecs * sizeof(struct bt_hci_vs_codec_info_v2);
|
||||
|
||||
/* allocate response packet */
|
||||
rp = hci_cmd_complete(evt, sizeof(*rp) +
|
||||
std_codecs_bytes +
|
||||
vs_codecs_bytes);
|
||||
rp->status = 0x00;
|
||||
|
||||
/* copy standard codec information */
|
||||
std_codecs = (struct bt_hci_std_codecs_v2 *)&rp->codecs[0];
|
||||
std_codecs->num_codecs = num_std_codecs;
|
||||
for (i = 0; i < num_std_codecs; i++) {
|
||||
struct bt_hci_std_codec_info_v2 *codec;
|
||||
|
||||
codec = &std_codecs->codec_info[i];
|
||||
codec->codec_id = std_codec_info[i].codec_id;
|
||||
codec->transports = std_codec_info[i].transports;
|
||||
}
|
||||
|
||||
/* copy vendor specific codec information */
|
||||
vs_codecs = (struct bt_hci_vs_codecs_v2 *)&rp->codecs[std_codecs_bytes];
|
||||
vs_codecs->num_codecs = num_vs_codecs;
|
||||
for (i = 0; i < num_std_codecs; i++) {
|
||||
struct bt_hci_vs_codec_info_v2 *codec;
|
||||
|
||||
codec = &vs_codecs->codec_info[i];
|
||||
codec->company_id =
|
||||
sys_cpu_to_le16(vs_codec_info[i].company_id);
|
||||
codec->codec_id = sys_cpu_to_le16(vs_codec_info[i].codec_id);
|
||||
codec->transports = vs_codec_info[i].transports;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t __weak hci_vendor_read_codec_capabilities(uint8_t coding_format,
|
||||
uint16_t company_id,
|
||||
uint16_t vs_codec_id,
|
||||
uint8_t transport,
|
||||
uint8_t direction,
|
||||
uint8_t *num_capabilities,
|
||||
size_t *capabilities_bytes,
|
||||
const uint8_t **capabilities)
|
||||
{
|
||||
ARG_UNUSED(coding_format);
|
||||
ARG_UNUSED(company_id);
|
||||
ARG_UNUSED(vs_codec_id);
|
||||
ARG_UNUSED(transport);
|
||||
ARG_UNUSED(direction);
|
||||
ARG_UNUSED(capabilities);
|
||||
|
||||
*num_capabilities = 0;
|
||||
*capabilities_bytes = 0;
|
||||
|
||||
/* return status */
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static void read_codec_capabilities(struct net_buf *buf, struct net_buf **evt)
|
||||
{
|
||||
struct bt_hci_cp_read_codec_capabilities *cmd = (void *)buf->data;
|
||||
struct bt_hci_rp_read_codec_capabilities *rp;
|
||||
const uint8_t *capabilities;
|
||||
size_t capabilities_bytes;
|
||||
uint8_t num_capabilities;
|
||||
uint16_t vs_codec_id;
|
||||
uint16_t company_id;
|
||||
uint8_t status;
|
||||
|
||||
company_id = sys_le16_to_cpu(cmd->codec_id.company_id);
|
||||
vs_codec_id = sys_le16_to_cpu(cmd->codec_id.vs_codec_id);
|
||||
|
||||
/* read codec capabilities */
|
||||
status = hci_vendor_read_codec_capabilities(cmd->codec_id.coding_format,
|
||||
company_id,
|
||||
vs_codec_id,
|
||||
cmd->transport,
|
||||
cmd->direction,
|
||||
&num_capabilities,
|
||||
&capabilities_bytes,
|
||||
&capabilities);
|
||||
|
||||
/* allocate response packet */
|
||||
rp = hci_cmd_complete(evt, sizeof(*rp) + capabilities_bytes);
|
||||
rp->status = status;
|
||||
|
||||
/* copy codec capabilities information */
|
||||
rp->num_capabilities = num_capabilities;
|
||||
memcpy(&rp->capabilities, capabilities, capabilities_bytes);
|
||||
}
|
||||
|
||||
uint8_t __weak hci_vendor_read_ctlr_delay(uint8_t coding_format,
|
||||
uint16_t company_id,
|
||||
uint16_t vs_codec_id,
|
||||
uint8_t transport,
|
||||
uint8_t direction,
|
||||
uint8_t codec_config_len,
|
||||
const uint8_t *codec_config,
|
||||
uint32_t *min_delay,
|
||||
uint32_t *max_delay)
|
||||
{
|
||||
ARG_UNUSED(coding_format);
|
||||
ARG_UNUSED(company_id);
|
||||
ARG_UNUSED(vs_codec_id);
|
||||
ARG_UNUSED(transport);
|
||||
ARG_UNUSED(direction);
|
||||
ARG_UNUSED(codec_config_len);
|
||||
ARG_UNUSED(codec_config);
|
||||
|
||||
*min_delay = 0;
|
||||
*max_delay = 0x3D0900; /* 4 seconds, maximum value allowed by spec */
|
||||
|
||||
/* return status */
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
static void read_ctlr_delay(struct net_buf *buf, struct net_buf **evt)
|
||||
{
|
||||
struct bt_hci_cp_read_ctlr_delay *cmd = (void *)buf->data;
|
||||
struct bt_hci_rp_read_ctlr_delay *rp;
|
||||
uint16_t vs_codec_id;
|
||||
uint16_t company_id;
|
||||
uint32_t min_delay;
|
||||
uint32_t max_delay;
|
||||
uint8_t status;
|
||||
|
||||
company_id = sys_le16_to_cpu(cmd->codec_id.company_id);
|
||||
vs_codec_id = sys_le16_to_cpu(cmd->codec_id.vs_codec_id);
|
||||
|
||||
status = hci_vendor_read_ctlr_delay(cmd->codec_id.coding_format,
|
||||
company_id,
|
||||
vs_codec_id,
|
||||
cmd->transport,
|
||||
cmd->direction,
|
||||
cmd->codec_config_len,
|
||||
cmd->codec_config,
|
||||
&min_delay,
|
||||
&max_delay);
|
||||
|
||||
rp = hci_cmd_complete(evt, sizeof(*rp));
|
||||
rp->status = status;
|
||||
sys_put_le24(min_delay, rp->min_ctlr_delay);
|
||||
sys_put_le24(max_delay, rp->max_ctlr_delay);
|
||||
}
|
||||
#endif /* CONFIG_BT_CTLR_HCI_CODEC_AND_DELAY_INFO */
|
||||
|
||||
static int info_cmd_handle(uint16_t ocf, struct net_buf *cmd,
|
||||
struct net_buf **evt)
|
||||
{
|
||||
|
@ -794,6 +1035,24 @@ static int info_cmd_handle(uint16_t ocf, struct net_buf *cmd,
|
|||
read_bd_addr(cmd, evt);
|
||||
break;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_HCI_CODEC_AND_DELAY_INFO)
|
||||
case BT_OCF(BT_HCI_OP_READ_CODECS):
|
||||
read_codecs(cmd, evt);
|
||||
break;
|
||||
|
||||
case BT_OCF(BT_HCI_OP_READ_CODECS_V2):
|
||||
read_codecs_v2(cmd, evt);
|
||||
break;
|
||||
|
||||
case BT_OCF(BT_HCI_OP_READ_CODEC_CAPABILITIES):
|
||||
read_codec_capabilities(cmd, evt);
|
||||
break;
|
||||
|
||||
case BT_OCF(BT_HCI_OP_READ_CTLR_DELAY):
|
||||
read_ctlr_delay(cmd, evt);
|
||||
break;
|
||||
#endif /* CONFIG_BT_CTLR_HCI_CODEC_AND_DELAY_INFO */
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -48,3 +48,24 @@ uint8_t hci_vendor_read_static_addr(struct bt_hci_vs_static_addr addrs[],
|
|||
void hci_vendor_read_key_hierarchy_roots(uint8_t ir[16], uint8_t er[16]);
|
||||
int hci_vendor_cmd_handle_common(uint16_t ocf, struct net_buf *cmd,
|
||||
struct net_buf **evt);
|
||||
uint8_t hci_vendor_read_std_codecs(
|
||||
const struct bt_hci_std_codec_info_v2 **codecs);
|
||||
uint8_t hci_vendor_read_vs_codecs(
|
||||
const struct bt_hci_vs_codec_info_v2 **codecs);
|
||||
uint8_t hci_vendor_read_codec_capabilities(uint8_t coding_format,
|
||||
uint16_t company_id,
|
||||
uint16_t vs_codec_id,
|
||||
uint8_t transport,
|
||||
uint8_t direction,
|
||||
uint8_t *num_capabilities,
|
||||
size_t *capabilities_bytes,
|
||||
const uint8_t **capabilities);
|
||||
uint8_t hci_vendor_read_ctlr_delay(uint8_t coding_format,
|
||||
uint16_t company_id,
|
||||
uint16_t vs_codec_id,
|
||||
uint8_t transport,
|
||||
uint8_t direction,
|
||||
uint8_t codec_config_len,
|
||||
const uint8_t *codec_config,
|
||||
uint32_t *min_delay,
|
||||
uint32_t *max_delay);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue