diff options
author | Howard Yen <howardyen@google.com> | 2022-07-19 16:48:59 +0000 |
---|---|---|
committer | Howard Yen <howardyen@google.com> | 2022-09-06 02:40:20 +0000 |
commit | e2ee93f8b6eab345632bb23d2df8fb2f68d8cb5d (patch) | |
tree | e1ba9ad19db3fcfb077412000b7ab64cd84631f9 | |
parent | b671a009819386044208eb2e7a6be8103ff97448 (diff) | |
download | aoc-e2ee93f8b6eab345632bb23d2df8fb2f68d8cb5d.tar.gz |
aoc: usb: send feedback endpoint information to AoC
Send feedback endpoint information to AoC for supporting
Asynchronization mode playback.
Bug: 228418729
Test: build and boot pass
Change-Id: Id50954e834ebd93045fd4584575b7bce20f5db7c
Signed-off-by: Howard Yen <howardyen@google.com>
-rw-r--r-- | usb/aoc_usb.h | 15 | ||||
-rw-r--r-- | usb/aoc_usb_dev.c | 33 | ||||
-rw-r--r-- | usb/snd_usb_audio_hook_impl_whi.c | 39 | ||||
-rw-r--r-- | usb/xhci_hooks_impl_whi.c | 15 |
4 files changed, 101 insertions, 1 deletions
diff --git a/usb/aoc_usb.h b/usb/aoc_usb.h index bc81f41..3c65a0c 100644 --- a/usb/aoc_usb.h +++ b/usb/aoc_usb.h @@ -29,7 +29,8 @@ enum aoc_usb_msg { GET_ISOC_TR_INFO, SET_ISOC_TR_INFO, SYNC_CONN_STAT, - SET_OFFLOAD_STATE + SET_OFFLOAD_STATE, + SEND_FB_EP_INFO }; enum aoc_usb_state { @@ -115,6 +116,17 @@ struct get_isoc_tr_info_args { u32 num_trbs_free; }; +struct feedback_ep_info_args { + bool enabled; + u16 bus_id; + u16 dev_num; + u16 slot_id; + u16 ep_num; + u32 max_packet; + u16 binterval; + u16 brefresh; +}; + int xhci_vendor_helper_init(void); int usb_vendor_helper_init(void); int snd_usb_audio_vendor_helper_init(void); @@ -123,6 +135,7 @@ extern int xhci_handle_event(struct xhci_hcd *xhci); extern void xhci_update_erst_dequeue(struct xhci_hcd *xhci, union xhci_trb *event_ring_deq); extern int xhci_exynos_register_vendor_ops(struct xhci_vendor_ops *vendor_ops); +int xhci_send_feedback_ep_info(struct xhci_hcd *xhci, struct feedback_ep_info_args *cmd_args); int xhci_get_usb_audio_count(struct xhci_hcd *xhci); int xhci_set_offload_state(struct xhci_hcd *xhci, bool enabled); struct xhci_hcd *get_xhci_hcd_by_udev(struct usb_device *udev); diff --git a/usb/aoc_usb_dev.c b/usb/aoc_usb_dev.c index 0b62c02..66fa966 100644 --- a/usb/aoc_usb_dev.c +++ b/usb/aoc_usb_dev.c @@ -315,6 +315,36 @@ static int aoc_usb_set_offload_state(struct aoc_usb_drvdata *drvdata, bool *enab return 0; } +static int aoc_usb_send_feedback_ep_info(struct aoc_usb_drvdata *drvdata, void *args) +{ + int ret = 0; + struct feedback_ep_info_args *fb_ep_info_args = + (struct feedback_ep_info_args *)args; + struct CMD_USB_CONTROL_SEND_FEEDBACK_EP_INFO *cmd; + + cmd = kzalloc(sizeof(struct CMD_USB_CONTROL_SEND_FEEDBACK_EP_INFO), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + AocCmdHdrSet(&cmd->parent, + CMD_USB_CONTROL_SEND_FEEDBACK_EP_INFO_ID, + sizeof(*cmd)); + + cmd->enabled = fb_ep_info_args->enabled; + cmd->bus_id = fb_ep_info_args->bus_id; + cmd->dev_num = fb_ep_info_args->dev_num; + cmd->slot_id = fb_ep_info_args->slot_id; + cmd->ep_num = fb_ep_info_args->ep_num; + cmd->max_packet = fb_ep_info_args->max_packet; + cmd->binterval = fb_ep_info_args->binterval; + cmd->brefresh = fb_ep_info_args->brefresh; + ret = aoc_usb_send_command(drvdata, cmd, sizeof(*cmd), cmd, sizeof(*cmd)); + + kfree(cmd); + + return ret; +} + static int aoc_usb_notify(struct notifier_block *this, unsigned long code, void *data) { @@ -351,6 +381,9 @@ static int aoc_usb_notify(struct notifier_block *this, case SET_OFFLOAD_STATE: ret = aoc_usb_set_offload_state(drvdata, data); break; + case SEND_FB_EP_INFO: + ret = aoc_usb_send_feedback_ep_info(drvdata, data); + break; default: dev_warn(&drvdata->adev->dev, "Code %lu is not supported\n", code); ret = -EINVAL; diff --git a/usb/snd_usb_audio_hook_impl_whi.c b/usb/snd_usb_audio_hook_impl_whi.c index 370caf5..56d0080 100644 --- a/usb/snd_usb_audio_hook_impl_whi.c +++ b/usb/snd_usb_audio_hook_impl_whi.c @@ -74,16 +74,55 @@ static int snd_usb_audio_vendor_set_pcm_intf(struct usb_interface *intf, int ifa struct usb_device *udev; struct xhci_hcd *xhci; struct xhci_vendor_data *vendor_data; + struct usb_host_interface *cur_alt; + struct feedback_ep_info_args cmd_args; + int i; if (!intf) { pr_err("%s: Invalid parameter\n", __func__); return 0; } + cur_alt = intf->cur_altsetting; udev = interface_to_usbdev(intf); xhci = get_xhci_hcd_by_udev(udev); vendor_data = xhci_to_priv(xhci)->vendor_data; + if (alt != 0 && cur_alt->desc.bNumEndpoints == 0) + dev_warn(&intf->dev, "Set PCM intf without endpoint\n"); + + for (i = 0; i < cur_alt->desc.bNumEndpoints; i++) { + const struct usb_endpoint_descriptor *epd = &cur_alt->endpoint[i].desc; + + dev_dbg(&intf->dev, "EP[%d], bLength=%u, bDescriptorType=%u, bEndpointAddress=%u, bmAttributes=0%x, wMaxPacketSize=%u, bInterval=%u, bRefresh=%u, bSynchAddress=%u\n", + i, epd->bLength, epd->bDescriptorType, epd->bEndpointAddress, + epd->bmAttributes, epd->wMaxPacketSize, epd->bInterval, + epd->bRefresh, epd->bSynchAddress); + + /** + * By below condition, we consider the endpoint is an feedback endpoint, + * 1. Its type is isoc. + * 2. Its sync type is none or async. (it should be none, add async for compaibility) + * 3. wMaxPacketSize <= 8, the max feedback data size is 4, reserve 8 for the future. + */ + if (usb_endpoint_type(epd) == USB_ENDPOINT_XFER_ISOC && usb_endpoint_dir_in(epd) && + ((epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) == USB_ENDPOINT_SYNC_ASYNC || + (epd->bmAttributes & USB_ENDPOINT_SYNCTYPE) == USB_ENDPOINT_SYNC_NONE) && + epd->wMaxPacketSize <= 8) { + + cmd_args.enabled = (alt != 0) ? true : false; + cmd_args.bus_id = udev->bus->busnum; + cmd_args.dev_num = udev->devnum; + cmd_args.slot_id = udev->slot_id; + cmd_args.ep_num = usb_endpoint_num(epd); + cmd_args.max_packet = epd->wMaxPacketSize; + cmd_args.binterval = epd->bInterval; + cmd_args.brefresh = epd->bRefresh; + + xhci_send_feedback_ep_info(xhci, &cmd_args); + } + } + if (vendor_data->offload_state) { xhci_dbg(xhci, "offloading is enabled\n"); return 0; diff --git a/usb/xhci_hooks_impl_whi.c b/usb/xhci_hooks_impl_whi.c index 29c57a8..2743feb 100644 --- a/usb/xhci_hooks_impl_whi.c +++ b/usb/xhci_hooks_impl_whi.c @@ -37,6 +37,21 @@ int unregister_aoc_usb_notifier(struct notifier_block *nb) return blocking_notifier_chain_unregister(&aoc_usb_notifier_list, nb); } +int xhci_send_feedback_ep_info(struct xhci_hcd *xhci, struct feedback_ep_info_args *cmd_args) +{ + if (!xhci || !cmd_args) + return -EINVAL; + + xhci_dbg(xhci, "Send feedback EP info, Num = %u, Max packet size = %u, bInterval = %u, bRefresh = %u", + cmd_args->ep_num, cmd_args->max_packet, + cmd_args->binterval, cmd_args->brefresh); + + blocking_notifier_call_chain(&aoc_usb_notifier_list, SEND_FB_EP_INFO, + cmd_args); + + return 0; +} + /* * If the Host connected to a hub, user may connect more than two USB audio * headsets or DACs. A caller can call this function to know how many USB |