mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 0/3] Add Audient EVO4 support
@ 2026-09-19 15:18 Christian Ruppert
  2026-09-19 15:18 ` [PATCH 1/3] Fix Audient EVO4 master playback control name Christian Ruppert
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Christian Ruppert @ 2026-09-19 15:18 UTC (permalink / raw)
  To: Jaroslav Kysela, Takashi Iwai, linux-kernel, linux-sound
  Cc: Christian Ruppert, Will Porter, Peter Drabik, Neil Andrews

This patch set adds support for advanced mixer features of the Audient
EVO4 audio interface. The code is structured so that support for the
EVO8 (and potentially other Audient devices) should be trivial to add
but I don't have access to the hardware and no way of testing them so
they are not supported by this patch set.

The third patch in the series (Add Kconfig option for Audient EVO4 mixer
quirks) is optional. Other mixer quirks are compiled in by default and
don't provide Kconfig options but as this one adds a few hundred lines
of code I decided to provide this last patch as an option and leave the
choice if such an option should be added to the subsystem maintainers.

Christian Ruppert (3):
  Fix Audient EVO4 master playback control name
  Add Audient EVO4 mixer quirks
  Add Kconfig option for Audient EVO4 mixer quirks

 MAINTAINERS              |   7 +
 sound/usb/Kconfig        |  10 +
 sound/usb/Makefile       |   2 +
 sound/usb/mixer_evo.c    | 505 +++++++++++++++++++++++++++++++++++++++
 sound/usb/mixer_evo.h    |  12 +
 sound/usb/mixer_maps.c   |  13 +
 sound/usb/mixer_quirks.c |   9 +
 7 files changed, 558 insertions(+)
 create mode 100644 sound/usb/mixer_evo.c
 create mode 100644 sound/usb/mixer_evo.h

-- 
2.55.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/3] Fix Audient EVO4 master playback control name
  2026-09-19 15:18 [PATCH 0/3] Add Audient EVO4 support Christian Ruppert
@ 2026-09-19 15:18 ` Christian Ruppert
  2026-09-19 15:18 ` [PATCH 2/3] Add Audient EVO4 mixer quirks Christian Ruppert
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Christian Ruppert @ 2026-09-19 15:18 UTC (permalink / raw)
  To: Jaroslav Kysela, Takashi Iwai, linux-kernel, linux-sound
  Cc: Christian Ruppert, Will Porter, Peter Drabik, Neil Andrews

The Audient EVO4 master volume mixer channel enumerates as 'EVO4 '. Rename
it to 'Master' according to control-names.rst.

Signed-off-by: Christian Ruppert <arc@gmx.li>
---
 sound/usb/mixer_maps.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index 41454cb403d0..1a6ad776126b 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -505,6 +505,14 @@ static const struct usbmix_connector_map gigabyte_b450_connector_map[] = {
 	{}
 };
 
+/* Audient EVO4: Rename FU 10 from 'EVO4 ' to 'Master' according to the
+ * ALSA naming convention
+ */
+static const struct usbmix_name_map audient_evo4_map[] = {
+	{ 10, "Master Playback" },
+	{}
+};
+
 /* Audient iD14 MkI and MkII: FU 12 sits on the monitor mixer branch but is
  * traced through to the Speaker output terminal, so it is named "Speaker
  * Playback Volume".  On MkII it controls only 4 of 6 playback channels.  MkI
@@ -632,6 +640,11 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = {
 		.id = USB_ID(0x2708, 0x0002),
 		.map = audient_id14_map,
 	},
+	{
+		/* Audient EVO4 MkI */
+		.id = USB_ID(0x2708, 0x0006),
+		.map = audient_evo4_map,
+	},
 	{
 		/* Audient iD14 MkII */
 		.id = USB_ID(0x2708, 0x0008),
-- 
2.55.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 2/3] Add Audient EVO4 mixer quirks
  2026-09-19 15:18 [PATCH 0/3] Add Audient EVO4 support Christian Ruppert
  2026-09-19 15:18 ` [PATCH 1/3] Fix Audient EVO4 master playback control name Christian Ruppert
@ 2026-09-19 15:18 ` Christian Ruppert
  2026-09-19 15:18 ` [PATCH 3/3] Add Kconfig option for " Christian Ruppert
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Christian Ruppert @ 2026-09-19 15:18 UTC (permalink / raw)
  To: Jaroslav Kysela, Takashi Iwai, linux-kernel, linux-sound
  Cc: Christian Ruppert, Will Porter, Peter Drabik, Neil Andrews

The controls enumerated by the Audient EVO4 are incomplete. Add missing
controls for
  * channel muting
  * the cross-fader
  * the recording mixer
  * phantom power

The driver is structured so that it should be trivial to extend it to the
EVO8 (and potentially other Audient devices) but we need a kind soul who
has access to that hardware to correctly map the control names and test
everything.

