diff options
Diffstat (limited to 'drivers/bluetooth/btusb.c')
| -rw-r--r-- | drivers/bluetooth/btusb.c | 68 |
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) { |
