Commit 26afbd82 authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz
Browse files

Bluetooth: Add initial implementation of CIS connections



This adds the initial implementation of CIS connections and introduces
the ISO packets/links.

== Central: Set CIG Parameters, create a CIS and Setup Data Path ==

> tools/isotest -s <address>

< HCI Command: LE Extended Create... (0x08|0x0043) plen 26
...
> HCI Event: Command Status (0x0f) plen 4
      LE Extended Create Connection (0x08|0x0043) ncmd 1
        Status: Success (0x00)
> HCI Event: LE Meta Event (0x3e) plen 31
      LE Enhanced Connection Complete (0x0a)
      ...
< HCI Command: LE Create Connected... (0x08|0x0064) plen 5
...
> HCI Event: Command Status (0x0f) plen 4
      LE Create Connected Isochronous Stream (0x08|0x0064) ncmd 1
        Status: Success (0x00)
> HCI Event: LE Meta Event (0x3e) plen 29
      LE Connected Isochronous Stream Established (0x19)
      ...
< HCI Command: LE Setup Isochronou.. (0x08|0x006e) plen 13
...
> HCI Event: Command Complete (0x0e) plen 6
      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        Status: Success (0x00)
        Handle: 257
< HCI Command: LE Setup Isochronou.. (0x08|0x006e) plen 13
...
> HCI Event: Command Complete (0x0e) plen 6
      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        Status: Success (0x00)
        Handle: 257

== Peripheral: Accept CIS and Setup Data Path ==

> tools/isotest -d

 HCI Event: LE Meta Event (0x3e) plen 7
      LE Connected Isochronous Stream Request (0x1a)
...
< HCI Command: LE Accept Co.. (0x08|0x0066) plen 2
...
> HCI Event: LE Meta Event (0x3e) plen 29
      LE Connected Isochronous Stream Established (0x19)
...
< HCI Command: LE Setup Is.. (0x08|0x006e) plen 13
...
> HCI Event: Command Complete (0x0e) plen 6
      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        Status: Success (0x00)
        Handle: 257
< HCI Command: LE Setup Is.. (0x08|0x006e) plen 13
...
> HCI Event: Command Complete (0x0e) plen 6
      LE Setup Isochronous Data Path (0x08|0x006e) ncmd 1
        Status: Success (0x00)
        Handle: 257

Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
parent dfe6d5c3
Loading
Loading
Loading
Loading
+32 −1
Original line number Diff line number Diff line
@@ -55,6 +55,8 @@
#define BTPROTO_CMTP	5
#define BTPROTO_HIDP	6
#define BTPROTO_AVDTP	7
#define BTPROTO_ISO	8
#define BTPROTO_LAST	BTPROTO_ISO

#define SOL_HCI		0
#define SOL_L2CAP	6
@@ -153,6 +155,35 @@ struct bt_voice {

#define BT_SCM_PKT_STATUS	0x03

#define BT_ISO_QOS		17

#define BT_ISO_QOS_CIG_UNSET	0xff
#define BT_ISO_QOS_CIS_UNSET	0xff

struct bt_iso_io_qos {
	__u32 interval;
	__u16 latency;
	__u16 sdu;
	__u8  phy;
	__u8  rtn;
};

struct bt_iso_qos {
	__u8  cig;
	__u8  cis;
	__u8  sca;
	__u8  packing;
	__u8  framing;
	struct bt_iso_io_qos in;
	struct bt_iso_io_qos out;
};

#define BT_ISO_PHY_1M		0x01
#define BT_ISO_PHY_2M		0x02
#define BT_ISO_PHY_CODED	0x04
#define BT_ISO_PHY_ANY		(BT_ISO_PHY_1M | BT_ISO_PHY_2M | \
				 BT_ISO_PHY_CODED)

#define BT_CODEC	19