Signed-off-by: Christian Ruppert <arc@gmx.li>
---
 MAINTAINERS              |   7 +
 sound/usb/Makefile       |   1 +
 sound/usb/mixer_evo.c    | 505 +++++++++++++++++++++++++++++++++++++++
 sound/usb/mixer_evo.h    |  12 +
 sound/usb/mixer_quirks.c |   5 +
 5 files changed, 530 insertions(+)
 create mode 100644 sound/usb/mixer_evo.c
 create mode 100644 sound/usb/mixer_evo.h

diff --git a/MAINTAINERS b/MAINTAINERS
index c2414447892c..5f8df442b1a5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4346,6 +4346,13 @@ F:	drivers/net/ieee802154/at86rf230.h
 F:	drivers/net/ieee802154/atusb.c
 F:	drivers/net/ieee802154/atusb.h
 
+AUDIENT EVO MIXER DRIVER
+M:	Christian Ruppert <arc@gmx.li>
+L:	linux-sound@vger.kernel.org
+S:	Maintained
+F:	sound/usb/mixer_evo.c
+F:	sound/usb/mixer_evo.h
+
 AUDIT SUBSYSTEM
 M:	Paul Moore <paul@paul-moore.com>
 M:	Eric Paris <eparis@redhat.com>
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index e62794a87e73..2e842dcc73de 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -11,6 +11,7 @@ snd-usb-audio-y := 	card.o \
 			helper.o \
 			implicit.o \
 			mixer.o \
+			mixer_evo.o \
 			mixer_quirks.o \
 			mixer_scarlett.o \
 			mixer_scarlett2.o \
