diff options
Diffstat (limited to 'net/bluetooth/hci_conn.c')
-rw-r--r-- | net/bluetooth/hci_conn.c | 62 |
1 files changed, 50 insertions, 12 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 6c7f36379722..f0817121ec5e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -31,6 +31,24 @@ | |||
31 | #include <net/bluetooth/a2mp.h> | 31 | #include <net/bluetooth/a2mp.h> |
32 | #include <net/bluetooth/smp.h> | 32 | #include <net/bluetooth/smp.h> |
33 | 33 | ||
34 | struct sco_param { | ||
35 | u16 pkt_type; | ||
36 | u16 max_latency; | ||
37 | }; | ||
38 | |||
39 | static const struct sco_param sco_param_cvsd[] = { | ||
40 | { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a }, /* S3 */ | ||
41 | { EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007 }, /* S2 */ | ||
42 | { EDR_ESCO_MASK | ESCO_EV3, 0x0007 }, /* S1 */ | ||
43 | { EDR_ESCO_MASK | ESCO_HV3, 0xffff }, /* D1 */ | ||
44 | { EDR_ESCO_MASK | ESCO_HV1, 0xffff }, /* D0 */ | ||
45 | }; | ||
46 | |||
47 | static const struct sco_param sco_param_wideband[] = { | ||
48 | { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d }, /* T2 */ | ||
49 | { EDR_ESCO_MASK | ESCO_EV3, 0x0008 }, /* T1 */ | ||
50 | }; | ||
51 | |||
34 | static void hci_le_create_connection(struct hci_conn *conn) | 52 | static void hci_le_create_connection(struct hci_conn *conn) |
35 | { | 53 | { |
36 | struct hci_dev *hdev = conn->hdev; | 54 | struct hci_dev *hdev = conn->hdev; |
@@ -172,10 +190,11 @@ static void hci_add_sco(struct hci_conn *conn, __u16 handle) | |||
172 | hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp); | 190 | hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp); |
173 | } | 191 | } |
174 | 192 | ||
175 | void hci_setup_sync(struct hci_conn *conn, __u16 handle) | 193 | bool hci_setup_sync(struct hci_conn *conn, __u16 handle) |
176 | { | 194 | { |
177 | struct hci_dev *hdev = conn->hdev; | 195 | struct hci_dev *hdev = conn->hdev; |
178 | struct hci_cp_setup_sync_conn cp; | 196 | struct hci_cp_setup_sync_conn cp; |
197 | const struct sco_param *param; | ||
179 | 198 | ||
180 | BT_DBG("hcon %p", conn); | 199 | BT_DBG("hcon %p", conn); |
181 | 200 | ||
@@ -185,15 +204,35 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) | |||
185 | conn->attempt++; | 204 | conn->attempt++; |
186 | 205 | ||
187 | cp.handle = cpu_to_le16(handle); | 206 | cp.handle = cpu_to_le16(handle); |
188 | cp.pkt_type = cpu_to_le16(conn->pkt_type); | ||
189 | 207 | ||
190 | cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); | 208 | cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); |
191 | cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); | 209 | cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); |
192 | cp.max_latency = __constant_cpu_to_le16(0xffff); | 210 | cp.voice_setting = cpu_to_le16(conn->setting); |
193 | cp.voice_setting = cpu_to_le16(hdev->voice_setting); | 211 | |
194 | cp.retrans_effort = 0xff; | 212 | switch (conn->setting & SCO_AIRMODE_MASK) { |
213 | case SCO_AIRMODE_TRANSP: | ||
214 | if (conn->attempt > ARRAY_SIZE(sco_param_wideband)) | ||
215 | return false; | ||
216 | cp.retrans_effort = 0x02; | ||
217 | param = &sco_param_wideband[conn->attempt - 1]; | ||
218 | break; | ||
219 | case SCO_AIRMODE_CVSD: | ||
220 | if (conn->attempt > ARRAY_SIZE(sco_param_cvsd)) | ||
221 | return false; | ||
222 | cp.retrans_effort = 0x01; | ||
223 | param = &sco_param_cvsd[conn->attempt - 1]; | ||
224 | break; | ||
225 | default: | ||
226 | return false; | ||
227 | } | ||
195 | 228 | ||
196 | hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp); | 229 | cp.pkt_type = __cpu_to_le16(param->pkt_type); |
230 | cp.max_latency = __cpu_to_le16(param->max_latency); | ||
231 | |||
232 | if (hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp) < 0) | ||
233 | return false; | ||
234 | |||
235 | return true; | ||
197 | } | 236 | } |
198 | 237 | ||
199 | void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, | 238 | void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, |
@@ -560,13 +599,13 @@ static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, | |||
560 | return acl; | 599 | return acl; |
561 | } | 600 | } |
562 | 601 | ||
563 | static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, | 602 | struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, |
564 | bdaddr_t *dst, u8 sec_level, u8 auth_type) | 603 | __u16 setting) |
565 | { | 604 | { |
566 | struct hci_conn *acl; | 605 | struct hci_conn *acl; |
567 | struct hci_conn *sco; | 606 | struct hci_conn *sco; |
568 | 607 | ||
569 | acl = hci_connect_acl(hdev, dst, sec_level, auth_type); | 608 | acl = hci_connect_acl(hdev, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); |
570 | if (IS_ERR(acl)) | 609 | if (IS_ERR(acl)) |
571 | return acl; | 610 | return acl; |
572 | 611 | ||
@@ -584,6 +623,8 @@ static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, | |||
584 | 623 | ||
585 | hci_conn_hold(sco); | 624 | hci_conn_hold(sco); |
586 | 625 | ||
626 | sco->setting = setting; | ||
627 | |||
587 | if (acl->state == BT_CONNECTED && | 628 | if (acl->state == BT_CONNECTED && |
588 | (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { | 629 | (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { |
589 | set_bit(HCI_CONN_POWER_SAVE, &acl->flags); | 630 | set_bit(HCI_CONN_POWER_SAVE, &acl->flags); |
@@ -612,9 +653,6 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, | |||
612 | return hci_connect_le(hdev, dst, dst_type, sec_level, auth_type); | 653 | return hci_connect_le(hdev, dst, dst_type, sec_level, auth_type); |
613 | case ACL_LINK: | 654 | case ACL_LINK: |
614 | return hci_connect_acl(hdev, dst, sec_level, auth_type); | 655 | return hci_connect_acl(hdev, dst, sec_level, auth_type); |
615 | case SCO_LINK: | ||
616 | case ESCO_LINK: | ||
617 | return hci_connect_sco(hdev, type, dst, sec_level, auth_type); | ||
618 | } | 656 | } |
619 | 657 | ||
620 | return ERR_PTR(-EINVAL); | 658 | return ERR_PTR(-EINVAL); |