struct	bt_codec_caps {
+26 −2
Original line number Diff line number Diff line
@@ -1989,7 +1989,7 @@ struct hci_rp_le_read_iso_tx_sync {
struct hci_cis_params {
	__u8    cis_id;
	__le16  c_sdu;
	__le16  p_pdu;
	__le16  p_sdu;
	__u8    c_phy;
	__u8    p_phy;
	__u8    c_rtn;
@@ -2000,7 +2000,7 @@ struct hci_cp_le_set_cig_params {
	__u8    cig_id;
	__u8    c_interval[3];
	__u8    p_interval[3];
	__u8    wc_sca;
	__u8    sca;
	__u8    packing;
	__u8    framing;
	__le16  c_latency;
@@ -2043,6 +2043,30 @@ struct hci_cp_le_reject_cis {
	__u8    reason;
} __packed;

#define HCI_OP_LE_SETUP_ISO_PATH		0x206e
struct hci_cp_le_setup_iso_path {
	__le16  handle;
	__u8    direction;
	__u8    path;
	__u8    codec;
	__le16  codec_cid;
	__le16  codec_vid;
	__u8    delay[3];
	__u8    codec_cfg_len;
	__u8    codec_cfg[0];
} __packed;

struct hci_rp_le_setup_iso_path {
	__u8    status;
	__le16  handle;
} __packed;

#define HCI_OP_LE_SET_HOST_FEATURE		0x2074
struct hci_cp_le_set_host_feature {
	__u8     bit_number;
	__u8     bit_value;
} __packed;

/* ---- HCI Events ---- */
struct hci_ev_status {
	__u8    status;
+106 −1
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ struct hci_conn_hash {
	unsigned int     acl_num;
	unsigned int     amp_num;
	unsigned int     sco_num;
	unsigned int     iso_num;
	unsigned int     le_num;
	unsigned int     le_num_peripheral;
};
@@ -474,13 +475,16 @@ struct hci_dev {
	unsigned int	acl_cnt;
	unsigned int	sco_cnt;
	unsigned int	le_cnt;
	unsigned int	iso_cnt;

	unsigned int	acl_mtu;
	unsigned int	sco_mtu;
	unsigned int	le_mtu;
	unsigned int	iso_mtu;
	unsigned int	acl_pkts;
	unsigned int	sco_pkts;
	unsigned int	le_pkts;
	unsigned int	iso_pkts;

	__u16		block_len;
	__u16		block_mtu;
@@ -657,6 +661,7 @@ enum conn_reasons {
	CONN_REASON_PAIR_DEVICE,
	CONN_REASON_L2CAP_CHAN,
	CONN_REASON_SCO_CONNECT,
	CONN_REASON_ISO_CONNECT,
};

struct hci_conn {
@@ -709,6 +714,7 @@ struct hci_conn {
	__s8		rssi;
	__s8		tx_power;
	__s8		max_tx_power;
	struct bt_iso_qos iso_qos;
	unsigned long	flags;

	enum conn_reasons conn_reason;
@@ -739,6 +745,7 @@ struct hci_conn {
	struct hci_dev	*hdev;
	void		*l2cap_data;
	void		*sco_data;
	void		*iso_data;
	struct amp_mgr	*amp_mgr;

	struct hci_conn	*link;
@@ -747,6 +754,8 @@ struct hci_conn {
	void (*connect_cfm_cb)	(struct hci_conn *conn, u8 status);
	void (*security_cfm_cb)	(struct hci_conn *conn, u8 status);
	void (*disconn_cfm_cb)	(struct hci_conn *conn, u8 reason);

	void (*cleanup)(struct hci_conn *conn);
};

struct hci_chan {
@@ -954,6 +963,9 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
	case ESCO_LINK:
		h->sco_num++;
		break;
	case ISO_LINK:
		h->iso_num++;
		break;
	}
}

@@ -980,6 +992,9 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
	case ESCO_LINK:
		h->sco_num--;
		break;
	case ISO_LINK:
		h->iso_num--;
		break;
	}
}

@@ -996,6 +1011,8 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
	case SCO_LINK:
	case ESCO_LINK:
		return h->sco_num;
	case ISO_LINK:
		return h->iso_num;
	default:
		return 0;
	}
@@ -1005,7 +1022,7 @@ static inline unsigned int hci_conn_count(struct hci_dev *hdev)
{
	struct hci_conn_hash *c = &hdev->conn_hash;

	return c->acl_num + c->amp_num + c->sco_num + c->le_num;
	return c->acl_num + c->amp_num + c->sco_num + c->le_num + c->iso_num;
}

static inline __u8 hci_conn_lookup_type(struct hci_dev *hdev, __u16 handle)
@@ -1091,6 +1108,53 @@ static inline struct hci_conn *hci_conn_hash_lookup_le(struct hci_dev *hdev,
	return NULL;
}

static inline struct hci_conn *hci_conn_hash_lookup_cis(struct hci_dev *hdev,
							bdaddr_t *ba,
							__u8 ba_type)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	struct hci_conn  *c;

	rcu_read_lock();

	list_for_each_entry_rcu(c, &h->list, list) {
		if (c->type != ISO_LINK)
			continue;

		if (ba_type == c->dst_type && !bacmp(&c->dst, ba)) {
			rcu_read_unlock();
			return c;
		}
	}

	rcu_read_unlock();

	return NULL;
}

static inline struct hci_conn *hci_conn_hash_lookup_cig(struct hci_dev *hdev,
							__u8 handle)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	struct hci_conn  *c;

	rcu_read_lock();

	list_for_each_entry_rcu(c, &h->list, list) {
		if (c->type != ISO_LINK)
			continue;

		if (handle == c->iso_qos.cig) {
			rcu_read_unlock();
			return c;
		}
	}

	rcu_read_unlock();

	return NULL;
}

static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
							__u8 type, __u16 state)
{
@@ -1111,6 +1175,27 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
	return NULL;
}

typedef void (*hci_conn_func_t)(struct hci_conn *conn, void *data);
static inline void hci_conn_hash_list_state(struct hci_dev *hdev,
					    hci_conn_func_t func, __u8 type,
					    __u16 state, void *data)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	struct hci_conn  *c;

	if (!func)
		return;

	rcu_read_lock();

	list_for_each_entry_rcu(c, &h->list, list) {
		if (c->type == type && c->state == state)
			func(c, data);
	}

	rcu_read_unlock();
}

static inline struct hci_conn *hci_lookup_le_connect(struct hci_dev *hdev)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
@@ -1134,6 +1219,8 @@ static inline struct hci_conn *hci_lookup_le_connect(struct hci_dev *hdev)
int hci_disconnect(struct hci_conn *conn, __u8 reason);
bool hci_setup_sync(struct hci_conn *conn, __u16 handle);
void hci_sco_setup(struct hci_conn *conn, __u8 status);
bool hci_iso_setup_path(struct hci_conn *conn);
int hci_le_create_cis(struct hci_conn *conn);

struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst,
			      u8 role);
