summaryrefslogtreecommitdiff
path: root/drivers/bluetooth/btusb.c
diff options
context:
space:
mode:
authorChris Lu <chris.lu@mediatek.com>2024-07-04 09:01:16 +0300
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>2024-07-15 17:11:52 +0300
commitceac1cb0259de682d78f5c784ef8e0b13022e9d9 (patch)
tree5447e1c258998915e43a1ac9f06fec9be29da6e2 /drivers/bluetooth/btusb.c
parent6dc22ab9f085ae165e4ce89d61fb426f94e8a969 (diff)
downloadlinux-ceac1cb0259de682d78f5c784ef8e0b13022e9d9.tar.xz
Bluetooth: btusb: mediatek: add ISO data transmission functions
This patch implements functions for ISO data send and receive in btusb driver for MediaTek's controller. MediaTek defines a specific interrupt endpoint for ISO data transmissin because the characteristics of interrupt endpoint are similar to the application of ISO data which can support guaranteed transmissin bandwidth, enough maximum data length and error checking mechanism. Driver sets up ISO interface and endpoints in btusb_mtk_setup and clears the setup in btusb_mtk_shutdown. These flow can't move to btmtk.c due to btusb_driver is only defined in btusb.c when claiming/relaesing interface. ISO packet anchor stops when driver suspending and resubmit interrupt urb for ISO data when driver resuming. Signed-off-by: Chris Lu <chris.lu@mediatek.com> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
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) {