Bluetooth: Add SCO fallback for eSCO connection attempts
When attempting to setup eSCO connections it can happen that some link manager implementations fail to properly negotiate the eSCO parameters and thus fail the eSCO setup. Normally the link manager is responsible for the negotiation of the parameters and actually fallback to SCO if no agreement can be reached. In cases where the link manager is just too stupid, then at least try to establish a SCO link if eSCO fails. For the Bluetooth devices with EDR support this includes handling packet types of EDR basebands. This is particular tricky since for the EDR the logic of enabling/disabling one specific packet type is turned around. This fix contains an extra bitmask to disable eSCO EDR packet when trying to fallback to a SCO connection. Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
255c76014a
commit
efc7688b55
3 changed files with 31 additions and 2 deletions
|
@ -133,8 +133,13 @@ enum {
|
|||
#define ESCO_EV3 0x0008
|
||||
#define ESCO_EV4 0x0010
|
||||
#define ESCO_EV5 0x0020
|
||||
#define ESCO_2EV3 0x0040
|
||||
#define ESCO_3EV3 0x0080
|
||||
#define ESCO_2EV5 0x0100
|
||||
#define ESCO_3EV5 0x0200
|
||||
|
||||
#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)
|
||||
#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5)
|
||||
|
||||
/* ACL flags */
|
||||
#define ACL_CONT 0x01
|
||||
|
@ -176,6 +181,9 @@ enum {
|
|||
#define LMP_EV5 0x02
|
||||
|
||||
#define LMP_SNIFF_SUBR 0x02
|
||||
#define LMP_EDR_ESCO_2M 0x20
|
||||
#define LMP_EDR_ESCO_3M 0x40
|
||||
#define LMP_EDR_3S_ESCO 0x80
|
||||
|
||||
#define LMP_SIMPLE_PAIR 0x08
|
||||
|
||||
|
|
|
@ -123,6 +123,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
|
|||
conn->state = BT_CONNECT;
|
||||
conn->out = 1;
|
||||
|
||||
conn->attempt++;
|
||||
|
||||
cp.handle = cpu_to_le16(handle);
|
||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
||||
|
||||
|
@ -139,6 +141,8 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
|
|||
conn->state = BT_CONNECT;
|
||||
conn->out = 1;
|
||||
|
||||
conn->attempt++;
|
||||
|
||||
cp.handle = cpu_to_le16(handle);
|
||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
||||
|
||||
|
@ -216,12 +220,13 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
|
|||
break;
|
||||
case SCO_LINK:
|
||||
if (lmp_esco_capable(hdev))
|
||||
conn->pkt_type = hdev->esco_type & SCO_ESCO_MASK;
|
||||
conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
|
||||
(hdev->esco_type & EDR_ESCO_MASK);
|
||||
else
|
||||
conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
|
||||
break;
|
||||
case ESCO_LINK:
|
||||
conn->pkt_type = hdev->esco_type;
|
||||
conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -484,6 +484,15 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
|
|||
if (hdev->features[4] & LMP_EV5)
|
||||
hdev->esco_type |= (ESCO_EV5);
|
||||
|
||||
if (hdev->features[5] & LMP_EDR_ESCO_2M)
|
||||
hdev->esco_type |= (ESCO_2EV3);
|
||||
|
||||
if (hdev->features[5] & LMP_EDR_ESCO_3M)
|
||||
hdev->esco_type |= (ESCO_3EV3);
|
||||
|
||||
if (hdev->features[5] & LMP_EDR_3S_ESCO)
|
||||
hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
|
||||
|
||||
BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
|
||||
hdev->features[0], hdev->features[1],
|
||||
hdev->features[2], hdev->features[3],
|
||||
|
@ -1639,6 +1648,13 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
|
|||
conn->type = SCO_LINK;
|
||||
}
|
||||
|
||||
if (conn->out && ev->status == 0x1c && conn->attempt < 2) {
|
||||
conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
|
||||
(hdev->esco_type & EDR_ESCO_MASK);
|
||||
hci_setup_sync(conn, conn->link->handle);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!ev->status) {
|
||||
conn->handle = __le16_to_cpu(ev->handle);
|
||||
conn->state = BT_CONNECTED;
|
||||
|
|
Loading…
Reference in a new issue