summaryrefslogtreecommitdiff
path: root/drivers/bluetooth/btusb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth/btusb.c')
-rw-r--r--drivers/bluetooth/btusb.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 034256c399dd..3077f16a149d 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -2645,6 +2645,40 @@ static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
return hci_recv_frame(hdev, skb);
}
+static void btusb_mtk_claim_iso_intf(struct btusb_data *data)
+{
+ struct btmtk_data *btmtk_data = hci_get_priv(data->hdev);
+ int err;
+
+ err = usb_driver_claim_interface(&btusb_driver,
+ btmtk_data->isopkt_intf, data);
+ if (err < 0) {
+ btmtk_data->isopkt_intf = NULL;
+ bt_dev_err(data->hdev, "Failed to claim iso interface");
+ return;
+ }
+
+ set_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags);
+}
+
+static void btusb_mtk_release_iso_intf(struct btusb_data *data)
+{
+ struct btmtk_data *btmtk_data = hci_get_priv(data->hdev);
+
+ if (btmtk_data->isopkt_intf) {
+ usb_kill_anchored_urbs(&btmtk_data->isopkt_anchor);
+ clear_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags);
+
+ dev_kfree_skb_irq(btmtk_data->isopkt_skb);
+ btmtk_data->isopkt_skb = NULL;
+ usb_set_intfdata(btmtk_data->isopkt_intf, NULL);
+ usb_driver_release_interface(&btusb_driver,
+ btmtk_data->isopkt_intf);
+ }
+
+ clear_bit(BTMTK_ISOPKT_OVER_INTR, &btmtk_data->flags);
+}
+
static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
{
struct btusb_data *data = hci_get_drvdata(hdev);
@@ -2661,6 +2695,9 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
if (err < 0)
return err;
+ if (test_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags))
+ btusb_mtk_release_iso_intf(data);
+
btusb_stop_traffic(data);
usb_kill_anchored_urbs(&data->tx_anchor);
@@ -2672,6 +2709,23 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data)
return err;
}
+static int btusb_send_frame_mtk(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct urb *urb;
+
+ BT_DBG("%s", hdev->name);
+
+ if (hci_skb_pkt_type(skb) == HCI_ISODATA_PKT) {
+ urb = alloc_mtk_intr_urb(hdev, skb, btusb_tx_complete);
+ if (IS_ERR(urb))
+ return PTR_ERR(urb);
+
+ return submit_or_queue_tx_urb(hdev, urb);
+ } else {
+ return btusb_send_frame(hdev, skb);
+ }
+}
+
static int btusb_mtk_setup(struct hci_dev *hdev)
{
struct btusb_data *data = hci_get_drvdata(hdev);
@@ -2686,11 +2740,22 @@ static int btusb_mtk_setup(struct hci_dev *hdev)
btmtk_data->ctrl_anchor = &data->ctrl_anchor;
btmtk_data->reset_sync = btusb_mtk_reset;
+ /* Claim ISO data interface and endpoint */
+ btmtk_data->isopkt_intf = usb_ifnum_to_if(data->udev, MTK_ISO_IFNUM);
+ if (btmtk_data->isopkt_intf)
+ btusb_mtk_claim_iso_intf(data);
+
return btmtk_usb_setup(hdev);
}
static int btusb_mtk_shutdown(struct hci_dev *hdev)
{
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ struct btmtk_data *btmtk_data = hci_get_priv(hdev);
+
+ if (test_bit(BTMTK_ISOPKT_RUNNING, &btmtk_data->flags))
+ btusb_mtk_release_iso_intf(data);
+
return btmtk_usb_shutdown(hdev);
}
@@ -3797,9 +3862,12 @@ static int btusb_probe(struct usb_interface *intf,
hdev->manufacturer = 70;
hdev->cmd_timeout = btmtk_reset_sync;
hdev->set_bdaddr = btmtk_set_bdaddr;
+ hdev->send = btusb_send_frame_mtk;
set_bit(HCI_QUIRK_BROKEN_ENHANCED_SETUP_SYNC_CONN, &hdev->quirks);
set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
data->recv_acl = btmtk_usb_recv_acl;
+ data->suspend = btmtk_usb_suspend;
+ data->resume = btmtk_usb_resume;
}
if (id->driver_info & BTUSB_SWAVE) {