@@ -1158,6 +1245,10 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
				 enum conn_reasons conn_reason);
struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
				 __u16 setting, struct bt_codec *codec);
struct hci_conn *hci_bind_cis(struct hci_dev *hdev, bdaddr_t *dst,
			      __u8 dst_type, struct bt_iso_qos *qos);
struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst,
				 __u8 dst_type, struct bt_iso_qos *qos);
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,
@@ -1525,6 +1616,15 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define use_enhanced_conn_complete(dev) (ll_privacy_capable(dev) || \
					 ext_adv_capable(dev))

/* CIS Master/Slave support */
#define iso_capable(dev) (cis_capable(dev))
#define cis_capable(dev) \
	(cis_central_capable(dev) || cis_peripheral_capable(dev))
#define cis_central_capable(dev) \
	((dev)->le_features[3] & HCI_LE_CIS_CENTRAL)
#define cis_peripheral_capable(dev) \
	((dev)->le_features[3] & HCI_LE_CIS_PERIPHERAL)

/* ----- HCI protocols ----- */
#define HCI_PROTO_DEFER             0x01

@@ -1539,6 +1639,10 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
	case ESCO_LINK:
		return sco_connect_ind(hdev, bdaddr, flags);

	case ISO_LINK:
		/* TODO: Handle connection indication */
		return -EINVAL;

	default:
		BT_ERR("unknown link type %d", type);
		return -EINVAL;
@@ -1746,6 +1850,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
		 const void *param);
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
void hci_send_iso(struct hci_conn *conn, struct sk_buff *skb);

void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
void *hci_recv_event_data(struct hci_dev *hdev, __u8 event);
+2 −0
Original line number Diff line number Diff line
@@ -124,6 +124,8 @@ struct hci_dev_info {
	__u16 acl_pkts;
	__u16 sco_mtu;
	__u16 sco_pkts;
	__u16 iso_mtu;
	__u16 iso_pkts;

	struct hci_dev_stats stat;
};
+3 −0
Original line number Diff line number Diff line
@@ -109,3 +109,6 @@ struct hci_conn;
int hci_abort_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, u8 reason);

int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn);

int hci_le_remove_cig_sync(struct hci_dev *hdev, u8 handle);
int hci_le_remove_cig(struct hci_dev *hdev, u8 handle);
Loading