diff options
author | Howard Yen <howardyen@google.com> | 2022-01-14 15:52:47 +0800 |
---|---|---|
committer | TreeHugger Robot <treehugger-gerrit@google.com> | 2022-02-17 02:19:46 +0000 |
commit | 32b45e2e08bcb3b6306ec9796d1f50ef44d0d514 (patch) | |
tree | 4090c77fa783bea907bbc3296444a4ffe7af980b | |
parent | 751036690ecd31bd8854638966b9d585ded74bbd (diff) | |
download | aoc-android-gs-raviole-5.10-s-qpr3-beta-2.tar.gz |
aoc: usb: support direct USB accessandroid-s-qpr3-beta-2_r0.5android-s-qpr3-beta-1_r0.6android-gs-raviole-5.10-s-qpr3-beta-2
Support direct USB access to allow APP to access external USB DAC
directly for extending the hi-res USB audio and format support.
Bug: 199034378
Test: build and boot pass
Change-Id: Ib20d2e1a30ef5e0ee01b652cbd033242f84203a7
Signed-off-by: Howard Yen <howardyen@google.com>
-rw-r--r-- | usb/Makefile | 6 | ||||
-rw-r--r-- | usb/aoc_usb.h | 8 | ||||
-rw-r--r-- | usb/aoc_usb_dev.c | 33 | ||||
-rw-r--r-- | usb/snd_usb_audio_hook_impl_whi.c | 110 | ||||
-rw-r--r-- | usb/xhci_hooks_impl_whi.c | 32 |
5 files changed, 183 insertions, 6 deletions
diff --git a/usb/Makefile b/usb/Makefile index 22c117c..5fb6eb9 100644 --- a/usb/Makefile +++ b/usb/Makefile @@ -2,14 +2,14 @@ # ASoC-based USB driver # obj-$(CONFIG_AOC_DRIVER) += aoc_usb_driver.o -aoc_usb_driver-objs := aoc_usb_dev.o xhci_hooks_impl_whi.o usb_hooks_impl_whi.o +aoc_usb_driver-objs := aoc_usb_dev.o xhci_hooks_impl_whi.o usb_hooks_impl_whi.o snd_usb_audio_hook_impl_whi.o KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build M ?= $(shell pwd) KBUILD_OPTIONS += CONFIG_AOC_DRIVER=m -EXTRA_CFLAGS=-I$(KERNEL_SRC)/../google-modules/aoc_ipc -I$(KERNEL_SRC)/../google-modules/aoc -I$(KERNEL_SRC)/drivers/usb/host +EXTRA_CFLAGS=-I$(KERNEL_SRC)/../google-modules/aoc_ipc -I$(KERNEL_SRC)/../google-modules/aoc -I$(KERNEL_SRC)/drivers/usb/host -I$(KERNEL_SRC)/sound/usb KBUILD_EXTRA_SYMBOLS=$(OUT_DIR)/../google-modules/aoc/Module.symvers\ $(OUT_DIR)/../google-modules/aoc/alsa/Module.symvers modules modules_install clean: - $(MAKE) -C $(KERNEL_SRC) M=$(M) W=1 -Werror $(KBUILD_OPTIONS) EXTRA_CFLAGS="$(EXTRA_CFLAGS)" KBUILD_EXTRA_SYMBOLS="$(KBUILD_EXTRA_SYMBOLS)" $(@) + $(MAKE) -C $(KERNEL_SRC) M=$(M) W=1 $(KBUILD_OPTIONS) EXTRA_CFLAGS="$(EXTRA_CFLAGS)" KBUILD_EXTRA_SYMBOLS="$(KBUILD_EXTRA_SYMBOLS)" $(@) diff --git a/usb/aoc_usb.h b/usb/aoc_usb.h index 852f7aa..1787a33 100644 --- a/usb/aoc_usb.h +++ b/usb/aoc_usb.h @@ -28,7 +28,8 @@ enum aoc_usb_msg { SETUP_DONE, GET_ISOC_TR_INFO, SET_ISOC_TR_INFO, - SYNC_CONN_STAT + SYNC_CONN_STAT, + SET_OFFLOAD_STATE }; enum aoc_usb_state { @@ -64,6 +65,8 @@ struct xhci_vendor_data { bool usb_accessory_enabled; bool usb_audio_offload; + bool dt_direct_usb_access; + bool offload_state; enum usb_offload_op_mode op_mode; @@ -111,11 +114,14 @@ struct get_isoc_tr_info_args { int xhci_vendor_helper_init(void); int usb_vendor_helper_init(void); +int snd_usb_audio_vendor_helper_init(void); 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_set_offload_state(struct xhci_hcd *xhci, bool enabled); +struct xhci_hcd *get_xhci_hcd_by_udev(struct usb_device *udev); int usb_host_mode_state_notify(enum aoc_usb_state usb_state); diff --git a/usb/aoc_usb_dev.c b/usb/aoc_usb_dev.c index 97693db..2af8e8d 100644 --- a/usb/aoc_usb_dev.c +++ b/usb/aoc_usb_dev.c @@ -293,6 +293,31 @@ static int aoc_usb_set_isoc_tr_info(struct aoc_usb_drvdata *drvdata, void *args) return 0; } +static int aoc_usb_set_offload_state(struct aoc_usb_drvdata *drvdata, bool *enabled) +{ + int ret = 0; + struct CMD_USB_CONTROL_SET_OFFLOAD_STATE *cmd; + + cmd = kzalloc(sizeof(struct CMD_USB_CONTROL_SET_OFFLOAD_STATE), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + AocCmdHdrSet(&cmd->parent, + CMD_USB_CONTROL_SET_OFFLOAD_STATE_ID, + sizeof(*cmd)); + + cmd->offloading = *enabled; + ret = aoc_usb_send_command(drvdata, cmd, sizeof(*cmd), cmd, sizeof(*cmd)); + if (ret < 0) { + kfree(cmd); + return ret; + } + + kfree(cmd); + + return 0; +} + static int aoc_usb_notify(struct notifier_block *this, unsigned long code, void *data) { @@ -326,12 +351,18 @@ static int aoc_usb_notify(struct notifier_block *this, case SYNC_CONN_STAT: ret = aoc_usb_notify_conn_stat(drvdata, data); break; + case SET_OFFLOAD_STATE: + ret = aoc_usb_set_offload_state(drvdata, data); + break; default: dev_warn(&drvdata->adev->dev, "Code %lu is not supported\n", code); ret = -EINVAL; break; } + if (ret < 0) + dev_err(&drvdata->adev->dev, "Fail to handle code %lu, ret = %d", code, ret); + return ret; } @@ -487,6 +518,8 @@ static int __init aoc_usb_init(void) { xhci_vendor_helper_init(); usb_vendor_helper_init(); + snd_usb_audio_vendor_helper_init(); + INIT_WORK(&usb_recovery_ws, usb_recovery_work); INIT_WORK(&usb_host_mode_checking_ws, usb_host_mode_checking_work); diff --git a/usb/snd_usb_audio_hook_impl_whi.c b/usb/snd_usb_audio_hook_impl_whi.c new file mode 100644 index 0000000..be9173f --- /dev/null +++ b/usb/snd_usb_audio_hook_impl_whi.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Google Corp. + * + * Author: + * Howard.Yen <howardyen@google.com> + */ + +#include <sound/pcm.h> +#include <uapi/sound/asound.h> +#include "usbaudio.h" +#include "card.h" + +#include "aoc_usb.h" + + static int snd_usb_audio_vendor_connect(struct usb_interface *intf) +{ + struct usb_device *udev; + struct xhci_hcd *xhci; + + if (!intf) { + pr_err("%s: Invalid parameter\n", __func__); + return -EINVAL; + } + + udev = interface_to_usbdev(intf); + xhci = get_xhci_hcd_by_udev(udev); + + xhci_set_offload_state(xhci, true); + + return 0; +} + +static void snd_usb_audio_vendor_disconnect(struct usb_interface *intf) +{ + struct usb_device *udev; + struct xhci_hcd *xhci; + + if (!intf) { + pr_err("%s: Invalid parameter\n", __func__); + return; + } + + udev = interface_to_usbdev(intf); + xhci = get_xhci_hcd_by_udev(udev); + + xhci_set_offload_state(xhci, false); + + return; +} + +static int snd_usb_audio_vendor_set_interface(struct usb_device *udev, + struct usb_host_interface *alts, + int iface, int alt) +{ + return 0; +} + +static int snd_usb_audio_vendor_set_rate(struct usb_interface *intf, int iface, int rate, + int alt) +{ + return 0; +} + +static int snd_usb_audio_vendor_set_pcm_buf(struct usb_device *udev, int iface) +{ + return 0; +} + +static int snd_usb_audio_vendor_set_pcm_intf(struct usb_interface *intf, int iface, int alt, + int direction) +{ + return 0; +} + +static int snd_usb_audio_vendor_set_pcm_connection(struct usb_device *udev, + enum snd_vendor_pcm_open_close onoff, + int direction) +{ + return 0; +} + +static int snd_usb_audio_vendor_set_pcm_binterval(struct audioformat *fp, + struct audioformat *found, + int *cur_attr, int *attr) +{ + return 0; +} + +static int snd_usb_audio_vendor_usb_add_ctls(struct snd_usb_audio *chip) +{ + return 0; +} + +static struct snd_usb_audio_vendor_ops snd_usb_ops = { + .connect = snd_usb_audio_vendor_connect, + .disconnect = snd_usb_audio_vendor_disconnect, + .set_interface = snd_usb_audio_vendor_set_interface, + .set_rate = snd_usb_audio_vendor_set_rate, + .set_pcm_buf = snd_usb_audio_vendor_set_pcm_buf, + .set_pcm_intf = snd_usb_audio_vendor_set_pcm_intf, + .set_pcm_connection = snd_usb_audio_vendor_set_pcm_connection, + .set_pcm_binterval = snd_usb_audio_vendor_set_pcm_binterval, + .usb_add_ctls = snd_usb_audio_vendor_usb_add_ctls, +}; + +int snd_usb_audio_vendor_helper_init(void) +{ + return snd_vendor_set_ops(&snd_usb_ops); +} diff --git a/usb/xhci_hooks_impl_whi.c b/usb/xhci_hooks_impl_whi.c index d12f160..811eee4 100644 --- a/usb/xhci_hooks_impl_whi.c +++ b/usb/xhci_hooks_impl_whi.c @@ -37,6 +37,27 @@ int unregister_aoc_usb_notifier(struct notifier_block *nb) return blocking_notifier_chain_unregister(&aoc_usb_notifier_list, nb); } +int xhci_set_offload_state(struct xhci_hcd *xhci, bool enabled) +{ + struct xhci_vendor_data *vendor_data; + + if (!xhci) + return -EINVAL; + + vendor_data = xhci_to_priv(xhci)->vendor_data; + + if (!vendor_data->dt_direct_usb_access) + return -EPERM; + + xhci_info(xhci, "Set offloading state %s\n", enabled ? "true" : "false"); + + blocking_notifier_call_chain(&aoc_usb_notifier_list, SET_OFFLOAD_STATE, + &enabled); + vendor_data->offload_state = enabled; + + return 0; +} + static int xhci_sync_dev_ctx(struct xhci_hcd *xhci, unsigned int slot_id) { struct xhci_virt_device *dev; @@ -246,7 +267,7 @@ out: return is_video; } -static struct xhci_hcd *get_xhci_hcd_by_udev(struct usb_device *udev) +struct xhci_hcd *get_xhci_hcd_by_udev(struct usb_device *udev) { struct usb_hcd *uhcd = container_of(udev->bus, struct usb_hcd, self); @@ -475,6 +496,13 @@ static int usb_audio_offload_init(struct xhci_hcd *xhci) return ret; } + vendor_data->dt_direct_usb_access = + of_property_read_bool(dev->of_node, "direct-usb-access") ? true : false; + if (!vendor_data->dt_direct_usb_access) + dev_warn(dev, "Direct USB access is not supported\n"); + + vendor_data->offload_state = true; + usb_register_notify(&xhci_udev_nb); vendor_data->op_mode = USB_OFFLOAD_DRAM; vendor_data->xhci = xhci; @@ -539,7 +567,7 @@ static bool is_usb_offload_enabled(struct xhci_hcd *xhci, if (is_usb_video_device(udev)) return false; else if (ep_ring->type == TYPE_ISOC) - return true; + return vendor_data->offload_state; } } |