summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Yen <howardyen@google.com>2022-07-19 16:48:59 +0000
committerHoward Yen <howardyen@google.com>2022-09-06 02:40:20 +0000
commite2ee93f8b6eab345632bb23d2df8fb2f68d8cb5d (patch)
treee1ba9ad19db3fcfb077412000b7ab64cd84631f9
parentb671a009819386044208eb2e7a6be8103ff97448 (diff)
downloadaoc-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.h15
-rw-r--r--usb/aoc_usb_dev.c33
-rw-r--r--usb/snd_usb_audio_hook_impl_whi.c39
-rw-r--r--usb/xhci_hooks_impl_whi.c15
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