summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPuma Hsu <pumahsu@google.com>2023-03-12 21:00:31 +0800
committerWill McVicker <willmcvicker@google.com>2024-04-16 11:11:10 -0700
commit5e07db824466e0a379376e3c1ca1f6afe49191d6 (patch)
treef01e46699009c6134b437c0e9df38c9fc5ba8497
parentd18eebd9c3e69b401c710914c74e385abb3343d7 (diff)
downloadaoc-5e07db824466e0a379376e3c1ca1f6afe49191d6.tar.gz
aoc: usb: deliver transfer ring address to AOC
The transfer ring is allocated when the sound driver is going to use USB interface, and xhci needs to deliver the ring address to the AOC. So we register a callback and then sound driver can tell xhci driver to send the address to the AOC. Bug: 226259959 Test: USB audio works Change-Id: I9e7b63a9f56f905d43383c844a29ff3cb175eae1 Signed-off-by: Puma Hsu <pumahsu@google.com>
-rw-r--r--usb/aoc_usb.h4
-rw-r--r--usb/xhci_hooks_impl_whi.c57
2 files changed, 61 insertions, 0 deletions
diff --git a/usb/aoc_usb.h b/usb/aoc_usb.h
index 4df4a91..c5c2306 100644
--- a/usb/aoc_usb.h
+++ b/usb/aoc_usb.h
@@ -70,6 +70,10 @@ struct get_isoc_tr_info_args {
int register_aoc_usb_notifier(struct notifier_block *nb);
int unregister_aoc_usb_notifier(struct notifier_block *nb);
+extern bool aoc_alsa_usb_callback_register(void (*callback)(struct usb_device*,
+ struct usb_host_endpoint*));
+extern bool aoc_alsa_usb_callback_unregister(void);
+
int notify_offload_state(bool enabled);
int xhci_set_dcbaa_ptr(u64 aoc_dcbaa_ptr);
int xhci_setup_done(void);
diff --git a/usb/xhci_hooks_impl_whi.c b/usb/xhci_hooks_impl_whi.c
index 7f19d13..f863d9f 100644
--- a/usb/xhci_hooks_impl_whi.c
+++ b/usb/xhci_hooks_impl_whi.c
@@ -26,6 +26,32 @@ struct xhci_offload_data *xhci_get_offload_data(void)
return offload_data;
}
+static struct xhci_hcd *get_xhci_hcd_by_udev(struct usb_device *udev)
+{
+ struct usb_hcd *uhcd = container_of(udev->bus, struct usb_hcd, self);
+
+ return hcd_to_xhci(uhcd);
+}
+
+static u32 xhci_get_endpoint_type(struct usb_host_endpoint *ep)
+{
+ int in;
+
+ in = usb_endpoint_dir_in(&ep->desc);
+
+ switch (usb_endpoint_type(&ep->desc)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ return CTRL_EP;
+ case USB_ENDPOINT_XFER_BULK:
+ return in ? BULK_IN_EP : BULK_OUT_EP;
+ case USB_ENDPOINT_XFER_ISOC:
+ return in ? ISOC_IN_EP : ISOC_OUT_EP;
+ case USB_ENDPOINT_XFER_INT:
+ return in ? INT_IN_EP : INT_OUT_EP;
+ }
+ return 0;
+}
+
/*
* Determine if an USB device is a compatible devices:
* True: Devices are audio class and they contain ISOC endpoint
@@ -68,6 +94,35 @@ out:
return is_audio;
}
+static void setup_transfer_ring(struct usb_device *udev, struct usb_host_endpoint *ep)
+{
+ struct xhci_hcd *xhci = get_xhci_hcd_by_udev(udev);
+ struct xhci_virt_device *virt_dev;
+ unsigned int ep_index;
+ u32 endpoint_type;
+ u16 dir;
+
+ ep_index = xhci_get_endpoint_index(&ep->desc);
+ endpoint_type = xhci_get_endpoint_type(ep);
+ dir = endpoint_type == ISOC_IN_EP ? 0 : 1;
+
+ virt_dev = xhci->devs[udev->slot_id];
+ if (!virt_dev) {
+ xhci_err(xhci, "%s: virt_dev not found!\n", __func__);
+ return;
+ }
+
+ if (virt_dev->eps[ep_index].new_ring) {
+ xhci_info(xhci, "%s: deliver transfer ring from new_ring\n", __func__);
+ xhci_set_isoc_tr_info(0, dir, virt_dev->eps[ep_index].new_ring);
+ } else if (virt_dev->eps[ep_index].ring) {
+ xhci_info(xhci, "%s: deliver transfer ring from ring\n", __func__);
+ xhci_set_isoc_tr_info(0, dir, virt_dev->eps[ep_index].ring);
+ } else {
+ xhci_err(xhci, "%s: transfer ring not found!\n", __func__);
+ }
+}
+
static int xhci_udev_notify(struct notifier_block *self, unsigned long action,
void *dev)
{
@@ -132,6 +187,7 @@ static int usb_audio_offload_init(struct xhci_hcd *xhci)
offload_data->offload_state = true;
+ aoc_alsa_usb_callback_register(setup_transfer_ring);
usb_register_notify(&xhci_udev_nb);
offload_data->op_mode = USB_OFFLOAD_DRAM;
offload_data->xhci = xhci;
@@ -156,6 +212,7 @@ static void usb_audio_offload_cleanup(struct xhci_hcd *xhci)
offload_data->op_mode = USB_OFFLOAD_STOP;
offload_data->xhci = NULL;
+ aoc_alsa_usb_callback_unregister();
usb_unregister_notify(&xhci_udev_nb);
/* Notification for xhci driver removing */