Commit b2af264a authored by Kiran K's avatar Kiran K Committed by Luiz Augusto von Dentz
Browse files

Bluetooth: Add support for HCI_Enhanced_Setup_Synchronous_Connection command



< HCI Command: Enhanced Setup Synchronous Connection (0x01|0x003d) plen 59
        Handle: 256
        Transmit bandwidth: 8000
        Receive bandwidth: 8000
        Max latency: 13
        Packet type: 0x0380
          3-EV3 may not be used
          2-EV5 may not be used
          3-EV5 may not be used
        Retransmission effort: Optimize for link quality (0x02)
> HCI Event: Command Status (0x0f) plen 4
      Enhanced Setup Synchronous Connection (0x01|0x003d) ncmd 1
        Status: Success (0x00)
> HCI Event: Synchronous Connect Complete (0x2c) plen 17
        Status: Success (0x00)
        Handle: 257
        Address: CC:98:8B:92:04:FD (SONY Visual Products Inc.)
        Link type: eSCO (0x02)
        Transmission interval: 0x0c
        Retransmission window: 0x06
        RX packet length: 60
        TX packet length: 60
        Air mode: Transparent (0x03)

Signed-off-by: default avatarKiran K <kiran.k@intel.com>
Reviewed-by: default avatarChethan T N <chethan.tumkur.narayan@intel.com>
Reviewed-by: default avatarSrivatsa Ravishankar <ravishankar.srivatsa@intel.com>
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent f6873401
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -174,6 +174,7 @@ struct bt_codecs {
} __packed;

#define BT_CODEC_CVSD		0x02
#define BT_CODEC_TRANSPARENT	0x03

__printf(1, 2)
void bt_info(const char *fmt, ...);
+34 −0
Original line number Diff line number Diff line
@@ -873,6 +873,40 @@ struct hci_cp_logical_link_cancel {
	__u8     flow_spec_id;
} __packed;

#define HCI_OP_ENHANCED_SETUP_SYNC_CONN		0x043d
struct hci_coding_format {
	__u8	id;
	__le16	cid;
	__le16	vid;
} __packed;

struct hci_cp_enhanced_setup_sync_conn {
	__le16   handle;
	__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;
+5 −1
Original line number Diff line number Diff line
@@ -713,6 +713,7 @@ struct hci_conn {
	struct amp_mgr	*amp_mgr;

	struct hci_conn	*link;
	struct bt_codec codec;

	void (*connect_cfm_cb)	(struct hci_conn *conn, u8 status);
	void (*security_cfm_cb)	(struct hci_conn *conn, u8 status);
@@ -1121,7 +1122,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
				 u8 sec_level, u8 auth_type,
				 enum conn_reasons conn_reason);
struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
				 __u16 setting);
				 __u16 setting, struct bt_codec *codec);
int hci_conn_check_link_mode(struct hci_conn *conn);
int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level);
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type,
@@ -1458,6 +1459,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
/* Use LL Privacy based address resolution if supported */
#define use_ll_privacy(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY)

/* Use enhanced synchronous connection if command is supported */
#define enhanced_sco_capable(dev) ((dev)->commands[29] & 0x08)

/* Use ext scanning if set ext scan param and ext scan enable is supported */
#define use_ext_scan(dev) (((dev)->commands[37] & 0x20) && \
			   ((dev)->commands[37] & 0x40))
+102 −3
Original line number Diff line number Diff line
@@ -307,13 +307,103 @@ static bool find_next_esco_param(struct hci_conn *conn,
	return conn->attempt <= size;
}

bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle)
{
	struct hci_dev *hdev = conn->hdev;
	struct hci_cp_enhanced_setup_sync_conn cp;
	const struct sco_param *param;

	bt_dev_dbg(hdev, "hcon %p", conn);

	conn->state = BT_CONNECT;
	conn->out = true;

	conn->attempt++;

	memset(&cp, 0x00, sizeof(cp));

	cp.handle   = cpu_to_le16(handle);

	cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
	cp.rx_bandwidth   = cpu_to_le32(0x00001f40);

	switch (conn->codec.id) {
	case BT_CODEC_TRANSPARENT:
		if (!find_next_esco_param(conn, esco_param_msbc,
					  ARRAY_SIZE(esco_param_msbc)))
			return false;
		param = &esco_param_msbc[conn->attempt - 1];
		cp.tx_coding_format.id = 0x03;
		cp.rx_coding_format.id = 0x03;
		cp.tx_codec_frame_size = __cpu_to_le16(60);
		cp.rx_codec_frame_size = __cpu_to_le16(60);
		cp.in_bandwidth = __cpu_to_le32(0x1f40);
		cp.out_bandwidth = __cpu_to_le32(0x1f40);
		cp.in_coding_format.id = 0x03;
		cp.out_coding_format.id = 0x03;
		cp.in_coded_data_size = __cpu_to_le16(16);
		cp.out_coded_data_size = __cpu_to_le16(16);
		cp.in_pcm_data_format = 2;
		cp.out_pcm_data_format = 2;
		cp.in_pcm_sample_payload_msb_pos = 0;
		cp.out_pcm_sample_payload_msb_pos = 0;
		cp.in_data_path = conn->codec.data_path;
		cp.out_data_path = conn->codec.data_path;
		cp.in_transport_unit_size = 1;
		cp.out_transport_unit_size = 1;
		break;

	case BT_CODEC_CVSD:
		if (lmp_esco_capable(conn->link)) {
			if (!find_next_esco_param(conn, esco_param_cvsd,
						  ARRAY_SIZE(esco_param_cvsd)))
				return false;
			param = &esco_param_cvsd[conn->attempt - 1];
		} else {
			if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
				return false;
			param = &sco_param_cvsd[conn->attempt - 1];
		}
		cp.tx_coding_format.id = 2;
		cp.rx_coding_format.id = 2;
		cp.tx_codec_frame_size = __cpu_to_le16(60);
		cp.rx_codec_frame_size = __cpu_to_le16(60);
		cp.in_bandwidth = __cpu_to_le32(16000);
		cp.out_bandwidth = __cpu_to_le32(16000);
		cp.in_coding_format.id = 4;
		cp.out_coding_format.id = 4;
		cp.in_coded_data_size = __cpu_to_le16(16);
		cp.out_coded_data_size = __cpu_to_le16(16);
		cp.in_pcm_data_format = 2;
		cp.out_pcm_data_format = 2;
		cp.in_pcm_sample_payload_msb_pos = 0;
		cp.out_pcm_sample_payload_msb_pos = 0;
		cp.in_data_path = conn->codec.data_path;
		cp.out_data_path = conn->codec.data_path;
		cp.in_transport_unit_size = 16;
		cp.out_transport_unit_size = 16;
		break;
	default:
		return false;
	}

	cp.retrans_effort = param->retrans_effort;
	cp.pkt_type = __cpu_to_le16(param->pkt_type);
	cp.max_latency = __cpu_to_le16(param->max_latency);

	if (hci_send_cmd(hdev, HCI_OP_ENHANCED_SETUP_SYNC_CONN, sizeof(cp), &cp) < 0)
		return false;

	return true;
}

static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
{
	struct hci_dev *hdev = conn->hdev;
	struct hci_cp_setup_sync_conn cp;
	const struct sco_param *param;

	BT_DBG("hcon %p", conn);
	bt_dev_dbg(hdev, "hcon %p", conn);

	conn->state = BT_CONNECT;
	conn->out = true;
@@ -359,6 +449,14 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
	return true;
}

bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
{
	if (enhanced_sco_capable(conn->hdev))
		return hci_enhanced_setup_sync_conn(conn, handle);

	return hci_setup_sync_conn(conn, handle);
}

u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
		      u16 to_multiplier)
{
@@ -1324,7 +1422,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
}

struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
				 __u16 setting)
				 __u16 setting, struct bt_codec *codec)
{
	struct hci_conn *acl;
	struct hci_conn *sco;
@@ -1349,6 +1447,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
	hci_conn_hold(sco);

	sco->setting = setting;
	sco->codec = *codec;

	if (acl->state == BT_CONNECTED &&
	    (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
+39 −0
Original line number Diff line number Diff line
@@ -2278,6 +2278,41 @@ static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
	hci_dev_unlock(hdev);
}

static void hci_cs_enhanced_setup_sync_conn(struct hci_dev *hdev, __u8 status)
{
	struct hci_cp_enhanced_setup_sync_conn *cp;
	struct hci_conn *acl, *sco;
	__u16 handle;

	bt_dev_dbg(hdev, "status 0x%2.2x", status);

	if (!status)
		return;

	cp = hci_sent_cmd_data(hdev, HCI_OP_ENHANCED_SETUP_SYNC_CONN);
	if (!cp)
		return;

	handle = __le16_to_cpu(cp->handle);

	bt_dev_dbg(hdev, "handle 0x%4.4x", handle);

	hci_dev_lock(hdev);

	acl = hci_conn_hash_lookup_handle(hdev, handle);
	if (acl) {
		sco = acl->link;
		if (sco) {
			sco->state = BT_CLOSED;

			hci_connect_cfm(sco, status);
			hci_conn_del(sco);
		}
	}

	hci_dev_unlock(hdev);
}

static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
{
	struct hci_cp_sniff_mode *cp;
@@ -3764,6 +3799,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
		hci_cs_setup_sync_conn(hdev, ev->status);
		break;

	case HCI_OP_ENHANCED_SETUP_SYNC_CONN:
		hci_cs_enhanced_setup_sync_conn(hdev, ev->status);
		break;

	case HCI_OP_SNIFF_MODE:
		hci_cs_sniff_mode(hdev, ev->status);
		break;
Loading