summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Yen <howardyen@google.com>2022-01-14 15:52:47 +0800
committerTreeHugger Robot <treehugger-gerrit@google.com>2022-02-17 02:19:46 +0000
commit32b45e2e08bcb3b6306ec9796d1f50ef44d0d514 (patch)
tree4090c77fa783bea907bbc3296444a4ffe7af980b
parent751036690ecd31bd8854638966b9d585ded74bbd (diff)
downloadaoc-android-gs-raviole-5.10-s-qpr3-beta-2.tar.gz
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/Makefile6
-rw-r--r--usb/aoc_usb.h8
-rw-r--r--usb/aoc_usb_dev.c33
-rw-r--r--usb/snd_usb_audio_hook_impl_whi.c110
-rw-r--r--usb/xhci_hooks_impl_whi.c32
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;
}
}