diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2007-10-20 08:55:10 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-22 05:59:47 -0400 |
commit | b6a0dc822497e1c0b9e8c4add270cc27fce48454 (patch) | |
tree | ecfd0a08f62e4c6c7d1e63e62c04b6c17ca09cb6 /net/bluetooth/hci_event.c | |
parent | dae6a0f6636d05bcb28ece1f3630b23ed2d66e18 (diff) |
[Bluetooth] Add support for handling simple eSCO links
With the Bluetooth 1.2 specification the Extended SCO feature for
better audio connections was introduced. So far the Bluetooth core
wasn't able to handle any eSCO connections correctly. This patch
adds simple eSCO support while keeping backward compatibility with
older devices.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/hci_event.c')
-rw-r--r-- | net/bluetooth/hci_event.c | 99 |
1 files changed, 86 insertions, 13 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e2cfeea5ee72..46df2e403df8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -511,11 +511,11 @@ static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status) | |||
511 | struct hci_conn *acl, *sco; | 511 | struct hci_conn *acl, *sco; |
512 | __u16 handle; | 512 | __u16 handle; |
513 | 513 | ||
514 | BT_DBG("%s status 0x%x", hdev->name, status); | ||
515 | |||
514 | if (!status) | 516 | if (!status) |
515 | return; | 517 | return; |
516 | 518 | ||
517 | BT_DBG("%s status 0x%x", hdev->name, status); | ||
518 | |||
519 | cp = hci_sent_cmd_data(hdev, HCI_OP_ADD_SCO); | 519 | cp = hci_sent_cmd_data(hdev, HCI_OP_ADD_SCO); |
520 | if (!cp) | 520 | if (!cp) |
521 | return; | 521 | return; |
@@ -544,7 +544,34 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) | |||
544 | 544 | ||
545 | static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status) | 545 | static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status) |
546 | { | 546 | { |
547 | struct hci_cp_setup_sync_conn *cp; | ||
548 | struct hci_conn *acl, *sco; | ||
549 | __u16 handle; | ||
550 | |||
547 | BT_DBG("%s status 0x%x", hdev->name, status); | 551 | BT_DBG("%s status 0x%x", hdev->name, status); |
552 | |||
553 | if (!status) | ||
554 | return; | ||
555 | |||
556 | cp = hci_sent_cmd_data(hdev, HCI_OP_SETUP_SYNC_CONN); | ||
557 | if (!cp) | ||
558 | return; | ||
559 | |||
560 | handle = __le16_to_cpu(cp->handle); | ||
561 | |||
562 | BT_DBG("%s handle %d", hdev->name, handle); | ||
563 | |||
564 | hci_dev_lock(hdev); | ||
565 | |||
566 | acl = hci_conn_hash_lookup_handle(hdev, handle); | ||
567 | if (acl && (sco = acl->link)) { | ||
568 | sco->state = BT_CLOSED; | ||
569 | |||
570 | hci_proto_connect_cfm(sco, status); | ||
571 | hci_conn_del(sco); | ||
572 | } | ||
573 | |||
574 | hci_dev_unlock(hdev); | ||
548 | } | 575 | } |
549 | 576 | ||
550 | static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status) | 577 | static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status) |
@@ -692,9 +719,12 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s | |||
692 | if (conn->type == ACL_LINK) { | 719 | if (conn->type == ACL_LINK) { |
693 | struct hci_conn *sco = conn->link; | 720 | struct hci_conn *sco = conn->link; |
694 | if (sco) { | 721 | if (sco) { |
695 | if (!ev->status) | 722 | if (!ev->status) { |
696 | hci_add_sco(sco, conn->handle); | 723 | if (lmp_esco_capable(hdev)) |
697 | else { | 724 | hci_setup_sync(sco, conn->handle); |
725 | else | ||
726 | hci_add_sco(sco, conn->handle); | ||
727 | } else { | ||
698 | hci_proto_connect_cfm(sco, ev->status); | 728 | hci_proto_connect_cfm(sco, ev->status); |
699 | hci_conn_del(sco); | 729 | hci_conn_del(sco); |
700 | } | 730 | } |
@@ -724,9 +754,9 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
724 | if (mask & HCI_LM_ACCEPT) { | 754 | if (mask & HCI_LM_ACCEPT) { |
725 | /* Connection accepted */ | 755 | /* Connection accepted */ |
726 | struct hci_conn *conn; | 756 | struct hci_conn *conn; |
727 | struct hci_cp_accept_conn_req cp; | ||
728 | 757 | ||
729 | hci_dev_lock(hdev); | 758 | hci_dev_lock(hdev); |
759 | |||
730 | conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); | 760 | conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); |
731 | if (!conn) { | 761 | if (!conn) { |
732 | if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) { | 762 | if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) { |
@@ -735,18 +765,39 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
735 | return; | 765 | return; |
736 | } | 766 | } |
737 | } | 767 | } |
768 | |||
738 | memcpy(conn->dev_class, ev->dev_class, 3); | 769 | memcpy(conn->dev_class, ev->dev_class, 3); |
739 | conn->state = BT_CONNECT; | 770 | conn->state = BT_CONNECT; |
771 | |||
740 | hci_dev_unlock(hdev); | 772 | hci_dev_unlock(hdev); |
741 | 773 | ||
742 | bacpy(&cp.bdaddr, &ev->bdaddr); | 774 | if (ev->link_type == ACL_LINK || !lmp_esco_capable(hdev)) { |
775 | struct hci_cp_accept_conn_req cp; | ||
743 | 776 | ||
744 | if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) | 777 | bacpy(&cp.bdaddr, &ev->bdaddr); |
745 | cp.role = 0x00; /* Become master */ | 778 | |
746 | else | 779 | if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) |
747 | cp.role = 0x01; /* Remain slave */ | 780 | cp.role = 0x00; /* Become master */ |
781 | else | ||
782 | cp.role = 0x01; /* Remain slave */ | ||
783 | |||
784 | hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, | ||
785 | sizeof(cp), &cp); | ||
786 | } else { | ||
787 | struct hci_cp_accept_sync_conn_req cp; | ||
788 | |||
789 | bacpy(&cp.bdaddr, &ev->bdaddr); | ||
790 | cp.pkt_type = cpu_to_le16(hdev->esco_type); | ||
791 | |||
792 | cp.tx_bandwidth = cpu_to_le32(0x00001f40); | ||
793 | cp.rx_bandwidth = cpu_to_le32(0x00001f40); | ||
794 | cp.max_latency = cpu_to_le16(0xffff); | ||
795 | cp.content_format = cpu_to_le16(hdev->voice_setting); | ||
796 | cp.retrans_effort = 0xff; | ||
748 | 797 | ||
749 | hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp); | 798 | hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, |
799 | sizeof(cp), &cp); | ||
800 | } | ||
750 | } else { | 801 | } else { |
751 | /* Connection rejected */ | 802 | /* Connection rejected */ |
752 | struct hci_cp_reject_conn_req cp; | 803 | struct hci_cp_reject_conn_req cp; |
@@ -1254,7 +1305,29 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b | |||
1254 | 1305 | ||
1255 | static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1306 | static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
1256 | { | 1307 | { |
1257 | BT_DBG("%s", hdev->name); | 1308 | struct hci_ev_sync_conn_complete *ev = (void *) skb->data; |
1309 | struct hci_conn *conn; | ||
1310 | |||
1311 | BT_DBG("%s status %d", hdev->name, ev->status); | ||
1312 | |||
1313 | hci_dev_lock(hdev); | ||
1314 | |||
1315 | conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); | ||
1316 | if (!conn) | ||
1317 | goto unlock; | ||
1318 | |||
1319 | if (!ev->status) { | ||
1320 | conn->handle = __le16_to_cpu(ev->handle); | ||
1321 | conn->state = BT_CONNECTED; | ||
1322 | } else | ||
1323 | conn->state = BT_CLOSED; | ||
1324 | |||
1325 | hci_proto_connect_cfm(conn, ev->status); | ||
1326 | if (ev->status) | ||
1327 | hci_conn_del(conn); | ||
1328 | |||
1329 | unlock: | ||
1330 | hci_dev_unlock(hdev); | ||
1258 | } | 1331 | } |
1259 | 1332 | ||
1260 | static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1333 | static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb) |