Commit 5b7f9909 authored by Marcel Holtmann's avatar Marcel Holtmann

[Bluetooth] Add basics to better support and handle eSCO links

To better support and handle eSCO links in the future a bunch of
constants needs to be added and some basic routines need to be
updated. This is the initial step.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 8de0a154
...@@ -107,14 +107,14 @@ enum { ...@@ -107,14 +107,14 @@ enum {
#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */ #define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */
#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ #define HCI_INIT_TIMEOUT (10000) /* 10 seconds */
/* HCI Packet types */ /* HCI data types */
#define HCI_COMMAND_PKT 0x01 #define HCI_COMMAND_PKT 0x01
#define HCI_ACLDATA_PKT 0x02 #define HCI_ACLDATA_PKT 0x02
#define HCI_SCODATA_PKT 0x03 #define HCI_SCODATA_PKT 0x03
#define HCI_EVENT_PKT 0x04 #define HCI_EVENT_PKT 0x04
#define HCI_VENDOR_PKT 0xff #define HCI_VENDOR_PKT 0xff
/* HCI Packet types */ /* HCI packet types */
#define HCI_DM1 0x0008 #define HCI_DM1 0x0008
#define HCI_DM3 0x0400 #define HCI_DM3 0x0400
#define HCI_DM5 0x4000 #define HCI_DM5 0x4000
...@@ -129,6 +129,14 @@ enum { ...@@ -129,6 +129,14 @@ enum {
#define SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3) #define SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3)
#define ACL_PTYPE_MASK (~SCO_PTYPE_MASK) #define ACL_PTYPE_MASK (~SCO_PTYPE_MASK)
/* eSCO packet types */
#define ESCO_HV1 0x0001
#define ESCO_HV2 0x0002
#define ESCO_HV3 0x0004
#define ESCO_EV3 0x0008
#define ESCO_EV4 0x0010
#define ESCO_EV5 0x0020
/* ACL flags */ /* ACL flags */
#define ACL_CONT 0x01 #define ACL_CONT 0x01
#define ACL_START 0x02 #define ACL_START 0x02
...@@ -138,6 +146,7 @@ enum { ...@@ -138,6 +146,7 @@ enum {
/* Baseband links */ /* Baseband links */
#define SCO_LINK 0x00 #define SCO_LINK 0x00
#define ACL_LINK 0x01 #define ACL_LINK 0x01
#define ESCO_LINK 0x02
/* LMP features */ /* LMP features */
#define LMP_3SLOT 0x01 #define LMP_3SLOT 0x01
...@@ -162,6 +171,11 @@ enum { ...@@ -162,6 +171,11 @@ enum {
#define LMP_PSCHEME 0x02 #define LMP_PSCHEME 0x02
#define LMP_PCONTROL 0x04 #define LMP_PCONTROL 0x04
#define LMP_ESCO 0x80
#define LMP_EV4 0x01
#define LMP_EV5 0x02
#define LMP_SNIFF_SUBR 0x02 #define LMP_SNIFF_SUBR 0x02
/* Connection modes */ /* Connection modes */
......
...@@ -78,6 +78,7 @@ struct hci_dev { ...@@ -78,6 +78,7 @@ struct hci_dev {
__u16 voice_setting; __u16 voice_setting;
__u16 pkt_type; __u16 pkt_type;
__u16 esco_type;
__u16 link_policy; __u16 link_policy;
__u16 link_mode; __u16 link_mode;
...@@ -452,6 +453,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn); ...@@ -452,6 +453,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT) #define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT)
#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF) #define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) #define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
/* ----- HCI protocols ----- */ /* ----- HCI protocols ----- */
struct hci_proto { struct hci_proto {
......
...@@ -123,8 +123,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) ...@@ -123,8 +123,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
conn->state = BT_CONNECT; conn->state = BT_CONNECT;
conn->out = 1; conn->out = 1;
cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
cp.handle = cpu_to_le16(handle); cp.handle = cpu_to_le16(handle);
cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, sizeof(cp), &cp); hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, sizeof(cp), &cp);
} }
...@@ -220,19 +220,19 @@ int hci_conn_del(struct hci_conn *conn) ...@@ -220,19 +220,19 @@ int hci_conn_del(struct hci_conn *conn)
del_timer(&conn->disc_timer); del_timer(&conn->disc_timer);
if (conn->type == SCO_LINK) { if (conn->type == ACL_LINK) {
struct hci_conn *acl = conn->link;
if (acl) {
acl->link = NULL;
hci_conn_put(acl);
}
} else {
struct hci_conn *sco = conn->link; struct hci_conn *sco = conn->link;
if (sco) if (sco)
sco->link = NULL; sco->link = NULL;
/* Unacked frames */ /* Unacked frames */
hdev->acl_cnt += conn->sent; hdev->acl_cnt += conn->sent;
} else {
struct hci_conn *acl = conn->link;
if (acl) {
acl->link = NULL;
hci_conn_put(acl);
}
} }
tasklet_disable(&hdev->tx_task); tasklet_disable(&hdev->tx_task);
...@@ -297,9 +297,10 @@ EXPORT_SYMBOL(hci_get_route); ...@@ -297,9 +297,10 @@ EXPORT_SYMBOL(hci_get_route);
/* Create SCO or ACL connection. /* Create SCO or ACL connection.
* Device _must_ be locked */ * Device _must_ be locked */
struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst) struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
{ {
struct hci_conn *acl; struct hci_conn *acl;
struct hci_conn *sco;
BT_DBG("%s dst %s", hdev->name, batostr(dst)); BT_DBG("%s dst %s", hdev->name, batostr(dst));
...@@ -313,15 +314,16 @@ struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst) ...@@ -313,15 +314,16 @@ struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
if (acl->state == BT_OPEN || acl->state == BT_CLOSED) if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
hci_acl_connect(acl); hci_acl_connect(acl);
if (type == SCO_LINK) { if (type == ACL_LINK)
struct hci_conn *sco; return acl;
if (!(sco = hci_conn_hash_lookup_ba(hdev, SCO_LINK, dst))) { if (!(sco = hci_conn_hash_lookup_ba(hdev, type, dst))) {
if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) { if (!(sco = hci_conn_add(hdev, type, dst))) {
hci_conn_put(acl); hci_conn_put(acl);
return NULL; return NULL;
} }
} }
acl->link = sco; acl->link = sco;
sco->link = acl; sco->link = acl;
...@@ -332,9 +334,6 @@ struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst) ...@@ -332,9 +334,6 @@ struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
hci_add_sco(sco, acl->handle); hci_add_sco(sco, acl->handle);
return sco; return sco;
} else {
return acl;
}
} }
EXPORT_SYMBOL(hci_connect); EXPORT_SYMBOL(hci_connect);
......
...@@ -851,6 +851,7 @@ int hci_register_dev(struct hci_dev *hdev) ...@@ -851,6 +851,7 @@ int hci_register_dev(struct hci_dev *hdev)
hdev->flags = 0; hdev->flags = 0;
hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
hdev->esco_type = (ESCO_HV1);
hdev->link_mode = (HCI_LM_ACCEPT); hdev->link_mode = (HCI_LM_ACCEPT);
hdev->idle_timeout = 0; hdev->idle_timeout = 0;
......
...@@ -350,11 +350,24 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s ...@@ -350,11 +350,24 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
if (hdev->features[0] & LMP_5SLOT) if (hdev->features[0] & LMP_5SLOT)
hdev->pkt_type |= (HCI_DM5 | HCI_DH5); hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
if (hdev->features[1] & LMP_HV2) if (hdev->features[1] & LMP_HV2) {
hdev->pkt_type |= (HCI_HV2); hdev->pkt_type |= (HCI_HV2);
hdev->esco_type |= (ESCO_HV2);
}
if (hdev->features[1] & LMP_HV3) if (hdev->features[1] & LMP_HV3) {
hdev->pkt_type |= (HCI_HV3); hdev->pkt_type |= (HCI_HV3);
hdev->esco_type |= (ESCO_HV3);
}
if (hdev->features[3] & LMP_ESCO)
hdev->esco_type |= (ESCO_EV3);
if (hdev->features[4] & LMP_EV4)
hdev->esco_type |= (ESCO_EV4);
if (hdev->features[4] & LMP_EV5)
hdev->esco_type |= (ESCO_EV5);
BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name,
lf->features[0], lf->features[1], lf->features[2]); lf->features[0], lf->features[1], lf->features[2]);
...@@ -881,12 +894,12 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s ...@@ -881,12 +894,12 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
if (conn) { if (conn) {
conn->sent -= count; conn->sent -= count;
if (conn->type == SCO_LINK) { if (conn->type == ACL_LINK) {
if ((hdev->sco_cnt += count) > hdev->sco_pkts)
hdev->sco_cnt = hdev->sco_pkts;
} else {
if ((hdev->acl_cnt += count) > hdev->acl_pkts) if ((hdev->acl_cnt += count) > hdev->acl_pkts)
hdev->acl_cnt = hdev->acl_pkts; hdev->acl_cnt = hdev->acl_pkts;
} else {
if ((hdev->sco_cnt += count) > hdev->sco_pkts)
hdev->sco_cnt = hdev->sco_pkts;
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment