Skip to content
Draft
116 changes: 98 additions & 18 deletions drivers/bluetooth/btintel.c
Original file line number Diff line number Diff line change
Expand Up @@ -2567,45 +2567,110 @@ static int btintel_prepare_fw_download_tlv(struct hci_dev *hdev,
return err;
}

static int btintel_lc3_freq_preset(struct bt_codec *codec, __u8 *preset)
{
const struct bt_codec_caps *caps;
const u8 *pos, *end;

if (!codec->num_caps) {
*preset = 0x01;
return 0;
}

caps = (const void *)&codec[1];
pos = caps->data;
end = pos + caps->len;

while (pos < end) {
u8 ltv_len = pos[0];

if (!ltv_len || pos + 1 + ltv_len > end)
return -EINVAL;

if (pos[1] == 0x01) { /* Sampling_Frequency */
if (ltv_len != 2)
return -EINVAL;
switch (pos[2]) {
case 0x03: /* 16 kHz */
*preset = 0x01;
return 0;
case 0x08: /* 48 kHz */
*preset = 0x22;
return 0;
default:
return -EINVAL;
}
}
pos += 1 + ltv_len;
}

return -EINVAL;
}

static int btintel_get_codec_config_data(struct hci_dev *hdev,
__u8 link, struct bt_codec *codec,
__u8 *ven_len, __u8 **ven_data)
{
int err = 0;

if (!ven_data || !ven_len)
if (!ven_data || !ven_len || !codec)
return -EINVAL;

*ven_len = 0;
*ven_data = NULL;

if (link != ESCO_LINK) {
bt_dev_err(hdev, "Invalid link type(%u)", link);
return -EINVAL;
}

*ven_data = kmalloc(sizeof(__u8), GFP_KERNEL);
if (!*ven_data) {
err = -ENOMEM;
goto error;
}

/* supports only CVSD and mSBC offload codecs */
switch (codec->id) {
case 0x02:
**ven_data = 0x00;
switch (link) {
case ESCO_LINK:
case SCO_LINK:
switch (codec->id) {
case 0x00:
case 0x01:
case 0x02:
case 0x04:
case 0x03:
**ven_data = 0x00;
break;
case 0x05:
**ven_data = 0x01;
break;
default:
err = -EINVAL;
bt_dev_err(hdev, "Invalid SCO codec id(%u)", codec->id);
goto error;
}
break;
case 0x05:
**ven_data = 0x01;
case ACL_LINK:
/* Preset 0x22 configures 48 kHz 16-bit stereo SSP offload */
**ven_data = 0x22;
break;
case CIS_LINK:
case BIS_LINK:
if (codec->id != BT_CODEC_LC3) {
**ven_data = 0x01;
break;
}
err = btintel_lc3_freq_preset(codec, *ven_data);
if (err) {
bt_dev_err(hdev, "Unsupported LC3 ISO offload config");
goto error;
}
break;
default:
err = -EINVAL;
bt_dev_err(hdev, "Invalid codec id(%u)", codec->id);
bt_dev_err(hdev, "Invalid link type(%u)", link);
goto error;
}

/* codec and its capabilities are pre-defined to ids
* preset id = 0x00 represents CVSD codec with sampling rate 8K
* preset id = 0x01 represents mSBC codec with sampling rate 16K
* preset id = 0x01 represents mSBC/16K mono SCO codec
* preset id = 0x22 represents 48K stereo A2DP / LE Audio offload
*/
*ven_len = sizeof(__u8);
return err;
Expand All @@ -2625,10 +2690,21 @@ static int btintel_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id)

static int btintel_configure_offload(struct hci_dev *hdev)
{
static const u8 ddc_offload_enable[] = {
/* DDC 0x0130: enable LC3, SCO, A2DP SBC/AAC, LE Audio, and delay reporting */
0x03, 0x30, 0x01, 0x3f,
/* DDC 0x0120: enable SCO (BIT(0)), LE ISO (BIT(1)), and A2DP (BIT(3)) */
0x0a, 0x20, 0x01, 0x0b, 0x00, 0x81, 0xf1, 0x01, 0x00, 0x00, 0x00,
};
struct sk_buff *skb;
int err = 0;
struct intel_offload_use_cases *use_cases;

skb = __hci_cmd_sync(hdev, 0xfc8b, sizeof(ddc_offload_enable),
ddc_offload_enable, HCI_INIT_TIMEOUT);
if (!IS_ERR(skb))
kfree_skb(skb);

skb = __hci_cmd_sync(hdev, 0xfc86, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
bt_dev_err(hdev, "Reading offload use cases failed (%ld)",
Expand All @@ -2648,9 +2724,10 @@ static int btintel_configure_offload(struct hci_dev *hdev)
goto error;
}

if (use_cases->preset[0] & 0x03) {
if (use_cases->preset[0] & 0x0b) {
hdev->get_data_path_id = btintel_get_data_path_id;
hdev->get_codec_config_data = btintel_get_codec_config_data;
hci_dev_set_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED);
Comment thread
lgirdwood marked this conversation as resolved.
Resolved
}
error:
kfree_skb(skb);
Expand Down Expand Up @@ -3650,9 +3727,6 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
*/
btintel_load_ddc_config(hdev, ddcname);

/* Read supported use cases and set callbacks to fetch datapath id */
btintel_configure_offload(hdev);

hci_dev_clear_flag(hdev, HCI_QUALITY_REPORT);

/* Send sar values to controller */
Expand All @@ -3672,6 +3746,12 @@ int btintel_bootloader_setup_tlv(struct hci_dev *hdev,
*ver = new_ver;

finish:
/* Read supported use cases and set callbacks to fetch datapath id.
* Run this in finish: so warm reboots (where ver->img_type is already
* BTINTEL_IMG_OP) also register offload callbacks.
*/
btintel_configure_offload(hdev);

/* Set the event mask for Intel specific vendor events. This enables
* a few extra events that are useful during general operation. It
* does not enable any debugging related events.
Expand Down
2 changes: 2 additions & 0 deletions include/net/bluetooth/bluetooth.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,8 @@ struct bt_codecs {
#define BT_CODEC_CVSD 0x02
#define BT_CODEC_TRANSPARENT 0x03
#define BT_CODEC_MSBC 0x05
#define BT_CODEC_LC3 0x06
Comment thread
lgirdwood marked this conversation as resolved.
Resolved
#define BT_CODEC_VENDOR 0xff

#define BT_ISO_BASE 20

Expand Down
31 changes: 31 additions & 0 deletions include/net/bluetooth/hci.h
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,34 @@ struct hci_cp_enhanced_setup_sync_conn {
__u8 retrans_effort;
} __packed;

#define HCI_OP_ENHANCED_ACCEPT_SYNC_CONN 0x043e
struct hci_cp_enhanced_accept_sync_conn {
bdaddr_t bdaddr;
__le32 tx_bandwidth;
__le32 rx_bandwidth;
struct hci_coding_format tx_coding_format;
struct hci_coding_format rx_coding_format;
__le16 tx_codec_frame_size;
__le16 rx_codec_frame_size;
__le32 in_bandwidth;
__le32 out_bandwidth;
struct hci_coding_format in_coding_format;
struct hci_coding_format out_coding_format;
__le16 in_coded_data_size;
__le16 out_coded_data_size;
__u8 in_pcm_data_format;
__u8 out_pcm_data_format;
__u8 in_pcm_sample_payload_msb_pos;
__u8 out_pcm_sample_payload_msb_pos;
__u8 in_data_path;
__u8 out_data_path;
__u8 in_transport_unit_size;
__u8 out_transport_unit_size;
__le16 max_latency;
__le16 pkt_type;
__u8 retrans_effort;
} __packed;

struct hci_rp_logical_link_cancel {
__u8 status;
__u8 phy_handle;
Expand Down Expand Up @@ -3484,7 +3512,10 @@ static inline __u16 hci_acl_dlen(const struct sk_buff *skb)
#define hci_iso_data_flags(h) ((h) >> 14)

/* codec transport types */
#define HCI_TRANSPORT_ACL 0x00
#define HCI_TRANSPORT_SCO_ESCO 0x01
#define HCI_TRANSPORT_LE_CIS 0x02
#define HCI_TRANSPORT_LE_BIS 0x03

/* le24 support */
static inline void hci_cpu_to_le24(__u32 val, __u8 dst[3])
Expand Down
21 changes: 21 additions & 0 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,11 @@ struct hci_conn {
struct hci_conn *parent;
struct hci_link *link;

#define HCI_MAX_CODEC_CFG_LEN 32

struct bt_codec codec;
__u8 codec_cfg[HCI_MAX_CODEC_CFG_LEN];
__u8 codec_cfg_len;

void (*connect_cfm_cb) (struct hci_conn *conn, u8 status);
void (*security_cfm_cb) (struct hci_conn *conn, u8 status);
Expand Down Expand Up @@ -884,6 +888,7 @@ int l2cap_recv_acldata(struct hci_dev *hdev, u16 handle, struct sk_buff *skb,

#if IS_ENABLED(CONFIG_BT_BREDR)
int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags);
void sco_conn_set_codec(struct hci_dev *hdev, struct hci_conn *conn);
int sco_recv_scodata(struct hci_dev *hdev, u16 handle, struct sk_buff *skb);
#else
static inline int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
Expand All @@ -892,6 +897,11 @@ static inline int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
return 0;
}

static inline void sco_conn_set_codec(struct hci_dev *hdev,
struct hci_conn *conn)
{
}

static inline int sco_recv_scodata(struct hci_dev *hdev, u16 handle,
struct sk_buff *skb)
{
Expand All @@ -902,6 +912,8 @@ static inline int sco_recv_scodata(struct hci_dev *hdev, u16 handle,

#if IS_ENABLED(CONFIG_BT_LE)
int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags);
void iso_conn_set_codec(struct hci_dev *hdev, struct hci_conn *conn,
const bdaddr_t *dst);
int iso_recv(struct hci_dev *hdev, u16 handle, struct sk_buff *skb,
u16 flags);
#else
Expand All @@ -911,6 +923,12 @@ static inline int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
return 0;
}

static inline void iso_conn_set_codec(struct hci_dev *hdev,
struct hci_conn *conn,
const bdaddr_t *dst)
{
}

static inline int iso_recv(struct hci_dev *hdev, u16 handle,
struct sk_buff *skb, u16 flags)
{
Expand Down Expand Up @@ -1631,7 +1649,10 @@ static inline bool hci_is_le_conn_scanning(struct hci_dev *hdev)
}

int hci_disconnect(struct hci_conn *conn, __u8 reason);
int hci_configure_datapath(struct hci_dev *hdev, __u8 link,
struct bt_codec *codec);
bool hci_setup_sync(struct hci_conn *conn, __u16 handle);
bool hci_accept_sync(struct hci_conn *conn);
void hci_sco_setup(struct hci_conn *conn, __u8 status);
bool hci_iso_setup_path(struct hci_conn *conn);
int hci_le_create_cis_pending(struct hci_dev *hdev);
Expand Down
2 changes: 2 additions & 0 deletions include/net/bluetooth/l2cap.h
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,8 @@ struct l2cap_chan {
__u8 mode;
__u8 chan_type;
__u8 chan_policy;
__u16 avdtp_handle;
struct mutex avdtp_lock;

__u8 sec_level;

Expand Down
Loading
Loading