diff -urN tmp/linux-2.6.18/include/net/bluetooth/bluetooth.h linux-2.6.18/include/net/bluetooth/bluetooth.h --- tmp/linux-2.6.18/include/net/bluetooth/bluetooth.h 2006-09-20 09:12:06.000000000 +0530 +++ linux-2.6.18/include/net/bluetooth/bluetooth.h 2007-09-20 21:14:06.000000000 +0530 @@ -53,6 +53,23 @@ #define SOL_SCO 17 #define SOL_RFCOMM 18 +#if 0 +/* Debugging */ +#define CONFIG_BT_BLUEZ_DEBUG + +#ifdef CONFIG_BT_BLUEZ_DEBUG +#define CONFIG_BT_SOCK_DEBUG 1 +#define CONFIG_BT_HCI_CORE_DEBUG 1 +#define CONFIG_BT_HCI_SOCK_DEBUG 1 +#define CONFIG_BT_RFCOMM_DEBUG 1 +#define CONFIG_BT_L2CAP_DEBUG 1 +#define CONFIG_BT_SCO_DEBUG 1 + +#define CONFIG_BT_HCIUART_DEBUG 1 +#define CONFIG_BT_HCIVHCI_DEBUG 1 +#endif /* CONFIG_BT_BLUEZ_DEBUG */ +#endif + #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg) #define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __FUNCTION__ , ## arg) #define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __FUNCTION__ , ## arg) diff -urN tmp/linux-2.6.18/include/net/bluetooth/hci_core.h linux-2.6.18/include/net/bluetooth/hci_core.h --- tmp/linux-2.6.18/include/net/bluetooth/hci_core.h 2006-09-20 09:12:06.000000000 +0530 +++ linux-2.6.18/include/net/bluetooth/hci_core.h 2007-11-19 21:56:06.000000000 +0530 @@ -75,6 +75,7 @@ __u16 voice_setting; __u16 pkt_type; + __u16 esco_pkt_type; __u16 link_policy; __u16 link_mode; @@ -413,6 +414,8 @@ int hci_register_sysfs(struct hci_dev *hdev); void hci_unregister_sysfs(struct hci_dev *hdev); + + #define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev)) /* ----- LMP capabilities ----- */ @@ -420,6 +423,7 @@ #define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT) #define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF) #define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) +#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO) /* ----- HCI protocols ----- */ struct hci_proto { diff -urN tmp/linux-2.6.18/include/net/bluetooth/hci.h linux-2.6.18/include/net/bluetooth/hci.h --- tmp/linux-2.6.18/include/net/bluetooth/hci.h 2006-09-20 09:12:06.000000000 +0530 +++ linux-2.6.18/include/net/bluetooth/hci.h 2007-11-06 02:02:32.000000000 +0530 @@ -128,6 +128,19 @@ #define SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3) #define ACL_PTYPE_MASK (~SCO_PTYPE_MASK) +/* eSCO packet types */ +#define HCI_ESCO_HV1 0x0001 +#define HCI_ESCO_HV2 0x0002 +#define HCI_ESCO_HV3 0x0004 +#define HCI_ESCO_EV3 0x0008 +#define HCI_ESCO_EV4 0x0010 +#define HCI_ESCO_EV5 0x0020 + +/* Some devices seem to have trouble establishing EV* packet connections */ +/* with other devices. For this reason we mask out the eSCO packets */ +/* for now. Might need to address this later */ +#define ESCO_PTYPE_MASK (HCI_ESCO_HV1 | HCI_ESCO_HV2 | HCI_ESCO_HV3) + /* ACL flags */ #define ACL_CONT 0x01 #define ACL_START 0x02 @@ -137,6 +150,7 @@ /* Baseband links */ #define SCO_LINK 0x00 #define ACL_LINK 0x01 +#define ESCO_LINK 0x02 /* LMP features */ #define LMP_3SLOT 0x01 @@ -157,6 +171,11 @@ #define LMP_ULAW 0x40 #define LMP_ALAW 0x80 +/* eSCO support and packets */ +#define LMP_ESCO 0x80 +#define LMP_EV4 0x01 +#define LMP_EV5 0x02 + #define LMP_CVSD 0x01 #define LMP_PSCHEME 0x02 #define LMP_PCONTROL 0x04 @@ -312,12 +331,29 @@ __u8 role; } __attribute__ ((packed)); +#define OCF_ACCEPT_SYNC_CONN_REQ 0x0029 +struct hci_cp_accept_sync_conn_req { + bdaddr_t bdaddr; + __le32 tx_rate; + __le32 rx_rate; + __le16 max_latency; + __le16 voice_setting; + __u8 retrans_effort; + __le16 pkt_type; +} __attribute__((packed)); + #define OCF_REJECT_CONN_REQ 0x000a struct hci_cp_reject_conn_req { bdaddr_t bdaddr; __u8 reason; } __attribute__ ((packed)); +#define OCF_REJECT_SYNC_CONN_REQ 0x002a +struct hci_cp_reject_sync_conn_req { + bdaddr_t bdaddr; + __u8 reason; +} __attribute__ ((packed)); + #define OCF_DISCONNECT 0x0006 struct hci_cp_disconnect { __le16 handle; @@ -330,6 +366,17 @@ __le16 pkt_type; } __attribute__ ((packed)); +#define OCF_SETUP_SYNC_CONN 0x0028 +struct hci_cp_setup_sync_conn { + __le16 handle; + __le32 tx_rate; + __le32 rx_rate; + __le16 latency; + __le16 voice_setting; + __u8 retrans_effort; + __le16 pkt_type; +} __attribute__ ((packed)); + #define OCF_INQUIRY 0x0001 struct hci_cp_inquiry { __u8 lap[3]; @@ -516,6 +563,29 @@ __u8 encr_mode; } __attribute__ ((packed)); +#define HCI_EV_SYNC_CONN_COMPLETE 0x2C +struct hci_ev_sync_conn_complete { + __u8 status; + __le16 handle; + bdaddr_t bdaddr; + __u8 link_type; + __u8 trans_interval; + __u8 retrans_window; + __le16 rx_pkt_len; + __le16 tx_pkt_len; + __u8 air_mode; +} __attribute__ ((packed)); + +#define HCI_EV_SYNC_CONN_CHANGED 0x2D +struct hci_ev_sync_conn_changed { + __u8 status; + __le16 handle; + __u8 trans_interval; + __u8 retrans_window; + __le16 rx_pkt_len; + __le16 tx_pkt_len; +} __attribute__ ((packed)); + #define HCI_EV_CONN_REQUEST 0x04 struct hci_ev_conn_request { bdaddr_t bdaddr; diff -urN tmp/linux-2.6.18/net/bluetooth/hci_conn.c linux-2.6.18/net/bluetooth/hci_conn.c --- tmp/linux-2.6.18/net/bluetooth/hci_conn.c 2006-09-20 09:12:06.000000000 +0530 +++ linux-2.6.18/net/bluetooth/hci_conn.c 2007-11-19 22:00:17.000000000 +0530 @@ -100,17 +100,33 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) { struct hci_dev *hdev = conn->hdev; - struct hci_cp_add_sco cp; BT_DBG("%p", conn); conn->state = BT_CONNECT; conn->out = 1; - cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); - cp.handle = __cpu_to_le16(handle); + /* Devices that support 1.2 should be using the eSCO */ + /* commands. Add SCO commands were deprecated in 1.2 */ - hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, sizeof(cp), &cp); + if (lmp_esco_capable(hdev)) { + struct hci_cp_setup_sync_conn cp; + cp.handle = __cpu_to_le16(handle); + cp.tx_rate = __cpu_to_le32(0x1f40); + cp.rx_rate = __cpu_to_le32(0x1f40); + cp.latency = __cpu_to_le16(0xffff); + cp.voice_setting = __cpu_to_le16(hdev->voice_setting); + cp.retrans_effort = 0xff; + cp.pkt_type = __cpu_to_le16(hdev->esco_pkt_type & ESCO_PTYPE_MASK); + + hci_send_cmd(hdev, OGF_LINK_CTL, OCF_SETUP_SYNC_CONN, sizeof(cp), &cp); + } else { + struct hci_cp_add_sco cp; + cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); + cp.handle = __cpu_to_le16(handle); + + hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, sizeof(cp), &cp); + } } static void hci_conn_timeout(unsigned long arg) @@ -194,23 +210,25 @@ del_timer(&conn->disc_timer); - if (conn->type == SCO_LINK) { - struct hci_conn *acl = conn->link; - if (acl) { - acl->link = NULL; - hci_conn_put(acl); - } - } else { + if (conn->type == ACL_LINK) { struct hci_conn *sco = conn->link; if (sco) sco->link = NULL; /* Unacked frames */ 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); +// hci_conn_del_sysfs(conn); + hci_conn_hash_del(hdev, conn); if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); @@ -270,6 +288,7 @@ struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst) { struct hci_conn *acl; + struct hci_conn *sco; BT_DBG("%s dst %s", hdev->name, batostr(dst)); @@ -283,28 +302,25 @@ if (acl->state == BT_OPEN || acl->state == BT_CLOSED) hci_acl_connect(acl); - if (type == SCO_LINK) { - struct hci_conn *sco; + if (type == ACL_LINK) + return acl; - if (!(sco = hci_conn_hash_lookup_ba(hdev, SCO_LINK, dst))) { - if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) { - hci_conn_put(acl); - return NULL; - } + if (!(sco = hci_conn_hash_lookup_ba(hdev, type, dst))) { + if (!(sco = hci_conn_add(hdev, type, dst))) { + hci_conn_put(acl); + return NULL; } - acl->link = sco; - sco->link = acl; + } + acl->link = sco; + sco->link = acl; - hci_conn_hold(sco); + hci_conn_hold(sco); - if (acl->state == BT_CONNECTED && - (sco->state == BT_OPEN || sco->state == BT_CLOSED)) - hci_add_sco(sco, acl->handle); + if (acl->state == BT_CONNECTED && + (sco->state == BT_OPEN || sco->state == BT_CLOSED)) + hci_add_sco(sco, acl->handle); - return sco; - } else { - return acl; - } + return sco; } EXPORT_SYMBOL(hci_connect); diff -urN tmp/linux-2.6.18/net/bluetooth/hci_core.c linux-2.6.18/net/bluetooth/hci_core.c --- tmp/linux-2.6.18/net/bluetooth/hci_core.c 2006-09-20 09:12:06.000000000 +0530 +++ linux-2.6.18/net/bluetooth/hci_core.c 2008-01-29 01:01:32.000000000 +0530 @@ -848,6 +848,7 @@ hdev->flags = 0; hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); + hdev->esco_pkt_type = HCI_ESCO_HV1; hdev->link_mode = (HCI_LM_ACCEPT); hdev->idle_timeout = 0; @@ -1390,6 +1391,7 @@ /* Process frame */ switch (bt_cb(skb)->pkt_type) { case HCI_EVENT_PKT: + BT_DBG("%s HCI event packet", hdev->name); hci_event_packet(hdev, skb); break; @@ -1404,6 +1406,7 @@ break; default: + BT_DBG("%s Invalid packet", hdev->name); kfree_skb(skb); break; } diff -urN tmp/linux-2.6.18/net/bluetooth/hci_event.c linux-2.6.18/net/bluetooth/hci_event.c --- tmp/linux-2.6.18/net/bluetooth/hci_event.c 2006-09-20 09:12:06.000000000 +0530 +++ linux-2.6.18/net/bluetooth/hci_event.c 2008-01-29 01:02:54.000000000 +0530 @@ -322,13 +322,30 @@ if (hdev->features[0] & LMP_5SLOT) hdev->pkt_type |= (HCI_DM5 | HCI_DH5); - if (hdev->features[1] & LMP_HV2) - hdev->pkt_type |= (HCI_HV2); + if (hdev->features[1] & LMP_HV2) { + hdev->pkt_type |= HCI_HV2; + hdev->esco_pkt_type |= HCI_ESCO_HV2; + } + + if (hdev->features[1] & LMP_HV3) { + hdev->pkt_type |= HCI_HV3; + hdev->esco_pkt_type |= HCI_ESCO_HV3; + } + + if (hdev->features[3] & LMP_ESCO) + hdev->esco_pkt_type |= HCI_ESCO_EV3; + + if (hdev->features[4] & LMP_EV4) + hdev->esco_pkt_type |= HCI_ESCO_EV4; + + if (hdev->features[4] & LMP_EV5) + hdev->esco_pkt_type |= HCI_ESCO_EV5; + + BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, + lf->features[0], lf->features[1], lf->features[2]); - if (hdev->features[1] & LMP_HV3) - hdev->pkt_type |= (HCI_HV3); - BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]); + BT_DBG("%s: eSco packets: 0x%x", hdev->name, hdev->esco_pkt_type); break; @@ -412,40 +429,76 @@ hci_dev_unlock(hdev); } -static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) +static inline void hci_cs_add_sco(struct hci_dev *hdev, __u8 status) { - BT_DBG("%s ocf 0x%x", hdev->name, ocf); + struct hci_conn *acl, *sco; + struct hci_cp_add_sco *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_ADD_SCO); - switch (ocf) { - case OCF_CREATE_CONN: - hci_cs_create_conn(hdev, status); - break; + if (!cp) + return; - case OCF_ADD_SCO: - if (status) { - struct hci_conn *acl, *sco; - struct hci_cp_add_sco *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_ADD_SCO); - __u16 handle; + hci_dev_lock(hdev); - if (!cp) - break; + if (status) { + __u16 handle = __le16_to_cpu(cp->handle); - handle = __le16_to_cpu(cp->handle); + BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status); - BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status); + acl = hci_conn_hash_lookup_handle(hdev, handle); + if (acl && (sco = acl->link)) { + sco->state = BT_CLOSED; - hci_dev_lock(hdev); + hci_proto_connect_cfm(sco, status); + hci_conn_del(sco); + } + } - acl = hci_conn_hash_lookup_handle(hdev, handle); - if (acl && (sco = acl->link)) { - sco->state = BT_CLOSED; + hci_dev_unlock(hdev); +} - hci_proto_connect_cfm(sco, status); - hci_conn_del(sco); - } +static inline void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status) +{ + struct hci_conn *acl, *sco; + struct hci_cp_setup_sync_conn *cp = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_SETUP_SYNC_CONN); - hci_dev_unlock(hdev); + if (!cp) + return; + + hci_dev_lock(hdev); + + if (status) { + __u16 handle = __le16_to_cpu(cp->handle); + + BT_DBG("%s eSCO conn setup error: handle %d status 0x%x", + hdev->name, handle, status); + + acl = hci_conn_hash_lookup_handle(hdev, handle); + if (acl && (sco = acl->link)) { + sco->state = BT_CLOSED; + + hci_proto_connect_cfm(sco, status); + hci_conn_del(sco); } + } + + hci_dev_unlock(hdev); +} + +static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status) +{ + BT_DBG("%s ocf 0x%x", hdev->name, ocf); + + switch (ocf) { + case OCF_CREATE_CONN: + hci_cs_create_conn(hdev, status); + break; + + case OCF_ADD_SCO: + hci_cs_add_sco(hdev, status); + break; + + case OCF_SETUP_SYNC_CONN: + hci_cs_setup_sync_conn(hdev, status); break; case OCF_INQUIRY: @@ -669,7 +722,6 @@ if (mask & HCI_LM_ACCEPT) { /* Connection accepted */ struct hci_conn *conn; - struct hci_cp_accept_conn_req cp; hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); @@ -684,23 +736,51 @@ conn->state = BT_CONNECT; hci_dev_unlock(hdev); - bacpy(&cp.bdaddr, &ev->bdaddr); + if ((ev->link_type == ACL_LINK) || (!lmp_esco_capable(hdev))) { + struct hci_cp_accept_conn_req cp; + bacpy(&cp.bdaddr, &ev->bdaddr); - if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) - cp.role = 0x00; /* Become master */ - else - cp.role = 0x01; /* Remain slave */ + if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) + cp.role = 0x00; /* Become master */ + else + cp.role = 0x01; /* Remain slave */ - hci_send_cmd(hdev, OGF_LINK_CTL, - OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp); + hci_send_cmd(hdev, OGF_LINK_CTL, + OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp); + } else { + /* Send the Accept Sync Connection Command */ + struct hci_cp_accept_sync_conn_req cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); + cp.tx_rate = __cpu_to_le32(0x1f40); + cp.rx_rate = __cpu_to_le32(0x1f40); + cp.max_latency = __cpu_to_le16(0xffff); + cp.voice_setting = __cpu_to_le16(hdev->voice_setting); + cp.retrans_effort = 0xff; + cp.pkt_type = __cpu_to_le16(hdev->esco_pkt_type & ESCO_PTYPE_MASK); + + hci_send_cmd(hdev, OGF_LINK_CTL, + OCF_ACCEPT_SYNC_CONN_REQ, sizeof(cp), &cp); + } } else { /* Connection rejected */ - struct hci_cp_reject_conn_req cp; - bacpy(&cp.bdaddr, &ev->bdaddr); - cp.reason = 0x0f; - hci_send_cmd(hdev, OGF_LINK_CTL, - OCF_REJECT_CONN_REQ, sizeof(cp), &cp); + if ((ev->link_type == ACL_LINK) || (!lmp_esco_capable(hdev))) { + struct hci_cp_reject_conn_req cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); + cp.reason = 0x0f; + hci_send_cmd(hdev, OGF_LINK_CTL, + OCF_REJECT_CONN_REQ, sizeof(cp), &cp); + } else { + struct hci_cp_reject_sync_conn_req cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); + cp.reason = 0x0f; + + hci_send_cmd(hdev, OGF_LINK_CTL, + OCF_REJECT_SYNC_CONN_REQ, sizeof(cp), &cp); + } } } @@ -780,6 +860,57 @@ hci_dev_unlock(hdev); } +/* eSCO Connect Complete */ +static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_sync_conn_complete *ev = (struct hci_ev_sync_conn_complete *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + /* There are two possibilities here. We establish an outgoing ESCO link and get */ + /* back a SCO link. Or we got a connect request with a SCO/ESCO link type and */ + /* arrived here once it was established */ + conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr); + if (!conn) { + /* Incoming SCO case */ + conn = hci_conn_hash_lookup_ba(hdev, SCO_LINK, &ev->bdaddr); + if (!conn) { + hci_dev_unlock(hdev); + return; + } + + if (conn->out) { + BT_DBG("ended up with a SCO link"); + hci_conn_del(conn); + hci_dev_unlock(hdev); + return; + } + } + + if (!ev->status) { + conn->handle = __le16_to_cpu(ev->handle); + conn->type = ev->link_type; + conn->state = BT_CONNECTED; + + if (conn->out) { + /* Update disconnect timer */ + hci_conn_hold(conn); + hci_conn_put(conn); + } + } else + conn->state = BT_CLOSED; + + hci_proto_connect_cfm(conn, ev->status); + if (ev->status) + hci_conn_del(conn); + + hci_dev_unlock(hdev); +} + + /* Disconnect Complete */ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { @@ -832,12 +963,12 @@ if (conn) { conn->sent -= count; - if (conn->type == SCO_LINK) { - if ((hdev->sco_cnt += count) > hdev->sco_pkts) - hdev->sco_cnt = hdev->sco_pkts; - } else { + if (conn->type == ACL_LINK) { if ((hdev->acl_cnt += count) > hdev->acl_pkts) hdev->acl_cnt = hdev->acl_pkts; + } else { + if ((hdev->sco_cnt += count) > hdev->sco_pkts) + hdev->sco_cnt = hdev->sco_pkts; } } } @@ -1116,6 +1247,10 @@ hci_conn_complete_evt(hdev, skb); break; + case HCI_EV_SYNC_CONN_COMPLETE: + hci_sync_conn_complete_evt(hdev, skb); + break; + case HCI_EV_DISCONN_COMPLETE: hci_disconn_complete_evt(hdev, skb); break; diff -urN tmp/linux-2.6.18/net/bluetooth/sco.c linux-2.6.18/net/bluetooth/sco.c --- tmp/linux-2.6.18/net/bluetooth/sco.c 2006-09-20 09:12:06.000000000 +0530 +++ linux-2.6.18/net/bluetooth/sco.c 2007-11-06 19:55:38.000000000 +0530 @@ -189,7 +189,7 @@ struct sco_conn *conn; struct hci_conn *hcon; struct hci_dev *hdev; - int err = 0; + int err, type; BT_DBG("%s -> %s", batostr(src), batostr(dst)); @@ -200,7 +200,9 @@ err = -ENOMEM; - hcon = hci_connect(hdev, SCO_LINK, dst); + type = lmp_esco_capable(hdev) ? ESCO_LINK : SCO_LINK; + + hcon = hci_connect(hdev, type, dst); if (!hcon) goto done; @@ -837,6 +839,9 @@ { BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); + if (type != SCO_LINK && type != ESCO_LINK) + return 0; + /* Always accept connection */ return HCI_LM_ACCEPT; } @@ -845,7 +850,7 @@ { BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); - if (hcon->type != SCO_LINK) + if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) return 0; if (!status) { @@ -864,7 +869,7 @@ { BT_DBG("hcon %p reason %d", hcon, reason); - if (hcon->type != SCO_LINK) + if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) return 0; sco_conn_del(hcon, bt_err(reason));