Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- sound/usb/card.c | 6 ++++++
+ sound/usb/card.c | 6 ++++++
1 file changed, 6 insertions(+)
-diff --git a/sound/usb/card.c b/sound/usb/card.c
-index 811bda4eeb9cf..74c5a87dff38e 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
-@@ -384,6 +384,12 @@ static const struct usb_audio_device_name usb_audio_names[] = {
+@@ -382,6 +382,12 @@ static const struct usb_audio_device_nam
/* Creative/Toshiba Multimedia Center SB-0500 */
DEVICE_NAME(0x041e, 0x3048, "Toshiba", "SB-0500"),
DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"),
DEVICE_NAME(0x05e1, 0x0408, "Syntek", "STK1160"),
---
-2.43.0
-
+++ /dev/null
-From 3a84e7746b37d4d8dce8d7d4f9f64542cbf68612 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 11 Aug 2024 17:29:56 -0700
-Subject: ALSA: usb-audio: Support multiple control interfaces
-
-From: Karol Kosik <k.kosik@outlook.com>
-
-[ Upstream commit 6aa8700150f7dc62f60b4cf5b1624e2e3d9ed78e ]
-
-Registering Numark Party Mix II fails with error 'bogus bTerminalLink 1'.
-The problem stems from the driver not being able to find input/output
-terminals required to configure audio streaming. The information about
-those terminals is stored in AudioControl Interface. Numark device
-contains 2 AudioControl Interfaces and the driver checks only one of them.
-
-According to the USB standard, a device can have multiple audio functions,
-each represented by Audio Interface Collection. Every audio function is
-considered to be closed box and will contain unique AudioControl Interface
-and zero or more AudioStreaming and MIDIStreaming Interfaces.
-
-The Numark device adheres to the standard and defines two audio functions:
-- MIDIStreaming function
-- AudioStreaming function
-It starts with MIDI function, followed by the audio function. The driver
-saves the first AudioControl Interface in `snd_usb_audio` structure
-associated with the entire device. It then attempts to use this interface
-to query for terminals and clocks. However, this fails because the correct
-information is stored in the second AudioControl Interface, defined in the
-second Audio Interface Collection.
-
-This patch introduces a structure holding association between each
-MIDI/Audio Interface and its corresponding AudioControl Interface,
-instead of relying on AudioControl Interface defined for the entire
-device. This structure is populated during usb probing phase and leveraged
-later when querying for terminals and when sending USB requests.
-
-Alternative solutions considered include:
-- defining a quirk for Numark where the order of interface is manually
-changed, or terminals are hardcoded in the driver. This solution would
-have fixed only this model, though it seems that device is USB compliant,
-and it also seems that other devices from this company may be affected.
-What's more, it looks like products from other manufacturers have similar
-problems, i.e. Rane One DJ console
-- keeping a list of all AudioControl Interfaces and querying all of them
-to find required information. That would have solved my problem and have
-low probability of breaking other devices, as we would always start with
-the same logic of querying first AudioControl Interface. This solution
-would not have followed the standard though.
-
-This patch preserves the `snd_usb_audio.ctrl_intf` variable, which holds
-the first AudioControl Interface, and uses it as a fallback when some
-interfaces are not parsed correctly and lack an associated AudioControl
-Interface, i.e., when configured via quirks.
-
-Link: https://bugzilla.kernel.org/show_bug.cgi?id=217865
-Signed-off-by: Karol Kosik <k.kosik@outlook.com>
-Link: https://patch.msgid.link/AS8P190MB1285893F4735C8B32AD3886BEC852@AS8P190MB1285.EURP190.PROD.OUTLOOK.COM
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- sound/usb/card.c | 2 ++
- sound/usb/clock.c | 62 ++++++++++++++++++++++++--------------
- sound/usb/format.c | 6 ++--
- sound/usb/helper.c | 34 +++++++++++++++++++++
- sound/usb/helper.h | 10 ++++--
- sound/usb/mixer.c | 2 +-
- sound/usb/mixer_quirks.c | 17 ++++++-----
- sound/usb/mixer_scarlett.c | 4 +--
- sound/usb/power.c | 3 +-
- sound/usb/power.h | 1 +
- sound/usb/stream.c | 21 ++++++++-----
- sound/usb/usbaudio.h | 12 ++++++++
- 12 files changed, 127 insertions(+), 47 deletions(-)
-
-diff --git a/sound/usb/card.c b/sound/usb/card.c
-index 26268ffb82742..811bda4eeb9cf 100644
---- a/sound/usb/card.c
-+++ b/sound/usb/card.c
-@@ -206,6 +206,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
- return -EINVAL;
- }
-
-+ snd_usb_add_ctrl_interface_link(chip, interface, ctrlif);
-+
- if (! snd_usb_parse_audio_interface(chip, interface)) {
- usb_set_interface(dev, interface, 0); /* reset the current interface */
- return usb_driver_claim_interface(&usb_audio_driver, iface,
-diff --git a/sound/usb/clock.c b/sound/usb/clock.c
-index a676ad093d189..6f0693c428b0b 100644
---- a/sound/usb/clock.c
-+++ b/sound/usb/clock.c
-@@ -76,11 +76,14 @@ static bool validate_clock_multiplier(void *p, int id, int proto)
- }
-
- #define DEFINE_FIND_HELPER(name, obj, validator, type2, type3) \
--static obj *name(struct snd_usb_audio *chip, int id, int proto) \
-+static obj *name(struct snd_usb_audio *chip, int id, \
-+ const struct audioformat *fmt) \
- { \
-- return find_uac_clock_desc(chip->ctrl_intf, id, validator, \
-- proto == UAC_VERSION_3 ? (type3) : (type2), \
-- proto); \
-+ struct usb_host_interface *ctrl_intf = \
-+ snd_usb_find_ctrl_interface(chip, fmt->iface); \
-+ return find_uac_clock_desc(ctrl_intf, id, validator, \
-+ fmt->protocol == UAC_VERSION_3 ? (type3) : (type2), \
-+ fmt->protocol); \
- }
-
- DEFINE_FIND_HELPER(snd_usb_find_clock_source,
-@@ -93,16 +96,19 @@ DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier,
- union uac23_clock_multiplier_desc, validate_clock_multiplier,
- UAC2_CLOCK_MULTIPLIER, UAC3_CLOCK_MULTIPLIER);
-
--static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
-+static int uac_clock_selector_get_val(struct snd_usb_audio *chip,
-+ int selector_id, int iface_no)
- {
-+ struct usb_host_interface *ctrl_intf;
- unsigned char buf;
- int ret;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
- ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
- UAC2_CS_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- UAC2_CX_CLOCK_SELECTOR << 8,
-- snd_usb_ctrl_intf(chip) | (selector_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8),
- &buf, sizeof(buf));
-
- if (ret < 0)
-@@ -111,16 +117,18 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i
- return buf;
- }
-
--static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
-- unsigned char pin)
-+static int uac_clock_selector_set_val(struct snd_usb_audio *chip,
-+ int selector_id, unsigned char pin, int iface_no)
- {
-+ struct usb_host_interface *ctrl_intf;
- int ret;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
- ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
- UAC2_CS_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- UAC2_CX_CLOCK_SELECTOR << 8,
-- snd_usb_ctrl_intf(chip) | (selector_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8),
- &pin, sizeof(pin));
- if (ret < 0)
- return ret;
-@@ -132,7 +140,7 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i
- return -EINVAL;
- }
-
-- ret = uac_clock_selector_get_val(chip, selector_id);
-+ ret = uac_clock_selector_get_val(chip, selector_id, iface_no);
- if (ret < 0)
- return ret;
-
-@@ -155,8 +163,10 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
- unsigned char data;
- struct usb_device *dev = chip->dev;
- union uac23_clock_source_desc *cs_desc;
-+ struct usb_host_interface *ctrl_intf;
-
-- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol);
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
-+ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt);
- if (!cs_desc)
- return false;
-
-@@ -191,7 +201,7 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_CLOCK_VALID << 8,
-- snd_usb_ctrl_intf(chip) | (source_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8),
- &data, sizeof(data));
- if (err < 0) {
- dev_warn(&dev->dev,
-@@ -217,8 +227,10 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
- struct usb_device *dev = chip->dev;
- u32 bmControls;
- union uac23_clock_source_desc *cs_desc;
-+ struct usb_host_interface *ctrl_intf;
-
-- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol);
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
-+ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt);
- if (!cs_desc)
- return false;
-
-@@ -235,7 +247,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_CLOCK_VALID << 8,
-- snd_usb_ctrl_intf(chip) | (source_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8),
- &data, sizeof(data));
-
- if (err < 0) {
-@@ -272,7 +284,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- }
-
- /* first, see if the ID we're looking at is a clock source already */
-- source = snd_usb_find_clock_source(chip, entity_id, proto);
-+ source = snd_usb_find_clock_source(chip, entity_id, fmt);
- if (source) {
- entity_id = GET_VAL(source, proto, bClockID);
- if (validate && !uac_clock_source_is_valid(chip, fmt,
-@@ -285,7 +297,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- return entity_id;
- }
-
-- selector = snd_usb_find_clock_selector(chip, entity_id, proto);
-+ selector = snd_usb_find_clock_selector(chip, entity_id, fmt);
- if (selector) {
- pins = GET_VAL(selector, proto, bNrInPins);
- clock_id = GET_VAL(selector, proto, bClockID);
-@@ -299,7 +311,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
-
- /* the entity ID we are looking at is a selector.
- * find out what it currently selects */
-- ret = uac_clock_selector_get_val(chip, clock_id);
-+ ret = uac_clock_selector_get_val(chip, clock_id, fmt->iface);
- if (ret < 0) {
- if (!chip->autoclock)
- return ret;
-@@ -327,7 +339,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- /* Skip setting clock selector again for some devices */
- if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR)
- return ret;
-- err = uac_clock_selector_set_val(chip, entity_id, cur);
-+ err = uac_clock_selector_set_val(chip, entity_id, cur, fmt->iface);
- if (err < 0) {
- if (pins == 1) {
- usb_audio_dbg(chip,
-@@ -355,7 +367,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- if (ret < 0)
- continue;
-
-- err = uac_clock_selector_set_val(chip, entity_id, i);
-+ err = uac_clock_selector_set_val(chip, entity_id, i, fmt->iface);
- if (err < 0)
- continue;
-
-@@ -369,7 +381,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- }
-
- /* FIXME: multipliers only act as pass-thru element for now */
-- multiplier = snd_usb_find_clock_multiplier(chip, entity_id, proto);
-+ multiplier = snd_usb_find_clock_multiplier(chip, entity_id, fmt);
- if (multiplier)
- return __uac_clock_find_source(chip, fmt,
- GET_VAL(multiplier, proto, bCSourceID),
-@@ -469,11 +481,13 @@ static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
- struct usb_device *dev = chip->dev;
- __le32 data;
- int err;
-+ struct usb_host_interface *ctrl_intf;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface);
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- &data, sizeof(data));
- if (err < 0) {
- dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n",
-@@ -502,8 +516,10 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
- __le32 data;
- int err;
- union uac23_clock_source_desc *cs_desc;
-+ struct usb_host_interface *ctrl_intf;
-
-- cs_desc = snd_usb_find_clock_source(chip, clock, fmt->protocol);
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
-+ cs_desc = snd_usb_find_clock_source(chip, clock, fmt);
-
- if (!cs_desc)
- return 0;
-@@ -522,7 +538,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
- err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- &data, sizeof(data));
- if (err < 0)
- return err;
-diff --git a/sound/usb/format.c b/sound/usb/format.c
-index 3b45d0ee76938..61c4aca8be09e 100644
---- a/sound/usb/format.c
-+++ b/sound/usb/format.c
-@@ -548,7 +548,9 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
- unsigned char tmp[2], *data;
- int nr_triplets, data_size, ret = 0, ret_l6;
- int clock = snd_usb_clock_find_source(chip, fp, false);
-+ struct usb_host_interface *ctrl_intf;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fp->iface);
- if (clock < 0) {
- dev_err(&dev->dev,
- "%s(): unable to find clock source (clock %d)\n",
-@@ -560,7 +562,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
- ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- tmp, sizeof(tmp));
-
- if (ret < 0) {
-@@ -595,7 +597,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
- ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- data, data_size);
-
- if (ret < 0) {
-diff --git a/sound/usb/helper.c b/sound/usb/helper.c
-index a4410267bf701..f582a2ced3fd1 100644
---- a/sound/usb/helper.c
-+++ b/sound/usb/helper.c
-@@ -131,3 +131,37 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting
- return NULL;
- return usb_altnum_to_altsetting(iface, altsetting);
- }
-+
-+int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
-+ int ctrlif)
-+{
-+ struct usb_device *dev = chip->dev;
-+ struct usb_host_interface *host_iface;
-+
-+ if (chip->num_intf_to_ctrl >= MAX_CARD_INTERFACES) {
-+ dev_info(&dev->dev, "Too many interfaces assigned to the single USB-audio card\n");
-+ return -EINVAL;
-+ }
-+
-+ /* find audiocontrol interface */
-+ host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
-+
-+ chip->intf_to_ctrl[chip->num_intf_to_ctrl].interface = ifnum;
-+ chip->intf_to_ctrl[chip->num_intf_to_ctrl].ctrl_intf = host_iface;
-+ chip->num_intf_to_ctrl++;
-+
-+ return 0;
-+}
-+
-+struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
-+ int ifnum)
-+{
-+ int i;
-+
-+ for (i = 0; i < chip->num_intf_to_ctrl; ++i)
-+ if (chip->intf_to_ctrl[i].interface == ifnum)
-+ return chip->intf_to_ctrl[i].ctrl_intf;
-+
-+ /* Fallback to first audiocontrol interface */
-+ return chip->ctrl_intf;
-+}
-diff --git a/sound/usb/helper.h b/sound/usb/helper.h
-index e2b51ec96ec62..0372e050b3dc4 100644
---- a/sound/usb/helper.h
-+++ b/sound/usb/helper.h
-@@ -17,6 +17,12 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
- struct usb_host_interface *
- snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting);
-
-+int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
-+ int ctrlif);
-+
-+struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
-+ int ifnum);
-+
- /*
- * retrieve usb_interface descriptor from the host interface
- * (conditional for compatibility with the older API)
-@@ -28,9 +34,9 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting
-
- #define snd_usb_get_speed(dev) ((dev)->speed)
-
--static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip)
-+static inline int snd_usb_ctrl_intf(struct usb_host_interface *ctrl_intf)
- {
-- return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber;
-+ return get_iface_desc(ctrl_intf)->bInterfaceNumber;
- }
-
- /* in validate.c */
-diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
-index 49facdf35b159..7bda8e9a93deb 100644
---- a/sound/usb/mixer.c
-+++ b/sound/usb/mixer.c
-@@ -728,7 +728,7 @@ static int get_cluster_channels_v3(struct mixer_build *state, unsigned int clust
- UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- cluster_id,
-- snd_usb_ctrl_intf(state->chip),
-+ snd_usb_ctrl_intf(state->mixer->hostif),
- &c_header, sizeof(c_header));
- if (err < 0)
- goto error;
-diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
-index c8d48566e1759..2323504339328 100644
---- a/sound/usb/mixer_quirks.c
-+++ b/sound/usb/mixer_quirks.c
-@@ -1043,7 +1043,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer,
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- pval & 0xff00,
-- snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8),
-+ snd_usb_ctrl_intf(mixer->hostif) | ((pval & 0xff) << 8),
- value, 2);
- if (err < 0)
- return err;
-@@ -1077,7 +1077,7 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list)
- UAC_SET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- pval & 0xff00,
-- snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8),
-+ snd_usb_ctrl_intf(list->mixer->hostif) | ((pval & 0xff) << 8),
- value, 2);
- snd_usb_unlock_shutdown(chip);
- return err;
-@@ -2115,24 +2115,25 @@ static int dell_dock_mixer_create(struct usb_mixer_interface *mixer)
- return 0;
- }
-
--static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id)
-+static void dell_dock_init_vol(struct usb_mixer_interface *mixer, int ch, int id)
- {
-+ struct snd_usb_audio *chip = mixer->chip;
- u16 buf = 0;
-
- snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- (UAC_FU_VOLUME << 8) | ch,
-- snd_usb_ctrl_intf(chip) | (id << 8),
-+ snd_usb_ctrl_intf(mixer->hostif) | (id << 8),
- &buf, 2);
- }
-
- static int dell_dock_mixer_init(struct usb_mixer_interface *mixer)
- {
- /* fix to 0dB playback volumes */
-- dell_dock_init_vol(mixer->chip, 1, 16);
-- dell_dock_init_vol(mixer->chip, 2, 16);
-- dell_dock_init_vol(mixer->chip, 1, 19);
-- dell_dock_init_vol(mixer->chip, 2, 19);
-+ dell_dock_init_vol(mixer, 1, 16);
-+ dell_dock_init_vol(mixer, 2, 16);
-+ dell_dock_init_vol(mixer, 1, 19);
-+ dell_dock_init_vol(mixer, 2, 19);
- return 0;
- }
-
-diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
-index 0d6e4f15bf77c..ff548041679bb 100644
---- a/sound/usb/mixer_scarlett.c
-+++ b/sound/usb/mixer_scarlett.c
-@@ -460,7 +460,7 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
- struct snd_usb_audio *chip = elem->head.mixer->chip;
- unsigned char buf[2 * MAX_CHANNELS] = {0, };
- int wValue = (elem->control << 8) | elem->idx_off;
-- int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
-+ int idx = snd_usb_ctrl_intf(elem->head.mixer->hostif) | (elem->head.id << 8);
- int err;
-
- err = snd_usb_ctl_msg(chip->dev,
-@@ -1002,7 +1002,7 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS |
-- USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) |
-+ USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->hostif) |
- (0x29 << 8), sample_rate_buffer, 4);
- if (err < 0)
- return err;
-diff --git a/sound/usb/power.c b/sound/usb/power.c
-index 606a2cb23eab6..66bd4daa68fd5 100644
---- a/sound/usb/power.c
-+++ b/sound/usb/power.c
-@@ -40,6 +40,7 @@ snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface,
- le16_to_cpu(pd_desc->waRecoveryTime1);
- pd->pd_d2d0_rec =
- le16_to_cpu(pd_desc->waRecoveryTime2);
-+ pd->ctrl_iface = ctrl_iface;
- return pd;
- }
- }
-@@ -57,7 +58,7 @@ int snd_usb_power_domain_set(struct snd_usb_audio *chip,
- unsigned char current_state;
- int err, idx;
-
-- idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8);
-+ idx = snd_usb_ctrl_intf(pd->ctrl_iface) | (pd->pd_id << 8);
-
- err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
- UAC2_CS_CUR,
-diff --git a/sound/usb/power.h b/sound/usb/power.h
-index 396e3e51440a7..1fa92ad0ca925 100644
---- a/sound/usb/power.h
-+++ b/sound/usb/power.h
-@@ -6,6 +6,7 @@ struct snd_usb_power_domain {
- int pd_id; /* UAC3 Power Domain ID */
- int pd_d1d0_rec; /* D1 to D0 recovery time */
- int pd_d2d0_rec; /* D2 to D0 recovery time */
-+ struct usb_host_interface *ctrl_iface; /* Control interface */
- };
-
- enum {
-diff --git a/sound/usb/stream.c b/sound/usb/stream.c
-index e14c725acebf2..d70c140813d68 100644
---- a/sound/usb/stream.c
-+++ b/sound/usb/stream.c
-@@ -713,10 +713,13 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
- struct usb_device *dev = chip->dev;
- struct uac_format_type_i_continuous_descriptor *fmt;
- unsigned int num_channels = 0, chconfig = 0;
-+ struct usb_host_interface *ctrl_intf;
- struct audioformat *fp;
- int clock = 0;
- u64 format;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
-+
- /* get audio formats */
- if (protocol == UAC_VERSION_1) {
- struct uac1_as_header_descriptor *as =
-@@ -740,7 +743,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
-
- format = le16_to_cpu(as->wFormatTag); /* remember the format value */
-
-- iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
-+ iterm = snd_usb_find_input_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- protocol);
- if (iterm) {
-@@ -776,7 +779,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
- * lookup the terminal associated to this interface
- * to extract the clock
- */
-- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
-+ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- protocol);
- if (input_term) {
-@@ -786,7 +789,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
- goto found_clock;
- }
-
-- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
-+ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- protocol);
- if (output_term) {
-@@ -870,6 +873,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- struct uac3_cluster_header_descriptor *cluster;
- struct uac3_as_header_descriptor *as = NULL;
- struct uac3_hc_descriptor_header hc_header;
-+ struct usb_host_interface *ctrl_intf;
- struct snd_pcm_chmap_elem *chmap;
- struct snd_usb_power_domain *pd;
- unsigned char badd_profile;
-@@ -881,6 +885,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- int err;
-
- badd_profile = chip->badd_profile;
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
-
- if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
- unsigned int maxpacksize =
-@@ -966,7 +971,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- cluster_id,
-- snd_usb_ctrl_intf(chip),
-+ snd_usb_ctrl_intf(ctrl_intf),
- &hc_header, sizeof(hc_header));
- if (err < 0)
- return ERR_PTR(err);
-@@ -990,7 +995,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- cluster_id,
-- snd_usb_ctrl_intf(chip),
-+ snd_usb_ctrl_intf(ctrl_intf),
- cluster, wLength);
- if (err < 0) {
- kfree(cluster);
-@@ -1011,7 +1016,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- * lookup the terminal associated to this interface
- * to extract the clock
- */
-- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
-+ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- UAC_VERSION_3);
- if (input_term) {
-@@ -1019,7 +1024,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- goto found_clock;
- }
-
-- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
-+ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- UAC_VERSION_3);
- if (output_term) {
-@@ -1068,7 +1073,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- UAC_VERSION_3,
- iface_no);
-
-- pd = snd_usb_find_power_domain(chip->ctrl_intf,
-+ pd = snd_usb_find_power_domain(ctrl_intf,
- as->bTerminalLink);
-
- /* ok, let's parse further... */
-diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
-index f5a8dca66457f..1f56a07827aa7 100644
---- a/sound/usb/usbaudio.h
-+++ b/sound/usb/usbaudio.h
-@@ -21,6 +21,15 @@ struct media_intf_devnode;
-
- #define MAX_CARD_INTERFACES 16
-
-+/*
-+ * Structure holding assosiation between Audio Control Interface
-+ * and given Streaming or Midi Interface.
-+ */
-+struct snd_intf_to_ctrl {
-+ u8 interface;
-+ struct usb_host_interface *ctrl_intf;
-+};
-+
- struct snd_usb_audio {
- int index;
- struct usb_device *dev;
-@@ -61,6 +70,9 @@ struct snd_usb_audio {
- struct usb_host_interface *ctrl_intf; /* the audio control interface */
- struct media_device *media_dev;
- struct media_intf_devnode *ctl_intf_media_devnode;
-+
-+ unsigned int num_intf_to_ctrl;
-+ struct snd_intf_to_ctrl intf_to_ctrl[MAX_CARD_INTERFACES];
- };
-
- #define USB_AUDIO_IFACE_UNUSED ((void *)-1L)
---
-2.43.0
-
nfp-use-irqf_no_autoen-flag-in-request_irq.patch
alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch
x86-ioapic-handle-allocation-failures-gracefully.patch
-alsa-usb-audio-support-multiple-control-interfaces.patch
alsa-usb-audio-define-macros-for-quirk-table-entries.patch
alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch
alsa-usb-audio-add-logitech-audio-profile-quirk.patch
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- sound/usb/card.c | 6 ++++++
+ sound/usb/card.c | 6 ++++++
1 file changed, 6 insertions(+)
-diff --git a/sound/usb/card.c b/sound/usb/card.c
-index 778de9244f1e7..9c411b82a218d 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
-@@ -384,6 +384,12 @@ static const struct usb_audio_device_name usb_audio_names[] = {
+@@ -382,6 +382,12 @@ static const struct usb_audio_device_nam
/* Creative/Toshiba Multimedia Center SB-0500 */
DEVICE_NAME(0x041e, 0x3048, "Toshiba", "SB-0500"),
DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"),
DEVICE_NAME(0x05e1, 0x0408, "Syntek", "STK1160"),
---
-2.43.0
-
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- sound/usb/mixer_quirks.c | 413 +++++++++++++++++++++++++++++++++++++++
- sound/usb/quirks-table.h | 1 +
+ sound/usb/mixer_quirks.c | 413 +++++++++++++++++++++++++++++++++++++++++++++++
+ sound/usb/quirks-table.h | 1
2 files changed, 414 insertions(+)
-diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
-index 1d8bf1ecfed44..3727dbd123597 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -14,6 +14,7 @@
#include <linux/hid.h>
#include <linux/init.h>
#include <linux/math64.h>
-@@ -2926,6 +2927,415 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer)
- return 0;
+@@ -2926,6 +2927,415 @@ static int snd_bbfpro_controls_create(st
}
-+/*
+ /*
+ * RME Digiface USB
+ */
+
+ return 0;
+}
+
- /*
++/*
* Pioneer DJ DJM Mixers
*
-@@ -3484,6 +3894,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
+ * These devices generally have options for soft-switching the playback and
+@@ -3483,6 +3893,9 @@ int snd_usb_mixer_apply_create_quirk(str
case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */
err = snd_bbfpro_controls_create(mixer);
break;
case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
err = snd_djm_controls_create(mixer, SND_DJM_250MK2_IDX);
break;
-diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
-index 631b9ab80f6cd..24c981c9b2405 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -3620,6 +3620,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
{
QUIRK_DATA_AUDIOFORMAT(0) {
.formats = SNDRV_PCM_FMTBIT_S32_LE,
---
-2.43.0
-
+++ /dev/null
-From 1900d66454dede84d5e1cdca46b1443b272293a3 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 11 Aug 2024 17:29:56 -0700
-Subject: ALSA: usb-audio: Support multiple control interfaces
-
-From: Karol Kosik <k.kosik@outlook.com>
-
-[ Upstream commit 6aa8700150f7dc62f60b4cf5b1624e2e3d9ed78e ]
-
-Registering Numark Party Mix II fails with error 'bogus bTerminalLink 1'.
-The problem stems from the driver not being able to find input/output
-terminals required to configure audio streaming. The information about
-those terminals is stored in AudioControl Interface. Numark device
-contains 2 AudioControl Interfaces and the driver checks only one of them.
-
-According to the USB standard, a device can have multiple audio functions,
-each represented by Audio Interface Collection. Every audio function is
-considered to be closed box and will contain unique AudioControl Interface
-and zero or more AudioStreaming and MIDIStreaming Interfaces.
-
-The Numark device adheres to the standard and defines two audio functions:
-- MIDIStreaming function
-- AudioStreaming function
-It starts with MIDI function, followed by the audio function. The driver
-saves the first AudioControl Interface in `snd_usb_audio` structure
-associated with the entire device. It then attempts to use this interface
-to query for terminals and clocks. However, this fails because the correct
-information is stored in the second AudioControl Interface, defined in the
-second Audio Interface Collection.
-
-This patch introduces a structure holding association between each
-MIDI/Audio Interface and its corresponding AudioControl Interface,
-instead of relying on AudioControl Interface defined for the entire
-device. This structure is populated during usb probing phase and leveraged
-later when querying for terminals and when sending USB requests.
-
-Alternative solutions considered include:
-- defining a quirk for Numark where the order of interface is manually
-changed, or terminals are hardcoded in the driver. This solution would
-have fixed only this model, though it seems that device is USB compliant,
-and it also seems that other devices from this company may be affected.
-What's more, it looks like products from other manufacturers have similar
-problems, i.e. Rane One DJ console
-- keeping a list of all AudioControl Interfaces and querying all of them
-to find required information. That would have solved my problem and have
-low probability of breaking other devices, as we would always start with
-the same logic of querying first AudioControl Interface. This solution
-would not have followed the standard though.
-
-This patch preserves the `snd_usb_audio.ctrl_intf` variable, which holds
-the first AudioControl Interface, and uses it as a fallback when some
-interfaces are not parsed correctly and lack an associated AudioControl
-Interface, i.e., when configured via quirks.
-
-Link: https://bugzilla.kernel.org/show_bug.cgi?id=217865
-Signed-off-by: Karol Kosik <k.kosik@outlook.com>
-Link: https://patch.msgid.link/AS8P190MB1285893F4735C8B32AD3886BEC852@AS8P190MB1285.EURP190.PROD.OUTLOOK.COM
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- sound/usb/card.c | 2 ++
- sound/usb/clock.c | 62 ++++++++++++++++++++++++--------------
- sound/usb/format.c | 6 ++--
- sound/usb/helper.c | 34 +++++++++++++++++++++
- sound/usb/helper.h | 10 ++++--
- sound/usb/mixer.c | 2 +-
- sound/usb/mixer_quirks.c | 17 ++++++-----
- sound/usb/mixer_scarlett.c | 4 +--
- sound/usb/power.c | 3 +-
- sound/usb/power.h | 1 +
- sound/usb/stream.c | 21 ++++++++-----
- sound/usb/usbaudio.h | 12 ++++++++
- 12 files changed, 127 insertions(+), 47 deletions(-)
-
-diff --git a/sound/usb/card.c b/sound/usb/card.c
-index bdb04fa37a71d..778de9244f1e7 100644
---- a/sound/usb/card.c
-+++ b/sound/usb/card.c
-@@ -206,6 +206,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
- return -EINVAL;
- }
-
-+ snd_usb_add_ctrl_interface_link(chip, interface, ctrlif);
-+
- if (! snd_usb_parse_audio_interface(chip, interface)) {
- usb_set_interface(dev, interface, 0); /* reset the current interface */
- return usb_driver_claim_interface(&usb_audio_driver, iface,
-diff --git a/sound/usb/clock.c b/sound/usb/clock.c
-index 60fcb872a80b6..8f85200292f3f 100644
---- a/sound/usb/clock.c
-+++ b/sound/usb/clock.c
-@@ -76,11 +76,14 @@ static bool validate_clock_multiplier(void *p, int id, int proto)
- }
-
- #define DEFINE_FIND_HELPER(name, obj, validator, type2, type3) \
--static obj *name(struct snd_usb_audio *chip, int id, int proto) \
-+static obj *name(struct snd_usb_audio *chip, int id, \
-+ const struct audioformat *fmt) \
- { \
-- return find_uac_clock_desc(chip->ctrl_intf, id, validator, \
-- proto == UAC_VERSION_3 ? (type3) : (type2), \
-- proto); \
-+ struct usb_host_interface *ctrl_intf = \
-+ snd_usb_find_ctrl_interface(chip, fmt->iface); \
-+ return find_uac_clock_desc(ctrl_intf, id, validator, \
-+ fmt->protocol == UAC_VERSION_3 ? (type3) : (type2), \
-+ fmt->protocol); \
- }
-
- DEFINE_FIND_HELPER(snd_usb_find_clock_source,
-@@ -93,16 +96,19 @@ DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier,
- union uac23_clock_multiplier_desc, validate_clock_multiplier,
- UAC2_CLOCK_MULTIPLIER, UAC3_CLOCK_MULTIPLIER);
-
--static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
-+static int uac_clock_selector_get_val(struct snd_usb_audio *chip,
-+ int selector_id, int iface_no)
- {
-+ struct usb_host_interface *ctrl_intf;
- unsigned char buf;
- int ret;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
- ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
- UAC2_CS_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- UAC2_CX_CLOCK_SELECTOR << 8,
-- snd_usb_ctrl_intf(chip) | (selector_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8),
- &buf, sizeof(buf));
-
- if (ret < 0)
-@@ -111,16 +117,18 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i
- return buf;
- }
-
--static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
-- unsigned char pin)
-+static int uac_clock_selector_set_val(struct snd_usb_audio *chip,
-+ int selector_id, unsigned char pin, int iface_no)
- {
-+ struct usb_host_interface *ctrl_intf;
- int ret;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
- ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
- UAC2_CS_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- UAC2_CX_CLOCK_SELECTOR << 8,
-- snd_usb_ctrl_intf(chip) | (selector_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8),
- &pin, sizeof(pin));
- if (ret < 0)
- return ret;
-@@ -132,7 +140,7 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i
- return -EINVAL;
- }
-
-- ret = uac_clock_selector_get_val(chip, selector_id);
-+ ret = uac_clock_selector_get_val(chip, selector_id, iface_no);
- if (ret < 0)
- return ret;
-
-@@ -155,8 +163,10 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
- unsigned char data;
- struct usb_device *dev = chip->dev;
- union uac23_clock_source_desc *cs_desc;
-+ struct usb_host_interface *ctrl_intf;
-
-- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol);
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
-+ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt);
- if (!cs_desc)
- return false;
-
-@@ -191,7 +201,7 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_CLOCK_VALID << 8,
-- snd_usb_ctrl_intf(chip) | (source_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8),
- &data, sizeof(data));
- if (err < 0) {
- dev_warn(&dev->dev,
-@@ -217,8 +227,10 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
- struct usb_device *dev = chip->dev;
- u32 bmControls;
- union uac23_clock_source_desc *cs_desc;
-+ struct usb_host_interface *ctrl_intf;
-
-- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol);
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
-+ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt);
- if (!cs_desc)
- return false;
-
-@@ -235,7 +247,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_CLOCK_VALID << 8,
-- snd_usb_ctrl_intf(chip) | (source_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8),
- &data, sizeof(data));
-
- if (err < 0) {
-@@ -274,7 +286,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- }
-
- /* first, see if the ID we're looking at is a clock source already */
-- source = snd_usb_find_clock_source(chip, entity_id, proto);
-+ source = snd_usb_find_clock_source(chip, entity_id, fmt);
- if (source) {
- entity_id = GET_VAL(source, proto, bClockID);
- if (validate && !uac_clock_source_is_valid(chip, fmt,
-@@ -287,7 +299,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- return entity_id;
- }
-
-- selector = snd_usb_find_clock_selector(chip, entity_id, proto);
-+ selector = snd_usb_find_clock_selector(chip, entity_id, fmt);
- if (selector) {
- pins = GET_VAL(selector, proto, bNrInPins);
- clock_id = GET_VAL(selector, proto, bClockID);
-@@ -317,7 +329,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
-
- /* the entity ID we are looking at is a selector.
- * find out what it currently selects */
-- ret = uac_clock_selector_get_val(chip, clock_id);
-+ ret = uac_clock_selector_get_val(chip, clock_id, fmt->iface);
- if (ret < 0) {
- if (!chip->autoclock)
- return ret;
-@@ -346,7 +358,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR ||
- !writeable)
- return ret;
-- err = uac_clock_selector_set_val(chip, entity_id, cur);
-+ err = uac_clock_selector_set_val(chip, entity_id, cur, fmt->iface);
- if (err < 0) {
- if (pins == 1) {
- usb_audio_dbg(chip,
-@@ -377,7 +389,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- if (ret < 0)
- continue;
-
-- err = uac_clock_selector_set_val(chip, entity_id, i);
-+ err = uac_clock_selector_set_val(chip, entity_id, i, fmt->iface);
- if (err < 0)
- continue;
-
-@@ -391,7 +403,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- }
-
- /* FIXME: multipliers only act as pass-thru element for now */
-- multiplier = snd_usb_find_clock_multiplier(chip, entity_id, proto);
-+ multiplier = snd_usb_find_clock_multiplier(chip, entity_id, fmt);
- if (multiplier)
- return __uac_clock_find_source(chip, fmt,
- GET_VAL(multiplier, proto, bCSourceID),
-@@ -491,11 +503,13 @@ static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
- struct usb_device *dev = chip->dev;
- __le32 data;
- int err;
-+ struct usb_host_interface *ctrl_intf;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface);
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- &data, sizeof(data));
- if (err < 0) {
- dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n",
-@@ -524,8 +538,10 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
- __le32 data;
- int err;
- union uac23_clock_source_desc *cs_desc;
-+ struct usb_host_interface *ctrl_intf;
-
-- cs_desc = snd_usb_find_clock_source(chip, clock, fmt->protocol);
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
-+ cs_desc = snd_usb_find_clock_source(chip, clock, fmt);
-
- if (!cs_desc)
- return 0;
-@@ -544,7 +560,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
- err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- &data, sizeof(data));
- if (err < 0)
- return err;
-diff --git a/sound/usb/format.c b/sound/usb/format.c
-index 3b45d0ee76938..61c4aca8be09e 100644
---- a/sound/usb/format.c
-+++ b/sound/usb/format.c
-@@ -548,7 +548,9 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
- unsigned char tmp[2], *data;
- int nr_triplets, data_size, ret = 0, ret_l6;
- int clock = snd_usb_clock_find_source(chip, fp, false);
-+ struct usb_host_interface *ctrl_intf;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fp->iface);
- if (clock < 0) {
- dev_err(&dev->dev,
- "%s(): unable to find clock source (clock %d)\n",
-@@ -560,7 +562,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
- ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- tmp, sizeof(tmp));
-
- if (ret < 0) {
-@@ -595,7 +597,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
- ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- data, data_size);
-
- if (ret < 0) {
-diff --git a/sound/usb/helper.c b/sound/usb/helper.c
-index bf80e55d013a8..72b671fb2c84c 100644
---- a/sound/usb/helper.c
-+++ b/sound/usb/helper.c
-@@ -130,3 +130,37 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting
- return NULL;
- return usb_altnum_to_altsetting(iface, altsetting);
- }
-+
-+int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
-+ int ctrlif)
-+{
-+ struct usb_device *dev = chip->dev;
-+ struct usb_host_interface *host_iface;
-+
-+ if (chip->num_intf_to_ctrl >= MAX_CARD_INTERFACES) {
-+ dev_info(&dev->dev, "Too many interfaces assigned to the single USB-audio card\n");
-+ return -EINVAL;
-+ }
-+
-+ /* find audiocontrol interface */
-+ host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
-+
-+ chip->intf_to_ctrl[chip->num_intf_to_ctrl].interface = ifnum;
-+ chip->intf_to_ctrl[chip->num_intf_to_ctrl].ctrl_intf = host_iface;
-+ chip->num_intf_to_ctrl++;
-+
-+ return 0;
-+}
-+
-+struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
-+ int ifnum)
-+{
-+ int i;
-+
-+ for (i = 0; i < chip->num_intf_to_ctrl; ++i)
-+ if (chip->intf_to_ctrl[i].interface == ifnum)
-+ return chip->intf_to_ctrl[i].ctrl_intf;
-+
-+ /* Fallback to first audiocontrol interface */
-+ return chip->ctrl_intf;
-+}
-diff --git a/sound/usb/helper.h b/sound/usb/helper.h
-index e2b51ec96ec62..0372e050b3dc4 100644
---- a/sound/usb/helper.h
-+++ b/sound/usb/helper.h
-@@ -17,6 +17,12 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
- struct usb_host_interface *
- snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting);
-
-+int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
-+ int ctrlif);
-+
-+struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
-+ int ifnum);
-+
- /*
- * retrieve usb_interface descriptor from the host interface
- * (conditional for compatibility with the older API)
-@@ -28,9 +34,9 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting
-
- #define snd_usb_get_speed(dev) ((dev)->speed)
-
--static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip)
-+static inline int snd_usb_ctrl_intf(struct usb_host_interface *ctrl_intf)
- {
-- return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber;
-+ return get_iface_desc(ctrl_intf)->bInterfaceNumber;
- }
-
- /* in validate.c */
-diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
-index 197fd07e69edd..017b50322d88f 100644
---- a/sound/usb/mixer.c
-+++ b/sound/usb/mixer.c
-@@ -728,7 +728,7 @@ static int get_cluster_channels_v3(struct mixer_build *state, unsigned int clust
- UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- cluster_id,
-- snd_usb_ctrl_intf(state->chip),
-+ snd_usb_ctrl_intf(state->mixer->hostif),
- &c_header, sizeof(c_header));
- if (err < 0)
- goto error;
-diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
-index 212b5e6443d88..1d8bf1ecfed44 100644
---- a/sound/usb/mixer_quirks.c
-+++ b/sound/usb/mixer_quirks.c
-@@ -1043,7 +1043,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer,
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- pval & 0xff00,
-- snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8),
-+ snd_usb_ctrl_intf(mixer->hostif) | ((pval & 0xff) << 8),
- value, 2);
- if (err < 0)
- return err;
-@@ -1077,7 +1077,7 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list)
- UAC_SET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- pval & 0xff00,
-- snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8),
-+ snd_usb_ctrl_intf(list->mixer->hostif) | ((pval & 0xff) << 8),
- value, 2);
- snd_usb_unlock_shutdown(chip);
- return err;
-@@ -2115,24 +2115,25 @@ static int dell_dock_mixer_create(struct usb_mixer_interface *mixer)
- return 0;
- }
-
--static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id)
-+static void dell_dock_init_vol(struct usb_mixer_interface *mixer, int ch, int id)
- {
-+ struct snd_usb_audio *chip = mixer->chip;
- u16 buf = 0;
-
- snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- (UAC_FU_VOLUME << 8) | ch,
-- snd_usb_ctrl_intf(chip) | (id << 8),
-+ snd_usb_ctrl_intf(mixer->hostif) | (id << 8),
- &buf, 2);
- }
-
- static int dell_dock_mixer_init(struct usb_mixer_interface *mixer)
- {
- /* fix to 0dB playback volumes */
-- dell_dock_init_vol(mixer->chip, 1, 16);
-- dell_dock_init_vol(mixer->chip, 2, 16);
-- dell_dock_init_vol(mixer->chip, 1, 19);
-- dell_dock_init_vol(mixer->chip, 2, 19);
-+ dell_dock_init_vol(mixer, 1, 16);
-+ dell_dock_init_vol(mixer, 2, 16);
-+ dell_dock_init_vol(mixer, 1, 19);
-+ dell_dock_init_vol(mixer, 2, 19);
- return 0;
- }
-
-diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
-index 0d6e4f15bf77c..ff548041679bb 100644
---- a/sound/usb/mixer_scarlett.c
-+++ b/sound/usb/mixer_scarlett.c
-@@ -460,7 +460,7 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
- struct snd_usb_audio *chip = elem->head.mixer->chip;
- unsigned char buf[2 * MAX_CHANNELS] = {0, };
- int wValue = (elem->control << 8) | elem->idx_off;
-- int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
-+ int idx = snd_usb_ctrl_intf(elem->head.mixer->hostif) | (elem->head.id << 8);
- int err;
-
- err = snd_usb_ctl_msg(chip->dev,
-@@ -1002,7 +1002,7 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS |
-- USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) |
-+ USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->hostif) |
- (0x29 << 8), sample_rate_buffer, 4);
- if (err < 0)
- return err;
-diff --git a/sound/usb/power.c b/sound/usb/power.c
-index 606a2cb23eab6..66bd4daa68fd5 100644
---- a/sound/usb/power.c
-+++ b/sound/usb/power.c
-@@ -40,6 +40,7 @@ snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface,
- le16_to_cpu(pd_desc->waRecoveryTime1);
- pd->pd_d2d0_rec =
- le16_to_cpu(pd_desc->waRecoveryTime2);
-+ pd->ctrl_iface = ctrl_iface;
- return pd;
- }
- }
-@@ -57,7 +58,7 @@ int snd_usb_power_domain_set(struct snd_usb_audio *chip,
- unsigned char current_state;
- int err, idx;
-
-- idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8);
-+ idx = snd_usb_ctrl_intf(pd->ctrl_iface) | (pd->pd_id << 8);
-
- err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
- UAC2_CS_CUR,
-diff --git a/sound/usb/power.h b/sound/usb/power.h
-index 396e3e51440a7..1fa92ad0ca925 100644
---- a/sound/usb/power.h
-+++ b/sound/usb/power.h
-@@ -6,6 +6,7 @@ struct snd_usb_power_domain {
- int pd_id; /* UAC3 Power Domain ID */
- int pd_d1d0_rec; /* D1 to D0 recovery time */
- int pd_d2d0_rec; /* D2 to D0 recovery time */
-+ struct usb_host_interface *ctrl_iface; /* Control interface */
- };
-
- enum {
-diff --git a/sound/usb/stream.c b/sound/usb/stream.c
-index e14c725acebf2..d70c140813d68 100644
---- a/sound/usb/stream.c
-+++ b/sound/usb/stream.c
-@@ -713,10 +713,13 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
- struct usb_device *dev = chip->dev;
- struct uac_format_type_i_continuous_descriptor *fmt;
- unsigned int num_channels = 0, chconfig = 0;
-+ struct usb_host_interface *ctrl_intf;
- struct audioformat *fp;
- int clock = 0;
- u64 format;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
-+
- /* get audio formats */
- if (protocol == UAC_VERSION_1) {
- struct uac1_as_header_descriptor *as =
-@@ -740,7 +743,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
-
- format = le16_to_cpu(as->wFormatTag); /* remember the format value */
-
-- iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
-+ iterm = snd_usb_find_input_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- protocol);
- if (iterm) {
-@@ -776,7 +779,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
- * lookup the terminal associated to this interface
- * to extract the clock
- */
-- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
-+ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- protocol);
- if (input_term) {
-@@ -786,7 +789,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
- goto found_clock;
- }
-
-- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
-+ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- protocol);
- if (output_term) {
-@@ -870,6 +873,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- struct uac3_cluster_header_descriptor *cluster;
- struct uac3_as_header_descriptor *as = NULL;
- struct uac3_hc_descriptor_header hc_header;
-+ struct usb_host_interface *ctrl_intf;
- struct snd_pcm_chmap_elem *chmap;
- struct snd_usb_power_domain *pd;
- unsigned char badd_profile;
-@@ -881,6 +885,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- int err;
-
- badd_profile = chip->badd_profile;
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
-
- if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
- unsigned int maxpacksize =
-@@ -966,7 +971,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- cluster_id,
-- snd_usb_ctrl_intf(chip),
-+ snd_usb_ctrl_intf(ctrl_intf),
- &hc_header, sizeof(hc_header));
- if (err < 0)
- return ERR_PTR(err);
-@@ -990,7 +995,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- cluster_id,
-- snd_usb_ctrl_intf(chip),
-+ snd_usb_ctrl_intf(ctrl_intf),
- cluster, wLength);
- if (err < 0) {
- kfree(cluster);
-@@ -1011,7 +1016,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- * lookup the terminal associated to this interface
- * to extract the clock
- */
-- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
-+ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- UAC_VERSION_3);
- if (input_term) {
-@@ -1019,7 +1024,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- goto found_clock;
- }
-
-- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
-+ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- UAC_VERSION_3);
- if (output_term) {
-@@ -1068,7 +1073,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- UAC_VERSION_3,
- iface_no);
-
-- pd = snd_usb_find_power_domain(chip->ctrl_intf,
-+ pd = snd_usb_find_power_domain(ctrl_intf,
- as->bTerminalLink);
-
- /* ok, let's parse further... */
-diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
-index 43d4029edab46..b0f042c996087 100644
---- a/sound/usb/usbaudio.h
-+++ b/sound/usb/usbaudio.h
-@@ -21,6 +21,15 @@ struct media_intf_devnode;
-
- #define MAX_CARD_INTERFACES 16
-
-+/*
-+ * Structure holding assosiation between Audio Control Interface
-+ * and given Streaming or Midi Interface.
-+ */
-+struct snd_intf_to_ctrl {
-+ u8 interface;
-+ struct usb_host_interface *ctrl_intf;
-+};
-+
- struct snd_usb_audio {
- int index;
- struct usb_device *dev;
-@@ -63,6 +72,9 @@ struct snd_usb_audio {
- struct usb_host_interface *ctrl_intf; /* the audio control interface */
- struct media_device *media_dev;
- struct media_intf_devnode *ctl_intf_media_devnode;
-+
-+ unsigned int num_intf_to_ctrl;
-+ struct snd_intf_to_ctrl intf_to_ctrl[MAX_CARD_INTERFACES];
- };
-
- #define USB_AUDIO_IFACE_UNUSED ((void *)-1L)
---
-2.43.0
-
alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch
x86-ioapic-handle-allocation-failures-gracefully.patch
x86-apic-remove-logical-destination-mode-for-64-bit.patch
-alsa-usb-audio-support-multiple-control-interfaces.patch
alsa-usb-audio-define-macros-for-quirk-table-entries.patch
alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch
alsa-usb-audio-add-quirk-for-rme-digiface-usb.patch
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- sound/usb/card.c | 6 ++++++
+ sound/usb/card.c | 6 ++++++
1 file changed, 6 insertions(+)
-diff --git a/sound/usb/card.c b/sound/usb/card.c
-index 778de9244f1e7..9c411b82a218d 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
-@@ -384,6 +384,12 @@ static const struct usb_audio_device_name usb_audio_names[] = {
+@@ -382,6 +382,12 @@ static const struct usb_audio_device_nam
/* Creative/Toshiba Multimedia Center SB-0500 */
DEVICE_NAME(0x041e, 0x3048, "Toshiba", "SB-0500"),
DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"),
DEVICE_NAME(0x05e1, 0x0408, "Syntek", "STK1160"),
---
-2.43.0
-
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- sound/usb/mixer_quirks.c | 413 +++++++++++++++++++++++++++++++++++++++
- sound/usb/quirks-table.h | 1 +
+ sound/usb/mixer_quirks.c | 413 +++++++++++++++++++++++++++++++++++++++++++++++
+ sound/usb/quirks-table.h | 1
2 files changed, 414 insertions(+)
-diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
-index 8cbfb65846047..74abc44be77ca 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -14,6 +14,7 @@
#include <linux/hid.h>
#include <linux/init.h>
#include <linux/math64.h>
-@@ -2926,6 +2927,415 @@ static int snd_bbfpro_controls_create(struct usb_mixer_interface *mixer)
- return 0;
+@@ -2926,6 +2927,415 @@ static int snd_bbfpro_controls_create(st
}
-+/*
+ /*
+ * RME Digiface USB
+ */
+
+ return 0;
+}
+
- /*
++/*
* Pioneer DJ DJM Mixers
*
-@@ -3484,6 +3894,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
+ * These devices generally have options for soft-switching the playback and
+@@ -3483,6 +3893,9 @@ int snd_usb_mixer_apply_create_quirk(str
case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */
err = snd_bbfpro_controls_create(mixer);
break;
case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */
err = snd_djm_controls_create(mixer, SND_DJM_250MK2_IDX);
break;
-diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
-index 631b9ab80f6cd..24c981c9b2405 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -3620,6 +3620,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
{
QUIRK_DATA_AUDIOFORMAT(0) {
.formats = SNDRV_PCM_FMTBIT_S32_LE,
---
-2.43.0
-
+++ /dev/null
-From 0d5ff56702cf94d5a85af9d602ad1a4548d51eae Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 11 Aug 2024 17:29:56 -0700
-Subject: ALSA: usb-audio: Support multiple control interfaces
-
-From: Karol Kosik <k.kosik@outlook.com>
-
-[ Upstream commit 6aa8700150f7dc62f60b4cf5b1624e2e3d9ed78e ]
-
-Registering Numark Party Mix II fails with error 'bogus bTerminalLink 1'.
-The problem stems from the driver not being able to find input/output
-terminals required to configure audio streaming. The information about
-those terminals is stored in AudioControl Interface. Numark device
-contains 2 AudioControl Interfaces and the driver checks only one of them.
-
-According to the USB standard, a device can have multiple audio functions,
-each represented by Audio Interface Collection. Every audio function is
-considered to be closed box and will contain unique AudioControl Interface
-and zero or more AudioStreaming and MIDIStreaming Interfaces.
-
-The Numark device adheres to the standard and defines two audio functions:
-- MIDIStreaming function
-- AudioStreaming function
-It starts with MIDI function, followed by the audio function. The driver
-saves the first AudioControl Interface in `snd_usb_audio` structure
-associated with the entire device. It then attempts to use this interface
-to query for terminals and clocks. However, this fails because the correct
-information is stored in the second AudioControl Interface, defined in the
-second Audio Interface Collection.
-
-This patch introduces a structure holding association between each
-MIDI/Audio Interface and its corresponding AudioControl Interface,
-instead of relying on AudioControl Interface defined for the entire
-device. This structure is populated during usb probing phase and leveraged
-later when querying for terminals and when sending USB requests.
-
-Alternative solutions considered include:
-- defining a quirk for Numark where the order of interface is manually
-changed, or terminals are hardcoded in the driver. This solution would
-have fixed only this model, though it seems that device is USB compliant,
-and it also seems that other devices from this company may be affected.
-What's more, it looks like products from other manufacturers have similar
-problems, i.e. Rane One DJ console
-- keeping a list of all AudioControl Interfaces and querying all of them
-to find required information. That would have solved my problem and have
-low probability of breaking other devices, as we would always start with
-the same logic of querying first AudioControl Interface. This solution
-would not have followed the standard though.
-
-This patch preserves the `snd_usb_audio.ctrl_intf` variable, which holds
-the first AudioControl Interface, and uses it as a fallback when some
-interfaces are not parsed correctly and lack an associated AudioControl
-Interface, i.e., when configured via quirks.
-
-Link: https://bugzilla.kernel.org/show_bug.cgi?id=217865
-Signed-off-by: Karol Kosik <k.kosik@outlook.com>
-Link: https://patch.msgid.link/AS8P190MB1285893F4735C8B32AD3886BEC852@AS8P190MB1285.EURP190.PROD.OUTLOOK.COM
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- sound/usb/card.c | 2 ++
- sound/usb/clock.c | 62 ++++++++++++++++++++++++--------------
- sound/usb/format.c | 6 ++--
- sound/usb/helper.c | 34 +++++++++++++++++++++
- sound/usb/helper.h | 10 ++++--
- sound/usb/mixer.c | 2 +-
- sound/usb/mixer_quirks.c | 17 ++++++-----
- sound/usb/mixer_scarlett.c | 4 +--
- sound/usb/power.c | 3 +-
- sound/usb/power.h | 1 +
- sound/usb/stream.c | 21 ++++++++-----
- sound/usb/usbaudio.h | 12 ++++++++
- 12 files changed, 127 insertions(+), 47 deletions(-)
-
-diff --git a/sound/usb/card.c b/sound/usb/card.c
-index bdb04fa37a71d..778de9244f1e7 100644
---- a/sound/usb/card.c
-+++ b/sound/usb/card.c
-@@ -206,6 +206,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
- return -EINVAL;
- }
-
-+ snd_usb_add_ctrl_interface_link(chip, interface, ctrlif);
-+
- if (! snd_usb_parse_audio_interface(chip, interface)) {
- usb_set_interface(dev, interface, 0); /* reset the current interface */
- return usb_driver_claim_interface(&usb_audio_driver, iface,
-diff --git a/sound/usb/clock.c b/sound/usb/clock.c
-index 60fcb872a80b6..8f85200292f3f 100644
---- a/sound/usb/clock.c
-+++ b/sound/usb/clock.c
-@@ -76,11 +76,14 @@ static bool validate_clock_multiplier(void *p, int id, int proto)
- }
-
- #define DEFINE_FIND_HELPER(name, obj, validator, type2, type3) \
--static obj *name(struct snd_usb_audio *chip, int id, int proto) \
-+static obj *name(struct snd_usb_audio *chip, int id, \
-+ const struct audioformat *fmt) \
- { \
-- return find_uac_clock_desc(chip->ctrl_intf, id, validator, \
-- proto == UAC_VERSION_3 ? (type3) : (type2), \
-- proto); \
-+ struct usb_host_interface *ctrl_intf = \
-+ snd_usb_find_ctrl_interface(chip, fmt->iface); \
-+ return find_uac_clock_desc(ctrl_intf, id, validator, \
-+ fmt->protocol == UAC_VERSION_3 ? (type3) : (type2), \
-+ fmt->protocol); \
- }
-
- DEFINE_FIND_HELPER(snd_usb_find_clock_source,
-@@ -93,16 +96,19 @@ DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier,
- union uac23_clock_multiplier_desc, validate_clock_multiplier,
- UAC2_CLOCK_MULTIPLIER, UAC3_CLOCK_MULTIPLIER);
-
--static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
-+static int uac_clock_selector_get_val(struct snd_usb_audio *chip,
-+ int selector_id, int iface_no)
- {
-+ struct usb_host_interface *ctrl_intf;
- unsigned char buf;
- int ret;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
- ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
- UAC2_CS_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- UAC2_CX_CLOCK_SELECTOR << 8,
-- snd_usb_ctrl_intf(chip) | (selector_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8),
- &buf, sizeof(buf));
-
- if (ret < 0)
-@@ -111,16 +117,18 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i
- return buf;
- }
-
--static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
-- unsigned char pin)
-+static int uac_clock_selector_set_val(struct snd_usb_audio *chip,
-+ int selector_id, unsigned char pin, int iface_no)
- {
-+ struct usb_host_interface *ctrl_intf;
- int ret;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
- ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
- UAC2_CS_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- UAC2_CX_CLOCK_SELECTOR << 8,
-- snd_usb_ctrl_intf(chip) | (selector_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8),
- &pin, sizeof(pin));
- if (ret < 0)
- return ret;
-@@ -132,7 +140,7 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i
- return -EINVAL;
- }
-
-- ret = uac_clock_selector_get_val(chip, selector_id);
-+ ret = uac_clock_selector_get_val(chip, selector_id, iface_no);
- if (ret < 0)
- return ret;
-
-@@ -155,8 +163,10 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
- unsigned char data;
- struct usb_device *dev = chip->dev;
- union uac23_clock_source_desc *cs_desc;
-+ struct usb_host_interface *ctrl_intf;
-
-- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol);
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
-+ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt);
- if (!cs_desc)
- return false;
-
-@@ -191,7 +201,7 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_CLOCK_VALID << 8,
-- snd_usb_ctrl_intf(chip) | (source_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8),
- &data, sizeof(data));
- if (err < 0) {
- dev_warn(&dev->dev,
-@@ -217,8 +227,10 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
- struct usb_device *dev = chip->dev;
- u32 bmControls;
- union uac23_clock_source_desc *cs_desc;
-+ struct usb_host_interface *ctrl_intf;
-
-- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol);
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
-+ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt);
- if (!cs_desc)
- return false;
-
-@@ -235,7 +247,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_CLOCK_VALID << 8,
-- snd_usb_ctrl_intf(chip) | (source_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8),
- &data, sizeof(data));
-
- if (err < 0) {
-@@ -274,7 +286,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- }
-
- /* first, see if the ID we're looking at is a clock source already */
-- source = snd_usb_find_clock_source(chip, entity_id, proto);
-+ source = snd_usb_find_clock_source(chip, entity_id, fmt);
- if (source) {
- entity_id = GET_VAL(source, proto, bClockID);
- if (validate && !uac_clock_source_is_valid(chip, fmt,
-@@ -287,7 +299,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- return entity_id;
- }
-
-- selector = snd_usb_find_clock_selector(chip, entity_id, proto);
-+ selector = snd_usb_find_clock_selector(chip, entity_id, fmt);
- if (selector) {
- pins = GET_VAL(selector, proto, bNrInPins);
- clock_id = GET_VAL(selector, proto, bClockID);
-@@ -317,7 +329,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
-
- /* the entity ID we are looking at is a selector.
- * find out what it currently selects */
-- ret = uac_clock_selector_get_val(chip, clock_id);
-+ ret = uac_clock_selector_get_val(chip, clock_id, fmt->iface);
- if (ret < 0) {
- if (!chip->autoclock)
- return ret;
-@@ -346,7 +358,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR ||
- !writeable)
- return ret;
-- err = uac_clock_selector_set_val(chip, entity_id, cur);
-+ err = uac_clock_selector_set_val(chip, entity_id, cur, fmt->iface);
- if (err < 0) {
- if (pins == 1) {
- usb_audio_dbg(chip,
-@@ -377,7 +389,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- if (ret < 0)
- continue;
-
-- err = uac_clock_selector_set_val(chip, entity_id, i);
-+ err = uac_clock_selector_set_val(chip, entity_id, i, fmt->iface);
- if (err < 0)
- continue;
-
-@@ -391,7 +403,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- }
-
- /* FIXME: multipliers only act as pass-thru element for now */
-- multiplier = snd_usb_find_clock_multiplier(chip, entity_id, proto);
-+ multiplier = snd_usb_find_clock_multiplier(chip, entity_id, fmt);
- if (multiplier)
- return __uac_clock_find_source(chip, fmt,
- GET_VAL(multiplier, proto, bCSourceID),
-@@ -491,11 +503,13 @@ static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
- struct usb_device *dev = chip->dev;
- __le32 data;
- int err;
-+ struct usb_host_interface *ctrl_intf;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface);
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- &data, sizeof(data));
- if (err < 0) {
- dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n",
-@@ -524,8 +538,10 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
- __le32 data;
- int err;
- union uac23_clock_source_desc *cs_desc;
-+ struct usb_host_interface *ctrl_intf;
-
-- cs_desc = snd_usb_find_clock_source(chip, clock, fmt->protocol);
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
-+ cs_desc = snd_usb_find_clock_source(chip, clock, fmt);
-
- if (!cs_desc)
- return 0;
-@@ -544,7 +560,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
- err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- &data, sizeof(data));
- if (err < 0)
- return err;
-diff --git a/sound/usb/format.c b/sound/usb/format.c
-index 1bb6a455a1b46..0cbf1d4fbe6ed 100644
---- a/sound/usb/format.c
-+++ b/sound/usb/format.c
-@@ -545,7 +545,9 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
- unsigned char tmp[2], *data;
- int nr_triplets, data_size, ret = 0, ret_l6;
- int clock = snd_usb_clock_find_source(chip, fp, false);
-+ struct usb_host_interface *ctrl_intf;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fp->iface);
- if (clock < 0) {
- dev_err(&dev->dev,
- "%s(): unable to find clock source (clock %d)\n",
-@@ -557,7 +559,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
- ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- tmp, sizeof(tmp));
-
- if (ret < 0) {
-@@ -592,7 +594,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
- ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- data, data_size);
-
- if (ret < 0) {
-diff --git a/sound/usb/helper.c b/sound/usb/helper.c
-index bf80e55d013a8..72b671fb2c84c 100644
---- a/sound/usb/helper.c
-+++ b/sound/usb/helper.c
-@@ -130,3 +130,37 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting
- return NULL;
- return usb_altnum_to_altsetting(iface, altsetting);
- }
-+
-+int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
-+ int ctrlif)
-+{
-+ struct usb_device *dev = chip->dev;
-+ struct usb_host_interface *host_iface;
-+
-+ if (chip->num_intf_to_ctrl >= MAX_CARD_INTERFACES) {
-+ dev_info(&dev->dev, "Too many interfaces assigned to the single USB-audio card\n");
-+ return -EINVAL;
-+ }
-+
-+ /* find audiocontrol interface */
-+ host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
-+
-+ chip->intf_to_ctrl[chip->num_intf_to_ctrl].interface = ifnum;
-+ chip->intf_to_ctrl[chip->num_intf_to_ctrl].ctrl_intf = host_iface;
-+ chip->num_intf_to_ctrl++;
-+
-+ return 0;
-+}
-+
-+struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
-+ int ifnum)
-+{
-+ int i;
-+
-+ for (i = 0; i < chip->num_intf_to_ctrl; ++i)
-+ if (chip->intf_to_ctrl[i].interface == ifnum)
-+ return chip->intf_to_ctrl[i].ctrl_intf;
-+
-+ /* Fallback to first audiocontrol interface */
-+ return chip->ctrl_intf;
-+}
-diff --git a/sound/usb/helper.h b/sound/usb/helper.h
-index e2b51ec96ec62..0372e050b3dc4 100644
---- a/sound/usb/helper.h
-+++ b/sound/usb/helper.h
-@@ -17,6 +17,12 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
- struct usb_host_interface *
- snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting);
-
-+int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
-+ int ctrlif);
-+
-+struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
-+ int ifnum);
-+
- /*
- * retrieve usb_interface descriptor from the host interface
- * (conditional for compatibility with the older API)
-@@ -28,9 +34,9 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting
-
- #define snd_usb_get_speed(dev) ((dev)->speed)
-
--static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip)
-+static inline int snd_usb_ctrl_intf(struct usb_host_interface *ctrl_intf)
- {
-- return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber;
-+ return get_iface_desc(ctrl_intf)->bInterfaceNumber;
- }
-
- /* in validate.c */
-diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
-index 2d27d729c3bea..9945ae55b0d08 100644
---- a/sound/usb/mixer.c
-+++ b/sound/usb/mixer.c
-@@ -728,7 +728,7 @@ static int get_cluster_channels_v3(struct mixer_build *state, unsigned int clust
- UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- cluster_id,
-- snd_usb_ctrl_intf(state->chip),
-+ snd_usb_ctrl_intf(state->mixer->hostif),
- &c_header, sizeof(c_header));
- if (err < 0)
- goto error;
-diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
-index 2bc344cf54a83..8cbfb65846047 100644
---- a/sound/usb/mixer_quirks.c
-+++ b/sound/usb/mixer_quirks.c
-@@ -1043,7 +1043,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer,
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- pval & 0xff00,
-- snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8),
-+ snd_usb_ctrl_intf(mixer->hostif) | ((pval & 0xff) << 8),
- value, 2);
- if (err < 0)
- return err;
-@@ -1077,7 +1077,7 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list)
- UAC_SET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- pval & 0xff00,
-- snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8),
-+ snd_usb_ctrl_intf(list->mixer->hostif) | ((pval & 0xff) << 8),
- value, 2);
- snd_usb_unlock_shutdown(chip);
- return err;
-@@ -2115,24 +2115,25 @@ static int dell_dock_mixer_create(struct usb_mixer_interface *mixer)
- return 0;
- }
-
--static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id)
-+static void dell_dock_init_vol(struct usb_mixer_interface *mixer, int ch, int id)
- {
-+ struct snd_usb_audio *chip = mixer->chip;
- u16 buf = 0;
-
- snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- (UAC_FU_VOLUME << 8) | ch,
-- snd_usb_ctrl_intf(chip) | (id << 8),
-+ snd_usb_ctrl_intf(mixer->hostif) | (id << 8),
- &buf, 2);
- }
-
- static int dell_dock_mixer_init(struct usb_mixer_interface *mixer)
- {
- /* fix to 0dB playback volumes */
-- dell_dock_init_vol(mixer->chip, 1, 16);
-- dell_dock_init_vol(mixer->chip, 2, 16);
-- dell_dock_init_vol(mixer->chip, 1, 19);
-- dell_dock_init_vol(mixer->chip, 2, 19);
-+ dell_dock_init_vol(mixer, 1, 16);
-+ dell_dock_init_vol(mixer, 2, 16);
-+ dell_dock_init_vol(mixer, 1, 19);
-+ dell_dock_init_vol(mixer, 2, 19);
- return 0;
- }
-
-diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
-index 0d6e4f15bf77c..ff548041679bb 100644
---- a/sound/usb/mixer_scarlett.c
-+++ b/sound/usb/mixer_scarlett.c
-@@ -460,7 +460,7 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
- struct snd_usb_audio *chip = elem->head.mixer->chip;
- unsigned char buf[2 * MAX_CHANNELS] = {0, };
- int wValue = (elem->control << 8) | elem->idx_off;
-- int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
-+ int idx = snd_usb_ctrl_intf(elem->head.mixer->hostif) | (elem->head.id << 8);
- int err;
-
- err = snd_usb_ctl_msg(chip->dev,
-@@ -1002,7 +1002,7 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS |
-- USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) |
-+ USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->hostif) |
- (0x29 << 8), sample_rate_buffer, 4);
- if (err < 0)
- return err;
-diff --git a/sound/usb/power.c b/sound/usb/power.c
-index 606a2cb23eab6..66bd4daa68fd5 100644
---- a/sound/usb/power.c
-+++ b/sound/usb/power.c
-@@ -40,6 +40,7 @@ snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface,
- le16_to_cpu(pd_desc->waRecoveryTime1);
- pd->pd_d2d0_rec =
- le16_to_cpu(pd_desc->waRecoveryTime2);
-+ pd->ctrl_iface = ctrl_iface;
- return pd;
- }
- }
-@@ -57,7 +58,7 @@ int snd_usb_power_domain_set(struct snd_usb_audio *chip,
- unsigned char current_state;
- int err, idx;
-
-- idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8);
-+ idx = snd_usb_ctrl_intf(pd->ctrl_iface) | (pd->pd_id << 8);
-
- err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
- UAC2_CS_CUR,
-diff --git a/sound/usb/power.h b/sound/usb/power.h
-index 396e3e51440a7..1fa92ad0ca925 100644
---- a/sound/usb/power.h
-+++ b/sound/usb/power.h
-@@ -6,6 +6,7 @@ struct snd_usb_power_domain {
- int pd_id; /* UAC3 Power Domain ID */
- int pd_d1d0_rec; /* D1 to D0 recovery time */
- int pd_d2d0_rec; /* D2 to D0 recovery time */
-+ struct usb_host_interface *ctrl_iface; /* Control interface */
- };
-
- enum {
-diff --git a/sound/usb/stream.c b/sound/usb/stream.c
-index e14c725acebf2..d70c140813d68 100644
---- a/sound/usb/stream.c
-+++ b/sound/usb/stream.c
-@@ -713,10 +713,13 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
- struct usb_device *dev = chip->dev;
- struct uac_format_type_i_continuous_descriptor *fmt;
- unsigned int num_channels = 0, chconfig = 0;
-+ struct usb_host_interface *ctrl_intf;
- struct audioformat *fp;
- int clock = 0;
- u64 format;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
-+
- /* get audio formats */
- if (protocol == UAC_VERSION_1) {
- struct uac1_as_header_descriptor *as =
-@@ -740,7 +743,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
-
- format = le16_to_cpu(as->wFormatTag); /* remember the format value */
-
-- iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
-+ iterm = snd_usb_find_input_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- protocol);
- if (iterm) {
-@@ -776,7 +779,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
- * lookup the terminal associated to this interface
- * to extract the clock
- */
-- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
-+ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- protocol);
- if (input_term) {
-@@ -786,7 +789,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
- goto found_clock;
- }
-
-- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
-+ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- protocol);
- if (output_term) {
-@@ -870,6 +873,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- struct uac3_cluster_header_descriptor *cluster;
- struct uac3_as_header_descriptor *as = NULL;
- struct uac3_hc_descriptor_header hc_header;
-+ struct usb_host_interface *ctrl_intf;
- struct snd_pcm_chmap_elem *chmap;
- struct snd_usb_power_domain *pd;
- unsigned char badd_profile;
-@@ -881,6 +885,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- int err;
-
- badd_profile = chip->badd_profile;
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
-
- if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
- unsigned int maxpacksize =
-@@ -966,7 +971,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- cluster_id,
-- snd_usb_ctrl_intf(chip),
-+ snd_usb_ctrl_intf(ctrl_intf),
- &hc_header, sizeof(hc_header));
- if (err < 0)
- return ERR_PTR(err);
-@@ -990,7 +995,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- cluster_id,
-- snd_usb_ctrl_intf(chip),
-+ snd_usb_ctrl_intf(ctrl_intf),
- cluster, wLength);
- if (err < 0) {
- kfree(cluster);
-@@ -1011,7 +1016,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- * lookup the terminal associated to this interface
- * to extract the clock
- */
-- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
-+ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- UAC_VERSION_3);
- if (input_term) {
-@@ -1019,7 +1024,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- goto found_clock;
- }
-
-- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
-+ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- UAC_VERSION_3);
- if (output_term) {
-@@ -1068,7 +1073,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- UAC_VERSION_3,
- iface_no);
-
-- pd = snd_usb_find_power_domain(chip->ctrl_intf,
-+ pd = snd_usb_find_power_domain(ctrl_intf,
- as->bTerminalLink);
-
- /* ok, let's parse further... */
-diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
-index 43d4029edab46..b0f042c996087 100644
---- a/sound/usb/usbaudio.h
-+++ b/sound/usb/usbaudio.h
-@@ -21,6 +21,15 @@ struct media_intf_devnode;
-
- #define MAX_CARD_INTERFACES 16
-
-+/*
-+ * Structure holding assosiation between Audio Control Interface
-+ * and given Streaming or Midi Interface.
-+ */
-+struct snd_intf_to_ctrl {
-+ u8 interface;
-+ struct usb_host_interface *ctrl_intf;
-+};
-+
- struct snd_usb_audio {
- int index;
- struct usb_device *dev;
-@@ -63,6 +72,9 @@ struct snd_usb_audio {
- struct usb_host_interface *ctrl_intf; /* the audio control interface */
- struct media_device *media_dev;
- struct media_intf_devnode *ctl_intf_media_devnode;
-+
-+ unsigned int num_intf_to_ctrl;
-+ struct snd_intf_to_ctrl intf_to_ctrl[MAX_CARD_INTERFACES];
- };
-
- #define USB_AUDIO_IFACE_UNUSED ((void *)-1L)
---
-2.43.0
-
alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch
x86-ioapic-handle-allocation-failures-gracefully.patch
x86-apic-remove-logical-destination-mode-for-64-bit.patch
-alsa-usb-audio-support-multiple-control-interfaces.patch
alsa-usb-audio-define-macros-for-quirk-table-entries.patch
alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch
alsa-usb-audio-add-quirk-for-rme-digiface-usb.patch
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- sound/usb/card.c | 6 ++++++
+ sound/usb/card.c | 6 ++++++
1 file changed, 6 insertions(+)
-diff --git a/sound/usb/card.c b/sound/usb/card.c
-index 7c98cc831b8d9..753fb47d25913 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
-@@ -384,6 +384,12 @@ static const struct usb_audio_device_name usb_audio_names[] = {
+@@ -382,6 +382,12 @@ static const struct usb_audio_device_nam
/* Creative/Toshiba Multimedia Center SB-0500 */
DEVICE_NAME(0x041e, 0x3048, "Toshiba", "SB-0500"),
DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"),
DEVICE_NAME(0x05e1, 0x0408, "Syntek", "STK1160"),
---
-2.43.0
-
+++ /dev/null
-From 4e61357fcd14afe57ede4e02ad249cf7763f3afb Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Sun, 11 Aug 2024 17:29:56 -0700
-Subject: ALSA: usb-audio: Support multiple control interfaces
-
-From: Karol Kosik <k.kosik@outlook.com>
-
-[ Upstream commit 6aa8700150f7dc62f60b4cf5b1624e2e3d9ed78e ]
-
-Registering Numark Party Mix II fails with error 'bogus bTerminalLink 1'.
-The problem stems from the driver not being able to find input/output
-terminals required to configure audio streaming. The information about
-those terminals is stored in AudioControl Interface. Numark device
-contains 2 AudioControl Interfaces and the driver checks only one of them.
-
-According to the USB standard, a device can have multiple audio functions,
-each represented by Audio Interface Collection. Every audio function is
-considered to be closed box and will contain unique AudioControl Interface
-and zero or more AudioStreaming and MIDIStreaming Interfaces.
-
-The Numark device adheres to the standard and defines two audio functions:
-- MIDIStreaming function
-- AudioStreaming function
-It starts with MIDI function, followed by the audio function. The driver
-saves the first AudioControl Interface in `snd_usb_audio` structure
-associated with the entire device. It then attempts to use this interface
-to query for terminals and clocks. However, this fails because the correct
-information is stored in the second AudioControl Interface, defined in the
-second Audio Interface Collection.
-
-This patch introduces a structure holding association between each
-MIDI/Audio Interface and its corresponding AudioControl Interface,
-instead of relying on AudioControl Interface defined for the entire
-device. This structure is populated during usb probing phase and leveraged
-later when querying for terminals and when sending USB requests.
-
-Alternative solutions considered include:
-- defining a quirk for Numark where the order of interface is manually
-changed, or terminals are hardcoded in the driver. This solution would
-have fixed only this model, though it seems that device is USB compliant,
-and it also seems that other devices from this company may be affected.
-What's more, it looks like products from other manufacturers have similar
-problems, i.e. Rane One DJ console
-- keeping a list of all AudioControl Interfaces and querying all of them
-to find required information. That would have solved my problem and have
-low probability of breaking other devices, as we would always start with
-the same logic of querying first AudioControl Interface. This solution
-would not have followed the standard though.
-
-This patch preserves the `snd_usb_audio.ctrl_intf` variable, which holds
-the first AudioControl Interface, and uses it as a fallback when some
-interfaces are not parsed correctly and lack an associated AudioControl
-Interface, i.e., when configured via quirks.
-
-Link: https://bugzilla.kernel.org/show_bug.cgi?id=217865
-Signed-off-by: Karol Kosik <k.kosik@outlook.com>
-Link: https://patch.msgid.link/AS8P190MB1285893F4735C8B32AD3886BEC852@AS8P190MB1285.EURP190.PROD.OUTLOOK.COM
-Signed-off-by: Takashi Iwai <tiwai@suse.de>
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- sound/usb/card.c | 2 ++
- sound/usb/clock.c | 62 ++++++++++++++++++++++++--------------
- sound/usb/format.c | 6 ++--
- sound/usb/helper.c | 34 +++++++++++++++++++++
- sound/usb/helper.h | 10 ++++--
- sound/usb/mixer.c | 2 +-
- sound/usb/mixer_quirks.c | 17 ++++++-----
- sound/usb/mixer_scarlett.c | 4 +--
- sound/usb/power.c | 3 +-
- sound/usb/power.h | 1 +
- sound/usb/stream.c | 21 ++++++++-----
- sound/usb/usbaudio.h | 12 ++++++++
- 12 files changed, 127 insertions(+), 47 deletions(-)
-
-diff --git a/sound/usb/card.c b/sound/usb/card.c
-index 1b2edc0fd2e99..7c98cc831b8d9 100644
---- a/sound/usb/card.c
-+++ b/sound/usb/card.c
-@@ -206,6 +206,8 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int
- return -EINVAL;
- }
-
-+ snd_usb_add_ctrl_interface_link(chip, interface, ctrlif);
-+
- if (! snd_usb_parse_audio_interface(chip, interface)) {
- usb_set_interface(dev, interface, 0); /* reset the current interface */
- return usb_driver_claim_interface(&usb_audio_driver, iface,
-diff --git a/sound/usb/clock.c b/sound/usb/clock.c
-index a676ad093d189..6f0693c428b0b 100644
---- a/sound/usb/clock.c
-+++ b/sound/usb/clock.c
-@@ -76,11 +76,14 @@ static bool validate_clock_multiplier(void *p, int id, int proto)
- }
-
- #define DEFINE_FIND_HELPER(name, obj, validator, type2, type3) \
--static obj *name(struct snd_usb_audio *chip, int id, int proto) \
-+static obj *name(struct snd_usb_audio *chip, int id, \
-+ const struct audioformat *fmt) \
- { \
-- return find_uac_clock_desc(chip->ctrl_intf, id, validator, \
-- proto == UAC_VERSION_3 ? (type3) : (type2), \
-- proto); \
-+ struct usb_host_interface *ctrl_intf = \
-+ snd_usb_find_ctrl_interface(chip, fmt->iface); \
-+ return find_uac_clock_desc(ctrl_intf, id, validator, \
-+ fmt->protocol == UAC_VERSION_3 ? (type3) : (type2), \
-+ fmt->protocol); \
- }
-
- DEFINE_FIND_HELPER(snd_usb_find_clock_source,
-@@ -93,16 +96,19 @@ DEFINE_FIND_HELPER(snd_usb_find_clock_multiplier,
- union uac23_clock_multiplier_desc, validate_clock_multiplier,
- UAC2_CLOCK_MULTIPLIER, UAC3_CLOCK_MULTIPLIER);
-
--static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
-+static int uac_clock_selector_get_val(struct snd_usb_audio *chip,
-+ int selector_id, int iface_no)
- {
-+ struct usb_host_interface *ctrl_intf;
- unsigned char buf;
- int ret;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
- ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
- UAC2_CS_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- UAC2_CX_CLOCK_SELECTOR << 8,
-- snd_usb_ctrl_intf(chip) | (selector_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8),
- &buf, sizeof(buf));
-
- if (ret < 0)
-@@ -111,16 +117,18 @@ static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_i
- return buf;
- }
-
--static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_id,
-- unsigned char pin)
-+static int uac_clock_selector_set_val(struct snd_usb_audio *chip,
-+ int selector_id, unsigned char pin, int iface_no)
- {
-+ struct usb_host_interface *ctrl_intf;
- int ret;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
- ret = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
- UAC2_CS_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- UAC2_CX_CLOCK_SELECTOR << 8,
-- snd_usb_ctrl_intf(chip) | (selector_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (selector_id << 8),
- &pin, sizeof(pin));
- if (ret < 0)
- return ret;
-@@ -132,7 +140,7 @@ static int uac_clock_selector_set_val(struct snd_usb_audio *chip, int selector_i
- return -EINVAL;
- }
-
-- ret = uac_clock_selector_get_val(chip, selector_id);
-+ ret = uac_clock_selector_get_val(chip, selector_id, iface_no);
- if (ret < 0)
- return ret;
-
-@@ -155,8 +163,10 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
- unsigned char data;
- struct usb_device *dev = chip->dev;
- union uac23_clock_source_desc *cs_desc;
-+ struct usb_host_interface *ctrl_intf;
-
-- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol);
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
-+ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt);
- if (!cs_desc)
- return false;
-
-@@ -191,7 +201,7 @@ static bool uac_clock_source_is_valid_quirk(struct snd_usb_audio *chip,
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_CLOCK_VALID << 8,
-- snd_usb_ctrl_intf(chip) | (source_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8),
- &data, sizeof(data));
- if (err < 0) {
- dev_warn(&dev->dev,
-@@ -217,8 +227,10 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
- struct usb_device *dev = chip->dev;
- u32 bmControls;
- union uac23_clock_source_desc *cs_desc;
-+ struct usb_host_interface *ctrl_intf;
-
-- cs_desc = snd_usb_find_clock_source(chip, source_id, fmt->protocol);
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
-+ cs_desc = snd_usb_find_clock_source(chip, source_id, fmt);
- if (!cs_desc)
- return false;
-
-@@ -235,7 +247,7 @@ static bool uac_clock_source_is_valid(struct snd_usb_audio *chip,
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_CLOCK_VALID << 8,
-- snd_usb_ctrl_intf(chip) | (source_id << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (source_id << 8),
- &data, sizeof(data));
-
- if (err < 0) {
-@@ -272,7 +284,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- }
-
- /* first, see if the ID we're looking at is a clock source already */
-- source = snd_usb_find_clock_source(chip, entity_id, proto);
-+ source = snd_usb_find_clock_source(chip, entity_id, fmt);
- if (source) {
- entity_id = GET_VAL(source, proto, bClockID);
- if (validate && !uac_clock_source_is_valid(chip, fmt,
-@@ -285,7 +297,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- return entity_id;
- }
-
-- selector = snd_usb_find_clock_selector(chip, entity_id, proto);
-+ selector = snd_usb_find_clock_selector(chip, entity_id, fmt);
- if (selector) {
- pins = GET_VAL(selector, proto, bNrInPins);
- clock_id = GET_VAL(selector, proto, bClockID);
-@@ -299,7 +311,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
-
- /* the entity ID we are looking at is a selector.
- * find out what it currently selects */
-- ret = uac_clock_selector_get_val(chip, clock_id);
-+ ret = uac_clock_selector_get_val(chip, clock_id, fmt->iface);
- if (ret < 0) {
- if (!chip->autoclock)
- return ret;
-@@ -327,7 +339,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- /* Skip setting clock selector again for some devices */
- if (chip->quirk_flags & QUIRK_FLAG_SKIP_CLOCK_SELECTOR)
- return ret;
-- err = uac_clock_selector_set_val(chip, entity_id, cur);
-+ err = uac_clock_selector_set_val(chip, entity_id, cur, fmt->iface);
- if (err < 0) {
- if (pins == 1) {
- usb_audio_dbg(chip,
-@@ -355,7 +367,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- if (ret < 0)
- continue;
-
-- err = uac_clock_selector_set_val(chip, entity_id, i);
-+ err = uac_clock_selector_set_val(chip, entity_id, i, fmt->iface);
- if (err < 0)
- continue;
-
-@@ -369,7 +381,7 @@ static int __uac_clock_find_source(struct snd_usb_audio *chip,
- }
-
- /* FIXME: multipliers only act as pass-thru element for now */
-- multiplier = snd_usb_find_clock_multiplier(chip, entity_id, proto);
-+ multiplier = snd_usb_find_clock_multiplier(chip, entity_id, fmt);
- if (multiplier)
- return __uac_clock_find_source(chip, fmt,
- GET_VAL(multiplier, proto, bCSourceID),
-@@ -469,11 +481,13 @@ static int get_sample_rate_v2v3(struct snd_usb_audio *chip, int iface,
- struct usb_device *dev = chip->dev;
- __le32 data;
- int err;
-+ struct usb_host_interface *ctrl_intf;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface);
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- &data, sizeof(data));
- if (err < 0) {
- dev_warn(&dev->dev, "%d:%d: cannot get freq (v2/v3): err %d\n",
-@@ -502,8 +516,10 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
- __le32 data;
- int err;
- union uac23_clock_source_desc *cs_desc;
-+ struct usb_host_interface *ctrl_intf;
-
-- cs_desc = snd_usb_find_clock_source(chip, clock, fmt->protocol);
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fmt->iface);
-+ cs_desc = snd_usb_find_clock_source(chip, clock, fmt);
-
- if (!cs_desc)
- return 0;
-@@ -522,7 +538,7 @@ int snd_usb_set_sample_rate_v2v3(struct snd_usb_audio *chip,
- err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- &data, sizeof(data));
- if (err < 0)
- return err;
-diff --git a/sound/usb/format.c b/sound/usb/format.c
-index 3b45d0ee76938..61c4aca8be09e 100644
---- a/sound/usb/format.c
-+++ b/sound/usb/format.c
-@@ -548,7 +548,9 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
- unsigned char tmp[2], *data;
- int nr_triplets, data_size, ret = 0, ret_l6;
- int clock = snd_usb_clock_find_source(chip, fp, false);
-+ struct usb_host_interface *ctrl_intf;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, fp->iface);
- if (clock < 0) {
- dev_err(&dev->dev,
- "%s(): unable to find clock source (clock %d)\n",
-@@ -560,7 +562,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
- ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- tmp, sizeof(tmp));
-
- if (ret < 0) {
-@@ -595,7 +597,7 @@ static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,
- ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8,
-- snd_usb_ctrl_intf(chip) | (clock << 8),
-+ snd_usb_ctrl_intf(ctrl_intf) | (clock << 8),
- data, data_size);
-
- if (ret < 0) {
-diff --git a/sound/usb/helper.c b/sound/usb/helper.c
-index bf80e55d013a8..72b671fb2c84c 100644
---- a/sound/usb/helper.c
-+++ b/sound/usb/helper.c
-@@ -130,3 +130,37 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting
- return NULL;
- return usb_altnum_to_altsetting(iface, altsetting);
- }
-+
-+int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
-+ int ctrlif)
-+{
-+ struct usb_device *dev = chip->dev;
-+ struct usb_host_interface *host_iface;
-+
-+ if (chip->num_intf_to_ctrl >= MAX_CARD_INTERFACES) {
-+ dev_info(&dev->dev, "Too many interfaces assigned to the single USB-audio card\n");
-+ return -EINVAL;
-+ }
-+
-+ /* find audiocontrol interface */
-+ host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0];
-+
-+ chip->intf_to_ctrl[chip->num_intf_to_ctrl].interface = ifnum;
-+ chip->intf_to_ctrl[chip->num_intf_to_ctrl].ctrl_intf = host_iface;
-+ chip->num_intf_to_ctrl++;
-+
-+ return 0;
-+}
-+
-+struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
-+ int ifnum)
-+{
-+ int i;
-+
-+ for (i = 0; i < chip->num_intf_to_ctrl; ++i)
-+ if (chip->intf_to_ctrl[i].interface == ifnum)
-+ return chip->intf_to_ctrl[i].ctrl_intf;
-+
-+ /* Fallback to first audiocontrol interface */
-+ return chip->ctrl_intf;
-+}
-diff --git a/sound/usb/helper.h b/sound/usb/helper.h
-index e2b51ec96ec62..0372e050b3dc4 100644
---- a/sound/usb/helper.h
-+++ b/sound/usb/helper.h
-@@ -17,6 +17,12 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
- struct usb_host_interface *
- snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting);
-
-+int snd_usb_add_ctrl_interface_link(struct snd_usb_audio *chip, int ifnum,
-+ int ctrlif);
-+
-+struct usb_host_interface *snd_usb_find_ctrl_interface(struct snd_usb_audio *chip,
-+ int ifnum);
-+
- /*
- * retrieve usb_interface descriptor from the host interface
- * (conditional for compatibility with the older API)
-@@ -28,9 +34,9 @@ snd_usb_get_host_interface(struct snd_usb_audio *chip, int ifnum, int altsetting
-
- #define snd_usb_get_speed(dev) ((dev)->speed)
-
--static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip)
-+static inline int snd_usb_ctrl_intf(struct usb_host_interface *ctrl_intf)
- {
-- return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber;
-+ return get_iface_desc(ctrl_intf)->bInterfaceNumber;
- }
-
- /* in validate.c */
-diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
-index 197fd07e69edd..017b50322d88f 100644
---- a/sound/usb/mixer.c
-+++ b/sound/usb/mixer.c
-@@ -728,7 +728,7 @@ static int get_cluster_channels_v3(struct mixer_build *state, unsigned int clust
- UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- cluster_id,
-- snd_usb_ctrl_intf(state->chip),
-+ snd_usb_ctrl_intf(state->mixer->hostif),
- &c_header, sizeof(c_header));
- if (err < 0)
- goto error;
-diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
-index c8d48566e1759..2323504339328 100644
---- a/sound/usb/mixer_quirks.c
-+++ b/sound/usb/mixer_quirks.c
-@@ -1043,7 +1043,7 @@ static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer,
- err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- pval & 0xff00,
-- snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8),
-+ snd_usb_ctrl_intf(mixer->hostif) | ((pval & 0xff) << 8),
- value, 2);
- if (err < 0)
- return err;
-@@ -1077,7 +1077,7 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list)
- UAC_SET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- pval & 0xff00,
-- snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8),
-+ snd_usb_ctrl_intf(list->mixer->hostif) | ((pval & 0xff) << 8),
- value, 2);
- snd_usb_unlock_shutdown(chip);
- return err;
-@@ -2115,24 +2115,25 @@ static int dell_dock_mixer_create(struct usb_mixer_interface *mixer)
- return 0;
- }
-
--static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id)
-+static void dell_dock_init_vol(struct usb_mixer_interface *mixer, int ch, int id)
- {
-+ struct snd_usb_audio *chip = mixer->chip;
- u16 buf = 0;
-
- snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- (UAC_FU_VOLUME << 8) | ch,
-- snd_usb_ctrl_intf(chip) | (id << 8),
-+ snd_usb_ctrl_intf(mixer->hostif) | (id << 8),
- &buf, 2);
- }
-
- static int dell_dock_mixer_init(struct usb_mixer_interface *mixer)
- {
- /* fix to 0dB playback volumes */
-- dell_dock_init_vol(mixer->chip, 1, 16);
-- dell_dock_init_vol(mixer->chip, 2, 16);
-- dell_dock_init_vol(mixer->chip, 1, 19);
-- dell_dock_init_vol(mixer->chip, 2, 19);
-+ dell_dock_init_vol(mixer, 1, 16);
-+ dell_dock_init_vol(mixer, 2, 16);
-+ dell_dock_init_vol(mixer, 1, 19);
-+ dell_dock_init_vol(mixer, 2, 19);
- return 0;
- }
-
-diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
-index 0d6e4f15bf77c..ff548041679bb 100644
---- a/sound/usb/mixer_scarlett.c
-+++ b/sound/usb/mixer_scarlett.c
-@@ -460,7 +460,7 @@ static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
- struct snd_usb_audio *chip = elem->head.mixer->chip;
- unsigned char buf[2 * MAX_CHANNELS] = {0, };
- int wValue = (elem->control << 8) | elem->idx_off;
-- int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
-+ int idx = snd_usb_ctrl_intf(elem->head.mixer->hostif) | (elem->head.id << 8);
- int err;
-
- err = snd_usb_ctl_msg(chip->dev,
-@@ -1002,7 +1002,7 @@ int snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS |
-- USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) |
-+ USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->hostif) |
- (0x29 << 8), sample_rate_buffer, 4);
- if (err < 0)
- return err;
-diff --git a/sound/usb/power.c b/sound/usb/power.c
-index 606a2cb23eab6..66bd4daa68fd5 100644
---- a/sound/usb/power.c
-+++ b/sound/usb/power.c
-@@ -40,6 +40,7 @@ snd_usb_find_power_domain(struct usb_host_interface *ctrl_iface,
- le16_to_cpu(pd_desc->waRecoveryTime1);
- pd->pd_d2d0_rec =
- le16_to_cpu(pd_desc->waRecoveryTime2);
-+ pd->ctrl_iface = ctrl_iface;
- return pd;
- }
- }
-@@ -57,7 +58,7 @@ int snd_usb_power_domain_set(struct snd_usb_audio *chip,
- unsigned char current_state;
- int err, idx;
-
-- idx = snd_usb_ctrl_intf(chip) | (pd->pd_id << 8);
-+ idx = snd_usb_ctrl_intf(pd->ctrl_iface) | (pd->pd_id << 8);
-
- err = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
- UAC2_CS_CUR,
-diff --git a/sound/usb/power.h b/sound/usb/power.h
-index 396e3e51440a7..1fa92ad0ca925 100644
---- a/sound/usb/power.h
-+++ b/sound/usb/power.h
-@@ -6,6 +6,7 @@ struct snd_usb_power_domain {
- int pd_id; /* UAC3 Power Domain ID */
- int pd_d1d0_rec; /* D1 to D0 recovery time */
- int pd_d2d0_rec; /* D2 to D0 recovery time */
-+ struct usb_host_interface *ctrl_iface; /* Control interface */
- };
-
- enum {
-diff --git a/sound/usb/stream.c b/sound/usb/stream.c
-index e14c725acebf2..d70c140813d68 100644
---- a/sound/usb/stream.c
-+++ b/sound/usb/stream.c
-@@ -713,10 +713,13 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
- struct usb_device *dev = chip->dev;
- struct uac_format_type_i_continuous_descriptor *fmt;
- unsigned int num_channels = 0, chconfig = 0;
-+ struct usb_host_interface *ctrl_intf;
- struct audioformat *fp;
- int clock = 0;
- u64 format;
-
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
-+
- /* get audio formats */
- if (protocol == UAC_VERSION_1) {
- struct uac1_as_header_descriptor *as =
-@@ -740,7 +743,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
-
- format = le16_to_cpu(as->wFormatTag); /* remember the format value */
-
-- iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
-+ iterm = snd_usb_find_input_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- protocol);
- if (iterm) {
-@@ -776,7 +779,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
- * lookup the terminal associated to this interface
- * to extract the clock
- */
-- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
-+ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- protocol);
- if (input_term) {
-@@ -786,7 +789,7 @@ snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip,
- goto found_clock;
- }
-
-- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
-+ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- protocol);
- if (output_term) {
-@@ -870,6 +873,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- struct uac3_cluster_header_descriptor *cluster;
- struct uac3_as_header_descriptor *as = NULL;
- struct uac3_hc_descriptor_header hc_header;
-+ struct usb_host_interface *ctrl_intf;
- struct snd_pcm_chmap_elem *chmap;
- struct snd_usb_power_domain *pd;
- unsigned char badd_profile;
-@@ -881,6 +885,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- int err;
-
- badd_profile = chip->badd_profile;
-+ ctrl_intf = snd_usb_find_ctrl_interface(chip, iface_no);
-
- if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) {
- unsigned int maxpacksize =
-@@ -966,7 +971,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- cluster_id,
-- snd_usb_ctrl_intf(chip),
-+ snd_usb_ctrl_intf(ctrl_intf),
- &hc_header, sizeof(hc_header));
- if (err < 0)
- return ERR_PTR(err);
-@@ -990,7 +995,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- cluster_id,
-- snd_usb_ctrl_intf(chip),
-+ snd_usb_ctrl_intf(ctrl_intf),
- cluster, wLength);
- if (err < 0) {
- kfree(cluster);
-@@ -1011,7 +1016,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- * lookup the terminal associated to this interface
- * to extract the clock
- */
-- input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
-+ input_term = snd_usb_find_input_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- UAC_VERSION_3);
- if (input_term) {
-@@ -1019,7 +1024,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- goto found_clock;
- }
-
-- output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
-+ output_term = snd_usb_find_output_terminal_descriptor(ctrl_intf,
- as->bTerminalLink,
- UAC_VERSION_3);
- if (output_term) {
-@@ -1068,7 +1073,7 @@ snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip,
- UAC_VERSION_3,
- iface_no);
-
-- pd = snd_usb_find_power_domain(chip->ctrl_intf,
-+ pd = snd_usb_find_power_domain(ctrl_intf,
- as->bTerminalLink);
-
- /* ok, let's parse further... */
-diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
-index 43d4029edab46..b0f042c996087 100644
---- a/sound/usb/usbaudio.h
-+++ b/sound/usb/usbaudio.h
-@@ -21,6 +21,15 @@ struct media_intf_devnode;
-
- #define MAX_CARD_INTERFACES 16
-
-+/*
-+ * Structure holding assosiation between Audio Control Interface
-+ * and given Streaming or Midi Interface.
-+ */
-+struct snd_intf_to_ctrl {
-+ u8 interface;
-+ struct usb_host_interface *ctrl_intf;
-+};
-+
- struct snd_usb_audio {
- int index;
- struct usb_device *dev;
-@@ -63,6 +72,9 @@ struct snd_usb_audio {
- struct usb_host_interface *ctrl_intf; /* the audio control interface */
- struct media_device *media_dev;
- struct media_intf_devnode *ctl_intf_media_devnode;
-+
-+ unsigned int num_intf_to_ctrl;
-+ struct snd_intf_to_ctrl intf_to_ctrl[MAX_CARD_INTERFACES];
- };
-
- #define USB_AUDIO_IFACE_UNUSED ((void *)-1L)
---
-2.43.0
-
nfp-use-irqf_no_autoen-flag-in-request_irq.patch
alsa-usb-audio-add-input-value-sanity-checks-for-sta.patch
x86-ioapic-handle-allocation-failures-gracefully.patch
-alsa-usb-audio-support-multiple-control-interfaces.patch
alsa-usb-audio-define-macros-for-quirk-table-entries.patch
alsa-usb-audio-replace-complex-quirk-lines-with-macr.patch
alsa-usb-audio-add-logitech-audio-profile-quirk.patch