diff --git a/sound/usb/mixer_evo.c b/sound/usb/mixer_evo.c
new file mode 100644
index 000000000000..c327b82c8d2d
--- /dev/null
+++ b/sound/usb/mixer_evo.c
@@ -0,0 +1,505 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Audient EVO driver for ALSA
+ * Copyright (C) 2026 Christian Ruppert <arc@gmx.li>
+ *
+ * Based on the work of Ivan Hazucha for audient-evo-py.
+ * https://github.com/vanzaho/audient-evo-py/
+ */
+
+
+#include <asm/byteorder.h>
+#include <linux/usb.h>
+#include <linux/usb/audio-v2.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "usbaudio.h"
+#include "mixer.h"
+#include "mixer_quirks.h"
+#include "helper.h"
+#include "mixer_evo.h"
+
+
+enum snd_evo_type {
+	SND_EVO_TYPE_MONITOR = 0,
+	SND_EVO_TYPE_PHANTOM,
+	SND_EVO_TYPE_MUTE,
+	SND_EVO_TYPE_MUTE_OUT,
+	SND_EVO_TYPE_MIXER,
+	SND_EVO_TYPE_NCTYPES
+};
+
+static const struct snd_evo_ctrl_type {
+	snd_ctl_elem_type_t type;
+	bool invert;
+	union {
+		int integer;
+	} min;
+	union {
+		int integer;
+	} max;
+	u16 wValue;
+	u16 wIndex;
+} snd_evo_ctypes[SND_EVO_TYPE_NCTYPES] = {
+	[SND_EVO_TYPE_MONITOR] = {
+		.type = SNDRV_CTL_ELEM_TYPE_INTEGER,
+		.min.integer = 0,
+		.max.integer = 127,
+		.wValue = 0x0000,
+		.wIndex = 0x3800,
+	},
+	[SND_EVO_TYPE_PHANTOM] = {
+		.type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
+		.invert = false,
+		.min.integer = 0,
+		.max.integer = 1,
+		.wValue = 0x0000,
+		.wIndex = 0x3A00,
+	},
+	[SND_EVO_TYPE_MUTE] = {
+		.type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
+		.invert = true,
+		.min.integer = 0,
+		.max.integer = 1,
+		.wValue = 0x0200,
+		.wIndex = 0x3A00,
+	},
+	[SND_EVO_TYPE_MUTE_OUT] = {
+		.type = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
+		.invert = true,
+		.min.integer = 0,
+		.max.integer = 1,
+		.wValue = 0x0100,
+		.wIndex = 0x3B00,
+	},
+	[SND_EVO_TYPE_MIXER] = {
+		.type = SNDRV_CTL_ELEM_TYPE_INTEGER,
+		.min.integer = -128 * 256,
+		.max.integer = 6 * 256,
+		.wValue = 0x0100,
+		.wIndex = 0x3C00,
+	},
+};
+
+#define SND_EVO_FLAGS_DIRECTION (1L<<0)
+#define SND_EVO_FLAGS_CAPTURE (1L<<0)
+#define SND_EVO_FLAGS_PLAYBACK (0L<<0)
+
+struct snd_evo_ctrl {
+	char *basename;
+	enum snd_evo_type type;
+	unsigned int channels;
+	unsigned int hwchannels;
+	unsigned int val_offs;
+	unsigned long flags;
+};
+
+static const struct snd_evo_ctrl evo4_controls[] = {
+	{
+		.basename = "Master",
+		.type = SND_EVO_TYPE_MUTE_OUT,
+		.channels = 1,
+		.hwchannels = 1,
+		.val_offs = 0,
+		.flags = SND_EVO_FLAGS_PLAYBACK,
+	},
+	{
+		.basename = "Mic",
+		.type = SND_EVO_TYPE_MUTE,
+		.channels = 4,
+		.hwchannels = 2,
+		.val_offs = 0,
+		.flags = SND_EVO_FLAGS_PLAYBACK,
+	},
+	{
+		.basename = "Monitor",
+		.type = SND_EVO_TYPE_MONITOR,
+		.channels = 1,
+		.hwchannels = 1,
+		.val_offs = 0,
+		.flags = SND_EVO_FLAGS_PLAYBACK,
+	},
+	{
+		.basename = "Mic 1",
+		.type = SND_EVO_TYPE_MIXER,
+		.channels = 2,
+		.hwchannels = 2,
+		.val_offs = 0,
+		.flags = SND_EVO_FLAGS_CAPTURE,
+	},
+	{
+		.basename = "Mic 2",
+		.type = SND_EVO_TYPE_MIXER,
+		.channels = 2,
+		.hwchannels = 2,
+		.val_offs = 2,
+		.flags = SND_EVO_FLAGS_CAPTURE,
+	},
+	{
+		.basename = "Master Left",
+		.type = SND_EVO_TYPE_MIXER,
+		.channels = 2,
+		.hwchannels = 2,
+		.val_offs = 4,
+		.flags = SND_EVO_FLAGS_CAPTURE,
+	},
+	{
+		.basename = "Master Right",
+		.type = SND_EVO_TYPE_MIXER,
+		.channels = 2,
+		.hwchannels = 2,
+		.val_offs = 6,
+		.flags = SND_EVO_FLAGS_CAPTURE,
+	},
+	{
+		.basename = "Loopback Left",
+		.type = SND_EVO_TYPE_MIXER,
+		.channels = 2,
+		.hwchannels = 2,
+		.val_offs = 8,
+		.flags = SND_EVO_FLAGS_CAPTURE,
+	},
+	{
+		.basename = "Loopback Right",
+		.type = SND_EVO_TYPE_MIXER,
+		.channels = 2,
+		.hwchannels = 2,
+		.val_offs = 10,
+		.flags = SND_EVO_FLAGS_CAPTURE,
+	},
+	{
+		.basename = "Mic 1 Phantom",
+		.type = SND_EVO_TYPE_PHANTOM,
+		.channels = 1,
+		.hwchannels = 1,
+		.val_offs = 0,
+		.flags = SND_EVO_FLAGS_CAPTURE,
+	},
+	{
+		.basename = "Mic 2 Phantom",
+		.type = SND_EVO_TYPE_PHANTOM,
+		.channels = 1,
+		.hwchannels = 1,
+		.val_offs = 1,
+		.flags = SND_EVO_FLAGS_CAPTURE,
+	},
+	{ 0 }, /* sentinel */
+};
+
+static const struct evo_devinfo {
+	u32 usb_id;
+	const struct snd_evo_ctrl *controls;
+} evo_devinfo[] = {
+	{
+		.usb_id = USB_ID(USB_AUDIENT_VID, USB_EVO4_PID),
+		.controls = evo4_controls,
+	},
+	{
+		.usb_id = USB_ID(USB_AUDIENT_VID, USB_EVO4_PID),
+		.controls = NULL,
+	},
+	{ 0 } /* sentinel */
+};
+
+
+static inline unsigned long snd_evo_kctl_priv(enum snd_evo_type type,
+					      u8 valoffs, u8 hwchannels)
+{
+	unsigned long type_l = type & 0xFF;
+	unsigned long valoffs_l = valoffs & 0xFF;
+	unsigned long hwchannels_l = hwchannels & 0xFF;
+
+	return (hwchannels_l << 16) | (valoffs_l << 8) | type_l;
+}
+
+static __always_inline
+const struct snd_evo_ctrl_type *snd_evo_kctl_type(struct snd_kcontrol *kctl)
+{
+	return &snd_evo_ctypes[kctl->private_value & 0xFF];
+}
+
+static __always_inline u16 snd_evo_kctl_valoffs(struct snd_kcontrol *kctl)
+{
+	return (kctl->private_value >> 8) & 0xFF;
+}
+
+static __always_inline u16 snd_evo_kctl_hwchannels(struct snd_kcontrol *kctl)
+{
+	return (kctl->private_value >> 16) & 0xFF;
+}
+
+static inline u16 snd_evo_kctl_channels(struct snd_kcontrol *kctl)
+{
+	struct usb_mixer_elem_info *info = kctl->private_data;
+
+	return info->channels;
+}
+
+
+#define EVO_REQ_CUR (0x01)
+#define EVO_REQTYPE_SET (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+#define EVO_REQTYPE_GET (USB_DIR_IN  | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+
+static inline int snd_evo_get_cur(struct usb_mixer_interface *mixer,
+				  u16 value, u16 index,
+				  void *buf, size_t len)
+{
+	struct usb_device *const dev = mixer->chip->dev;
+
+	return snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
+			       EVO_REQ_CUR, EVO_REQTYPE_GET,
+			       value, index, buf, len);
+}
+
+static inline int snd_evo_set_cur(struct usb_mixer_interface *mixer,
+				  u16 value, u16 index,
+				  void *buf, size_t len)
+{
+	struct usb_device *const dev = mixer->chip->dev;
+
+	return snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
+			       EVO_REQ_CUR, EVO_REQTYPE_SET,
+			       value, index, buf, len);
+}
+
+
+static int snd_ctl_evo_boolean_get(struct snd_kcontrol *kctl,
+				   struct snd_ctl_elem_value *ctl_val)
+{
+	struct usb_mixer_elem_list *const list = snd_kcontrol_chip(kctl);
+	struct usb_mixer_interface *const mixer = list->mixer;
+
+	const unsigned int nchan = snd_evo_kctl_channels(kctl);
+	const unsigned int hwchan = snd_evo_kctl_hwchannels(kctl);
+	const struct snd_evo_ctrl_type *const ctype = snd_evo_kctl_type(kctl);
+	const u16 value = ctype->wValue + snd_evo_kctl_valoffs(kctl);
+	const u16 index = ctype->wIndex;
+
+	int i;
+
+	for (i = 0; i < hwchan; i++) {
+		u32 buf;
+		int ret;
+
+		ret = snd_evo_get_cur(mixer, value + i, index,
+				      &buf, sizeof(buf));
+		if (ret < 0)
+			return ret;
+
+		ctl_val->value.integer.value[i] = le32_to_cpu(buf) ? 1 : 0;
+
+		if (ctype->invert)
+			ctl_val->value.integer.value[i] ^= 0x1;
+	}
+
+	for (; i < nchan; i++)
+		ctl_val->value.integer.value[i] = ctype->invert
+							? ctype->max.integer
+							: ctype->min.integer;
+
+	return 0;
+}
+
+static int snd_ctl_evo_boolean_set(struct snd_kcontrol *kctl,
+				   struct snd_ctl_elem_value *ctl_val)
+{
+	struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
+	struct usb_mixer_interface *mixer = list->mixer;
+
+	const unsigned int hwchan = snd_evo_kctl_hwchannels(kctl);
+	const struct snd_evo_ctrl_type *const ctype = snd_evo_kctl_type(kctl);
+	const u16 value = ctype->wValue + snd_evo_kctl_valoffs(kctl);
+	const u16 index = ctype->wIndex;
+
+	int changed = 0;
+	int i;
+
+	for (i = 0; i < hwchan; i++) {
+		u32 rbuf;
+		u32 buf = cpu_to_le32(ctl_val->value.integer.value[i] ? 1 : 0);
+		int ret;
+
+		if (ctype->invert)
+			buf ^= 0x1;
+
+		ret = snd_evo_get_cur(mixer, value + i, index,
+				      &rbuf, sizeof(rbuf));
+		if (ret < 0)
+			return ret;
+
+		if (rbuf != buf) {
+			changed = 1;
+
+			ret = snd_evo_set_cur(mixer, value + i, index,
+					      &buf, sizeof(buf));
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return changed;
+}
+
+static int snd_ctl_evo_integer_get(struct snd_kcontrol *kctl,
+				   struct snd_ctl_elem_value *ctl_val)
+{
+	struct usb_mixer_elem_list *const list = snd_kcontrol_chip(kctl);
+	struct usb_mixer_interface *const mixer = list->mixer;
+
+	const unsigned int nchan = snd_evo_kctl_channels(kctl);
+	const unsigned int hwchan = snd_evo_kctl_hwchannels(kctl);
+	const struct snd_evo_ctrl_type *const ctype = snd_evo_kctl_type(kctl);
+	const u16 value = ctype->wValue + snd_evo_kctl_valoffs(kctl);
+	const u16 index = ctype->wIndex;
+
+	int i;
+
+	for (i = 0; i < hwchan; i++) {
+		u16 buf;
+		s16 val;
+		int ret;
+
+		ret = snd_evo_get_cur(mixer, value + i, index,
+				      &buf, sizeof(buf));
+		if (ret < 0)
+			return ret;
+
+		val = le16_to_cpu(buf);
+		ctl_val->value.integer.value[i] = val;
+	}
+
+	for (; i < nchan; i++)
+		ctl_val->value.integer.value[i] = ctype->min.integer;
+
+	return 0;
+}
+
+static int snd_ctl_evo_integer_set(struct snd_kcontrol *kctl,
+				   struct snd_ctl_elem_value *ctl_val)
+{
+	struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
+	struct usb_mixer_interface *mixer = list->mixer;
+
+	const unsigned int hwchan = snd_evo_kctl_hwchannels(kctl);
+	const struct snd_evo_ctrl_type *const ctype = snd_evo_kctl_type(kctl);
+	const u16 value = ctype->wValue + snd_evo_kctl_valoffs(kctl);
+	const u16 index = ctype->wIndex;
+
+	int changed = 0;
+	int i;
+
+	for (i = 0; i < hwchan; i++) {
+		s16 rbuf;
+		s16 buf = cpu_to_le16(ctl_val->value.integer.value[i]);
+		int ret;
+
+		ret = snd_evo_get_cur(mixer, value + i, index,
+				      &rbuf, sizeof(rbuf));
+		if (ret < 0)
+			return ret;
+
+		if (rbuf != buf) {
+			changed = 1;
+
+			ret = snd_evo_set_cur(mixer, value + i, index,
+					      &buf, sizeof(buf));
+			if (ret < 0)
+				return ret;
+		}
+	}
+
+	return changed;
+}
+
+static int snd_ctl_evo_info(struct snd_kcontrol *kctl,
+			    struct snd_ctl_elem_info *uinfo)
+{
+	const struct snd_evo_ctrl_type *const ctype = snd_evo_kctl_type(kctl);
+
+	uinfo->type = ctype->type;
+	uinfo->access = SNDRV_CTL_ELEM_ACCESS_READWRITE
+			| SNDRV_CTL_ELEM_ACCESS_VOLATILE;
+	uinfo->count = snd_evo_kctl_channels(kctl);
+	uinfo->value.integer.min = ctype->min.integer;
+	uinfo->value.integer.max = ctype->max.integer;
+	return 0;
+}
+
+
+static int snd_evo_add_ctrl(struct usb_mixer_interface *mixer,
+			    const struct snd_evo_ctrl *ctrl)
+{
+	const struct snd_evo_ctrl_type *ctype = &snd_evo_ctypes[ctrl->type];
+	char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+	struct snd_kcontrol_new knew = { 0 };
+	struct snd_kcontrol *kctl;
+	struct usb_mixer_elem_info *elem;
+
+	knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	knew.name = name;
+	knew.info = snd_ctl_evo_info;
+	knew.private_value = snd_evo_kctl_priv(ctrl->type, ctrl->val_offs,
+					       ctrl->hwchannels);
+
+	switch (ctype->type) {
+	case SNDRV_CTL_ELEM_TYPE_INTEGER:
+		knew.get = snd_ctl_evo_integer_get;
+		knew.put = snd_ctl_evo_integer_set;
+		break;
+	case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
+		knew.get = snd_ctl_evo_boolean_get;
+		knew.put = snd_ctl_evo_boolean_set;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	snprintf(name, sizeof(name), "%s %s %s", ctrl->basename,
+		 ((ctrl->flags & SND_EVO_FLAGS_DIRECTION)
+			== SND_EVO_FLAGS_CAPTURE) ? "Capture" : "Playback",
+		 (ctype->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN)
+			? "Switch" : "Volume");
+
+	elem = kzalloc_obj(*elem);
+	if (!elem)
+		return -ENOMEM;
+
+	elem->head.mixer = mixer;
+	elem->channels = ctrl->channels;
+
+	kctl = snd_ctl_new1(&knew, elem);
+	if (!kctl) {
+		kfree(elem);
+		return -ENOMEM;
+	}
+
+	kctl->private_free = snd_usb_mixer_elem_free;
+
+	return snd_usb_mixer_add_control(&elem->head, kctl);
+}
+
+
+/* called from mixer_quirks.c */
+int snd_evo_controls_create(struct usb_mixer_interface *mixer)
+{
+	const struct evo_devinfo *info;
+	const struct snd_evo_ctrl *ctrl;
+
+	for (info = evo_devinfo; info->controls; info++)
+		if (info->usb_id == mixer->chip->usb_id)
+			break;
+
+	if (!info->controls)
+		return -ENODEV;
+
+	for (ctrl = info->controls; ctrl->basename; ctrl++) {
+		const int ret = snd_evo_add_ctrl(mixer, ctrl);
+
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
diff --git a/sound/usb/mixer_evo.h b/sound/usb/mixer_evo.h
new file mode 100644
index 000000000000..7fe7e197185c
--- /dev/null
+++ b/sound/usb/mixer_evo.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __USB_MIXER_EVO_H
+#define __USB_MIXER_EVO_H
+
+#include "mixer.h"
+
+#define USB_AUDIENT_VID (0x2708)
+#define USB_EVO4_PID (0x0006)
+
+int snd_evo_controls_create(struct usb_mixer_interface *mixer);
+
+#endif /* __USB_MIXER_EVO_H */
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index fc622eb95dc5..1e266fdbbb8e 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -38,6 +38,7 @@
 #include "mixer_scarlett2.h"
 #include "mixer_us16x08.h"
 #include "mixer_s1810c.h"
+#include "mixer_evo.h"
 #include "helper.h"
 #include "fcp.h"
 
@@ -4539,6 +4540,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 		err = snd_fcp_init(mixer);
 		break;
 
+	case USB_ID(USB_AUDIENT_VID, USB_EVO4_PID): /* Audient EVO 4 */
+		err = snd_evo_controls_create(mixer);
+		break;
+
 	case USB_ID(0x041e, 0x323b): /* Creative Sound Blaster E1 */
 		err = snd_soundblaster_e1_switch_create(mixer);
 		break;
-- 
2.55.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 3/3] Add Kconfig option for Audient EVO4 mixer quirks
  2026-09-19 15:18 [PATCH 0/3] Add Audient EVO4 support Christian Ruppert
  2026-09-19 15:18 ` [PATCH 1/3] Fix Audient EVO4 master playback control name Christian Ruppert
  2026-09-19 15:18 ` [PATCH 2/3] Add Audient EVO4 mixer quirks Christian Ruppert
@ 2026-09-19 15:18 ` Christian Ruppert
  2026-09-25 10:18 ` [PATCH 0/3] Add Audient EVO4 support Faaris Ansari
  2026-09-29 13:21 ` Takashi Iwai
  4 siblings, 0 replies; 8+ messages in thread
From: Christian Ruppert @ 2026-09-19 15:18 UTC (permalink / raw)
  To: Jaroslav Kysela, Takashi Iwai, linux-kernel, linux-sound
  Cc: Christian Ruppert, Will Porter, Peter Drabik, Neil Andrews

Add Kconfig option for the Audient EVO4 support. This is split out from
the evo4 driver so it can be optionally applied. Other mixer quirks don't
seem to have Kconfig options so I leave it to the upstream to decide what
to do with this.

Signed-off-by: Christian Ruppert <arc@gmx.li>
---
 sound/usb/Kconfig        | 10 ++++++++++
 sound/usb/Makefile       |  3 ++-
 sound/usb/mixer_quirks.c |  4 ++++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index b4588915efa1..21039dd4ae3a 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -175,6 +175,16 @@ config SND_USB_HIFACE
 	  To compile this driver as a module, choose M here: the module
 	  will be called snd-usb-hiface.
 
+config SND_USB_EVO
+	bool "Audient EVO advanced mixer features"
+	help
+	  Support advanced mixer features for the Audient EVO4 USB audio
+	  interface such as
+	    * the recording mixer
+	    * the monitor crossfader
+	    * phantom power control
+	    * missing channel mute buttons
+
 config SND_BCD2000
 	tristate "Behringer BCD2000 MIDI driver"
 	select SND_RAWMIDI
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index 2e842dcc73de..f3664adeab85 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -11,7 +11,6 @@ snd-usb-audio-y := 	card.o \
 			helper.o \
 			implicit.o \
 			mixer.o \
-			mixer_evo.o \
 			mixer_quirks.o \
 			mixer_scarlett.o \
 			mixer_scarlett2.o \
@@ -27,6 +26,8 @@ snd-usb-audio-y := 	card.o \
 snd-usb-audio-$(CONFIG_SND_USB_AUDIO_MIDI_V2) += midi2.o
 snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o
 
+snd-usb-audio-$(CONFIG_SND_USB_EVO) += mixer_evo.o
+
 snd-usbmidi-lib-y := midi.o
 
 # Toplevel Module Dependency
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 1e266fdbbb8e..c32ccff40122 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -38,7 +38,9 @@
 #include "mixer_scarlett2.h"
 #include "mixer_us16x08.h"
 #include "mixer_s1810c.h"
+#ifdef CONFIG_SND_USB_EVO
 #include "mixer_evo.h"
+#endif
 #include "helper.h"
 #include "fcp.h"
 
@@ -4540,9 +4542,11 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
 		err = snd_fcp_init(mixer);
 		break;
 
+#ifdef CONFIG_SND_USB_EVO
 	case USB_ID(USB_AUDIENT_VID, USB_EVO4_PID): /* Audient EVO 4 */
 		err = snd_evo_controls_create(mixer);
 		break;
+#endif
 
 	case USB_ID(0x041e, 0x323b): /* Creative Sound Blaster E1 */
 		err = snd_soundblaster_e1_switch_create(mixer);
-- 
2.55.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/3] Add Audient EVO4 support
  2026-09-19 15:18 [PATCH 0/3] Add Audient EVO4 support Christian Ruppert
                   ` (2 preceding siblings ...)
  2026-09-19 15:18 ` [PATCH 3/3] Add Kconfig option for " Christian Ruppert
@ 2026-09-25 10:18 ` Faaris Ansari
  2026-09-27 17:12   ` Christian Ruppert
  2026-09-29 13:21 ` Takashi Iwai
  4 siblings, 1 reply; 8+ messages in thread
From: Faaris Ansari @ 2026-09-25 10:18 UTC (permalink / raw)
  To: arc; +Cc: drabik.p, linux-kernel, linux-sound, mrwillporter, neil, perex, tiwai

Thanks for your work on this - there is currently a regression on the 
latest kernel versions (7.2 onwards, as well as LTS kernels 6.12 and 
6.18). Trying to set the volume in software like wpctl, or pwvucontrol 
causes the software volume to be pulled down with it - I think it's 
something to do with "sticky mixers", not completely sure.

I worked through troubleshooting it here as I originally thought it was 
a wireplumber issue: 
https://gitlab.freedesktop.org/pipewire/wireplumber/-/work_items/1022

This patch should hopefully solve that, and avoid the usage of external 
kernel modules like https://github.com/vanzaho/audient-evo-py (which 
you've based your work from)

I'm not exactly sure how the process with kernel stuff works, but 
considering a regression on current mainline as well as LTS branches for 
this device - is there some chance of fast tracking the merge of these 
patches?

Thanks, Faaris



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/3] Add Audient EVO4 support
  2026-09-25 10:18 ` [PATCH 0/3] Add Audient EVO4 support Faaris Ansari
@ 2026-09-27 17:12   ` Christian Ruppert
  2026-09-27 17:38     ` Faaris Ansari
  0 siblings, 1 reply; 8+ messages in thread
From: Christian Ruppert @ 2026-09-27 17:12 UTC (permalink / raw)
  To: Faaris Ansari
  Cc: drabik.p, linux-kernel, linux-sound, mrwillporter, neil, perex, tiwai

On Fri, Sep 25, 2026 at 11:18:33AM +0100, Faaris Ansari wrote:
> Thanks for your work on this - there is currently a regression on the latest
> kernel versions (7.2 onwards, as well as LTS kernels 6.12 and 6.18). Trying
> to set the volume in software like wpctl, or pwvucontrol causes the software
> volume to be pulled down with it - I think it's something to do with "sticky
> mixers", not completely sure.
> 
> I worked through troubleshooting it here as I originally thought it was a
> wireplumber issue:
> https://gitlab.freedesktop.org/pipewire/wireplumber/-/work_items/1022
> 
> This patch should hopefully solve that,

I'm afraid this is not going to be the case. The patch set doesn't change
anything with the pre-existing controls except for renaming the 'EVO4 '
master volume mixer to 'Master'. As a matter of fact, I made a similar
observation to yours when testing the patch set on the 'sound' kernel tree
and the (very sporadic) issue did not disappear after applying the
patches.

Unluckily, I didn't have time to investigate and as it seemed independent
from this patch set and was never observed on my (vanilla) 6.18.x
day-to-day setup, even with very recent kernels, I forgot about it. I
suspect this might be a regression in the sound-USB core modules or
possibly the the alsa core.

> and avoid the usage of external
> kernel modules like https://github.com/vanzaho/audient-evo-py (which you've
> based your work from)

This one should be solved with the patch set.

> I'm not exactly sure how the process with kernel stuff works, but
> considering a regression on current mainline as well as LTS branches for
> this device - is there some chance of fast tracking the merge of these
> patches?

The best way of supporting this (even if it only solves half of your
concerns) is probably to test it and reply with a Tested-by: tag to the
patches.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/3] Add Audient EVO4 support
  2026-09-27 17:12   ` Christian Ruppert
@ 2026-09-27 17:38     ` Faaris Ansari
  0 siblings, 0 replies; 8+ messages in thread
From: Faaris Ansari @ 2026-09-27 17:38 UTC (permalink / raw)
  To: Christian Ruppert
  Cc: drabik.p, linux-kernel, linux-sound, mrwillporter, neil, perex, tiwai

> I'm afraid this is not going to be the case. The patch set doesn't change
> anything with the pre-existing controls except for renaming the 'EVO4 '
> master volume mixer to 'Master'. As a matter of fact, I made a similar
> observation to yours when testing the patch set on the 'sound' kernel tree
> and the (very sporadic) issue did not disappear after applying the
> patches.

> Unluckily, I didn't have time to investigate and as it seemed independent
> from this patch set and was never observed on my (vanilla) 6.18.x
> day-to-day setup, even with very recent kernels, I forgot about it. I
> suspect this might be a regression in the sound-USB core modules or
> possibly the the alsa core.

I was able to find a work around to this specific issue, adding this
below line in modprobe.d made the hardware volume start working
correctly again.
options snd_usb_audio quirk_flags=2708:0006:ignore_ctl_error
I've reported this regression separately here:
https://lore.kernel.org/regressions/CANBVYRCL=8QdLxGg4S6qrahrFtwJxhv-aSGpW7-1S=+iOe4ZGA@mail.gmail.com/

I also was able to test your patches alongside this workaround. All of
the system controls I was expecting were in fact available within
`alsamixer`, including phantom power, mic gain, etc.
Both mic inputs still seem to be reported as stereo even though
they're mono - I think the other channel is for loopback or something?
I'm not entirely sure if this is something the patches are supposed to
solve.

> The patch set doesn't change
> anything with the pre-existing controls except for renaming the 'EVO4 '

On the note of the UCM config, I had to patch it due to the above or
else PipeWire wasn't able to directly manage the hardware volume knob.
Adding the PlaybackSwitch part also allowed the hardware mute to be
used by PipeWire.

46c46,47
< PlaybackVolume "EVO4 "
---
> PlaybackVolume "Master Playback Volume"
> PlaybackSwitch "Master Playback Switch"

One problem I had with this patchset is the settings I have don't seem
to save with UCM / PipeWire. When powering off the interface and
powering it back on again all settings are reset except for the Master
Playback Volume. After a small discussion on the PipeWire matrix
server I was told that these settings should live in the UCM config
too which I'm assuming they do not currently.
Muting the microphone in pwvucontrol also didn't seem to use the
hardware mic mute. Probably need to add `CaptureSwitch` for the
microphone in UCM too.

However, the current state is by far better than how the interface is
being handled by default - thanks so much for your work on this!

Faaris



On Sun, 27 Sept 2026 at 18:12, Christian Ruppert <arc@gmx.li> wrote:
>
> On Fri, Sep 25, 2026 at 11:18:33AM +0100, Faaris Ansari wrote:
> > Thanks for your work on this - there is currently a regression on the latest
> > kernel versions (7.2 onwards, as well as LTS kernels 6.12 and 6.18). Trying
> > to set the volume in software like wpctl, or pwvucontrol causes the software
> > volume to be pulled down with it - I think it's something to do with "sticky
> > mixers", not completely sure.
> >
> > I worked through troubleshooting it here as I originally thought it was a
> > wireplumber issue:
> > https://gitlab.freedesktop.org/pipewire/wireplumber/-/work_items/1022
> >
> > This patch should hopefully solve that,
>
> I'm afraid this is not going to be the case. The patch set doesn't change
> anything with the pre-existing controls except for renaming the 'EVO4 '
> master volume mixer to 'Master'. As a matter of fact, I made a similar
> observation to yours when testing the patch set on the 'sound' kernel tree
> and the (very sporadic) issue did not disappear after applying the
> patches.
>
> Unluckily, I didn't have time to investigate and as it seemed independent
> from this patch set and was never observed on my (vanilla) 6.18.x
> day-to-day setup, even with very recent kernels, I forgot about it. I
> suspect this might be a regression in the sound-USB core modules or
> possibly the the alsa core.
>
> > and avoid the usage of external
> > kernel modules like https://github.com/vanzaho/audient-evo-py (which you've
> > based your work from)
>
> This one should be solved with the patch set.
>
> > I'm not exactly sure how the process with kernel stuff works, but
> > considering a regression on current mainline as well as LTS branches for
> > this device - is there some chance of fast tracking the merge of these
> > patches?
>
> The best way of supporting this (even if it only solves half of your
> concerns) is probably to test it and reply with a Tested-by: tag to the
> patches.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/3] Add Audient EVO4 support
  2026-09-19 15:18 [PATCH 0/3] Add Audient EVO4 support Christian Ruppert
                   ` (3 preceding siblings ...)
  2026-09-25 10:18 ` [PATCH 0/3] Add Audient EVO4 support Faaris Ansari
@ 2026-09-29 13:21 ` Takashi Iwai
  4 siblings, 0 replies; 8+ messages in thread
From: Takashi Iwai @ 2026-09-29 13:21 UTC (permalink / raw)
  To: Christian Ruppert
  Cc: Jaroslav Kysela, Takashi Iwai, linux-kernel, linux-sound,
	Will Porter, Peter Drabik, Neil Andrews

On Sat, 19 Sep 2026 17:18:37 +0200,
Christian Ruppert wrote:
> 
> This patch set adds support for advanced mixer features of the Audient
> EVO4 audio interface. The code is structured so that support for the
> EVO8 (and potentially other Audient devices) should be trivial to add
> but I don't have access to the hardware and no way of testing them so
> they are not supported by this patch set.
> 
> The third patch in the series (Add Kconfig option for Audient EVO4 mixer
> quirks) is optional. Other mixer quirks are compiled in by default and
> don't provide Kconfig options but as this one adds a few hundred lines
> of code I decided to provide this last patch as an option and leave the
> choice if such an option should be added to the subsystem maintainers.
> 
> Christian Ruppert (3):
>   Fix Audient EVO4 master playback control name
>   Add Audient EVO4 mixer quirks
>   Add Kconfig option for Audient EVO4 mixer quirks

I merged the two, but dropped the Kconfig patch.

We have no Kconfig for other mixer stuff, and most likely the users
will enable simply all mixer supported devices.

It might make sense to introduce a Kconfig if we build each vendor
mixer stuff as an individual module, though.  Until then, let's try
to reduce Kconfig.

BTW, do you see an issue Faaris reported for the recent kernel?


thanks,

Takashi

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-09-29 13:21 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-19 15:18 [PATCH 0/3] Add Audient EVO4 support Christian Ruppert
2026-09-19 15:18 ` [PATCH 1/3] Fix Audient EVO4 master playback control name Christian Ruppert
2026-09-19 15:18 ` [PATCH 2/3] Add Audient EVO4 mixer quirks Christian Ruppert
2026-09-19 15:18 ` [PATCH 3/3] Add Kconfig option for " Christian Ruppert
2026-09-25 10:18 ` [PATCH 0/3] Add Audient EVO4 support Faaris Ansari
2026-09-27 17:12   ` Christian Ruppert
2026-09-27 17:38     ` Faaris Ansari
2026-09-29 13:21 ` Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®