* Re: [RFC PATCH 13/16] ALSA: mixer_audient: Add enumerated controls [not found] <sashiko-outbox-201869@kernel.org> @ 2026-11-06 20:29 ` Will Porter 0 siblings, 0 replies; 2+ messages in thread From: Will Porter @ 2026-11-06 20:29 UTC (permalink / raw) To: Christian Ruppert Cc: Takashi Iwai, Jaroslav Kysela, linux-sound, linux-kernel, Neil Andrews Hi Christian, The bot found a real problem in my patch 13: > Does advertising ctype->enumeration->items + 1 items in > snd_ctl_audient_info() while rejecting item index e->items with > -EINVAL in snd_ctl_audient_enum_set() break the ALSA control UAPI > contract for writable enumerated controls? Yes. mixer-test writes every advertised item, and alsactl restore fails on a value that store saved as the extra item. The diff below drops the extra item from every enum: - A device value outside the list makes get return -EIO. I chose an error over a fallback item: an unknown routing value shown as Main Mix could hide a route that bypasses the speaker volume, cut and dim. The device is not known to report such a value. - A write-only value that no transfer has confirmed (only after a failed probe write) reads as its init value, as a write-only switch reads off. Tested on the iD14 (stable 7.2.15) with the diff applied, with a script that does the enum writes of mixer-test on this card only: get returned every advertised item after its put (from the cache for the write-only controls), and the item past the end was rejected. alsactl store and restore of the card succeeded. I did not run the full mixer-test, because it writes the controls of every card. Does -EIO from get look right to you here? If the diff looks good, I'll fold it into patches 13 and 15 in the next version. Thanks, Will -- >8 -- From: Will Porter <mrwillporter@gmail.com> Subject: [RFC PATCH] ALSA: mixer_audient: Advertise only selectable enum items Every enumerated control advertised one item more than a put accepts. mixer-test writes every advertised item, and alsactl restore fails on a stored value of that item. Advertise only the real items. A get of a device value outside the list now returns -EIO: an unknown routing value shown as Main Mix could hide a route that bypasses the speaker volume, cut and dim. After a failed probe write, a write-only value reads as its init value; this does not confirm the device state. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Will Porter <mrwillporter@gmail.com> --- Proposed change to patches 13 and 15. sound/usb/mixer_audient.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/sound/usb/mixer_audient.c b/sound/usb/mixer_audient.c index e65c62e1eac4a..4180d7d8b325c 100644 --- a/sound/usb/mixer_audient.c +++ b/sound/usb/mixer_audient.c @@ -67,10 +67,8 @@ static const DECLARE_TLV_DB_MINMAX_MUTE(snd_audient_tlv_mixer, -12800, 600); #define SND_AUDIENT_CTYPE_FLAGS_CACHE BIT(3) /* - * An enumerated control: item i sends values[i]. The texts have one item - * more than the values. A put cannot select that last item: a get shows it - * for a device value outside the list ("Other"), or for a write-only value - * that no write has confirmed ("Unknown"). + * An enumerated control: item i sends values[i]. A get of a device value + * outside the list returns -EIO; it does not show a wrong item. */ struct snd_audient_enum { const char *const *texts; @@ -85,7 +83,7 @@ struct snd_audient_enum { .values = name##_values, \ .items = ARRAY_SIZE(name##_values), \ }; \ - static_assert(ARRAY_SIZE(texts_) == ARRAY_SIZE(name##_values) + 1) + static_assert(ARRAY_SIZE(texts_) == ARRAY_SIZE(name##_values)) /* * iD14 MkI units. The monitor controller, output routing, headphone level, @@ -126,7 +124,7 @@ static const DECLARE_TLV_DB_SCALE(snd_audient_tlv_id14_vol, -12800, 100, 0); /* Mono mode: one-speaker sum (Left, Right) or phantom centre */ static const char *const snd_audient_id14_mono_mode_texts[] = { - "Left", "Centre", "Right", "Other", + "Left", "Centre", "Right", }; SND_AUDIENT_ENUM(snd_audient_id14_mono_mode, snd_audient_id14_mono_mode_texts, 1, 0, 2); @@ -139,10 +137,10 @@ SND_AUDIENT_ENUM(snd_audient_id14_mono_mode, * mute still act on every headphone source. */ static const char *const snd_audient_id14_route_main_texts[] = { - "Main Mix", "Cue Mix", "DAW Thru (full scale)", "Other", + "Main Mix", "Cue Mix", "DAW Thru (full scale)", }; static const char *const snd_audient_id14_route_hp_texts[] = { - "Main Mix", "Cue Mix", "DAW Thru", "Other", + "Main Mix", "Cue Mix", "DAW Thru", }; SND_AUDIENT_ENUM(snd_audient_id14_route_main_l, snd_audient_id14_route_main_texts, 0x14, 0x10, 0x00); @@ -156,12 +154,10 @@ SND_AUDIENT_ENUM(snd_audient_id14_route_hp_r, /* * iD key function: the value is the monitor controller selector the key * toggles. ScrollControl (0xffff) toggles nothing: the knob then scrolls - * through the HID interface. The last item of a write-only enum shows a - * value that is not known. + * through the HID interface. */ static const char *const snd_audient_id14_id_key_texts[] = { "ScrollControl", "Mono", "Mono + Polarity", "Dim", "Talkback", - "Unknown", }; SND_AUDIENT_ENUM(snd_audient_id14_id_key, snd_audient_id14_id_key_texts, 0xffff, ID14_MON_MONO, ID14_MON_POLARITY, ID14_MON_DIM, @@ -170,13 +166,13 @@ SND_AUDIENT_ENUM(snd_audient_id14_id_key, snd_audient_id14_id_key_texts, /* Talkback source: the routing source number of the input; none = 0xff */ static const char *const snd_audient_id14_talkback_texts[] = { "None", "Mic 1", "Mic 2", "Digi 1", "Digi 2", "Digi 3", "Digi 4", - "Digi 5", "Digi 6", "Digi 7", "Digi 8", "Unknown", + "Digi 5", "Digi 6", "Digi 7", "Digi 8", }; SND_AUDIENT_ENUM(snd_audient_id14_talkback, snd_audient_id14_talkback_texts, 0xff, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13); static const char *const snd_audient_id14_optical_texts[] = { - "ADAT", "S/PDIF", "Unknown", + "ADAT", "S/PDIF", }; SND_AUDIENT_ENUM(snd_audient_id14_optical, snd_audient_id14_optical_texts, 0, 1); @@ -933,22 +929,23 @@ static int snd_ctl_audient_enum_get(struct snd_kcontrol *kctl, guard(mutex)(&mixer->lock); for (i = 0; i < hwchan; i++) { + unsigned int item; u32 val; int ret; ret = snd_audient_raw_get_one(mixer, ctype, snd_audient_cache_slot(elem, i), base + i, &val); - if (ret == -ENODATA) { /* unknown write-only value */ - ctl_val->value.enumerated.item[i] = - ctype->enumeration->items; - continue; - } else if (ret < 0) { + if (ret == -ENODATA) /* unknown write-only value: init */ + val = ctype->init; + else if (ret < 0) return ret; - } - ctl_val->value.enumerated.item[i] = - snd_audient_enum_item(ctype->enumeration, val); + item = snd_audient_enum_item(ctype->enumeration, val); + if (item >= ctype->enumeration->items) + return -EIO; + + ctl_val->value.enumerated.item[i] = item; } for (; i < nchan; i++) @@ -1007,7 +1004,7 @@ static int snd_ctl_audient_info(struct snd_kcontrol *kctl, if (ctype->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) return snd_ctl_enum_info(uinfo, snd_audient_kctl_channels(kctl), - ctype->enumeration->items + 1, + ctype->enumeration->items, ctype->enumeration->texts); uinfo->type = ctype->type; ^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [RFC V2 PATCH 00/11] Re: ALSA: usb-audio: Audient iD14 MkI vendor @ 2026-11-03 23:01 Christian Ruppert 2026-11-06 16:31 ` [RFC PATCH 00/16] ALSA: usb-audio: Audient driver and iD14 MkI support Will Porter 0 siblings, 1 reply; 2+ messages in thread From: Christian Ruppert @ 2026-11-03 23:01 UTC (permalink / raw) To: Will Porter Cc: Takashi Iwai, Jaroslav Kysela, linux-sound, linux-kernel, Neil Andrews [-- Attachment #1: Type: text/plain, Size: 7205 bytes --] On Mon, Nov 02, 2026 at 08:45:18PM -0600, Will Porter wrote: > Hi Christian, > > Thanks for RFC V2, and for folding everything in so quickly. > > On Mon, Nov 02, 2026 at 01:32:46AM +0100, Christian Ruppert wrote: > > Makes sense. Added to RFC V2 (in patch 10 where the cache is added). > > Please double-check if the logic reflects what you had in mind. > > Yes, that is what I had in mind: a put of the cached value still > writes it, but returns 0, so alsactl restore sends no change events. > On an iD14 MkI, a put of the held value sent no change event on a > write-only switch, a volume or a matrix control. A put of a new value > on the write-only switch sent one. > > One question on the same function. A FORCE_SET control without CACHE > now reads the device before each write; in RFC v1 the put skipped > that read. If the device refuses the read, the put fails before it > writes. No table uses FORCE_SET without CACHE today, so nothing > breaks now. > > Should that combination work? If yes, the put could skip the read > when the control has no cache slot, as the diff below does. If not, > a comment or a check in snd_audient_add_ctrl() would say so, and you > can drop the diff. I guess that depends how we define force_set. In my mind it's literally force set, i.e. for write-only values we must explicitly specify both FORCE_SET and CACHE. The reasoning is that I don't see how write-only controls can work correctly without cache. But force-setting uncached read-write controls might be of value if the set operation as such triggers an event inside a device, even if the value is the same as the one just read back on some volatile control. I imagine this could become useful for certain enumeration types, for example to load a preset. The question is now what the put function should return in such a case and until we encounter one it's rather hypothetical to say what's preferable: - We could systematically return 1 because an event was triggered in the device. If you think this is the right thing to do, feel free to weave your diff into patch 10. I don't think it makes sense to reiterate RFC V3 for such a small change and I'll test the full patch set anwyay. - We could return 1 if the value is changed and 0 if it isn't which is the current behaviour and designed to be consistent with FORCE_SET in case we do have a cache. I imagine (cached) write-only controls are more probable to trigger events on writing than volatile read-write controls so this seemed the reasonable choice. > > I don't think this is necessary as it should be rather obvious to > > everyone touching the driver that the u32 argument can't carry more > > than 4 bytes. Added a comment to the parameter definition. > > Fine with me. > > checkpatch --strict on the 11 patches gives no errors or warnings, > only CHECK-level style notes, mostly unneeded parentheses (04, 05, > 07, 10) and alignment (01, 05). I'll leave those to your discretion. Not sure if we need to reiterate because of those, Takashi please advise. I would like to keep the parentheses for readability if possible and the alignment issues can be fixed little by little when we touch the file over time. Or otherwise, you can also weave in fixes if you prefer. > iD14 patches on RFC V2 > > I rebased my iD14 patch series on RFC V2. Three of my patches are now > part of yours, so seven remain: > > 1. a step size for integer controls > 2. enumerated controls > 3. a separate mixer map for the iD14 MkI > 4. iD14 MkI monitor and routing controls > 5. iD14 MkI mixer matrix > 6. iD14 MkI write-only controls > 7. the iD14 MkI FU 12 control Is there a reason 4, 5 and 6 are separate? They should all be one big update in the device definition tables without any code changes, right? > All 18 patches build one by one with W=1 without warnings. > On an iD14 MkI (7.2.11 stable), the controls passed the same read and > write checks as on RFC v1. > > Next steps > > As agreed, I'll send the final series: your 11 patches, then the > seven iD14 patches. Two questions first: > > - Your four mixer_evo fixes ("ALSA: mixer_evo: minor fixes and tlv > addition") are still open on Patchwork. Should they still go in > separately, before this series? Then I'd base the final series on > sound for-next once Takashi applies them. Or should I put them at > the front of the final series? In principle they are bugfixes and the intention was to keep them small enough so they can still squeeze into 7.4. If Takashi decides that it's already too late for this type of fixes I'm happy remove the ones which are fixed by our new patch set anyway and resubmit the remaining ones at the beginning of our serie. Happy to review and test an RFC of the complete series until he's back and takes a decision. I expect your seven patches aren't massively impacted by the four pending fixes so starting to review them as soon as you're ready would allow for one or two iterations if required, without losing any time while waiting. > - If the diff below looks right to you, shall I fold it into patch > 10 when I send, or would you prefer to take it into your own tree > first? See above. If you think it makes sense to apply it please just fold it in, I don't think we need a full iteration for this. > Thanks, > Will > > -- >8 -- > From: Will Porter <mrwillporter@gmail.com> > Subject: [RFC PATCH] ALSA: mixer_audient: Skip the read for an uncached FORCE_SET put > > A FORCE_SET put without a cache slot reads the device before the > write, and fails without writing if that read fails. Skip the read > in that case, as RFC v1 did. Puts on cached controls keep their > change reporting. > > Also fix a typo in a comment and drop a blank line. > > Assisted-by: Claude:claude-opus-5-5 > Signed-off-by: Will Porter <mrwillporter@gmail.com> > --- > Proposed change to patch 10. > > diff --git a/sound/usb/mixer_audient.c b/sound/usb/mixer_audient.c > index 483ab8f..33c2d1f 100644 > --- a/sound/usb/mixer_audient.c > +++ b/sound/usb/mixer_audient.c > @@ -329,11 +329,12 @@ static int snd_audient_raw_set_one(struct usb_mixer_interface *const mixer, > int ret; > u32 val; > > - if (force) { > + if (force || > + (!slot && (ctype->flags & SND_AUDIENT_CTYPE_FLAGS_FORCE_SET))) { > val = !value; /* just make it different */ > } else { > ret = snd_audient_raw_get_one(mixer, ctype, slot, cidx, &val); > - if (ret == -ENODATA) /* FORCED_SET and not cached yet */ > + if (ret == -ENODATA) /* FORCE_SET and not cached yet */ > val = !value; /* just make it different */ > else if (ret < 0) > return ret; > @@ -352,7 +353,6 @@ static int snd_audient_raw_set_one(struct usb_mixer_interface *const mixer, > slot->value = value; > slot->valid = true; > } > - > } > > return val != value; -- Christian Ruppert <arc@gmx.li> This message is digitally signed with GnuPG. GPG/PGP Key fingerprint = 4492 2196 75F0 EAA0 981E B661 1476 F17A 975F 587B [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 870 bytes --] ^ permalink raw reply [flat|nested] 2+ messages in thread
* [RFC PATCH 00/16] ALSA: usb-audio: Audient driver and iD14 MkI support 2026-11-03 23:01 [RFC V2 PATCH 00/11] Re: ALSA: usb-audio: Audient iD14 MkI vendor Christian Ruppert @ 2026-11-06 16:31 ` Will Porter 2026-11-06 16:31 ` [RFC PATCH 13/16] ALSA: mixer_audient: Add enumerated controls Will Porter 0 siblings, 1 reply; 2+ messages in thread From: Will Porter @ 2026-11-06 16:31 UTC (permalink / raw) To: Christian Ruppert Cc: Takashi Iwai, Jaroslav Kysela, linux-sound, linux-kernel, Neil Andrews Hi Christian, On Wed, Nov 04, 2026 at 12:01:47AM +0100, Christian Ruppert wrote: > I guess that depends how we define force_set. In my mind it's literally > force set, i.e. for write-only values we must explicitly specify both > FORCE_SET and CACHE. That definition makes sense to me. With it, the read before the write is fine: an uncached FORCE_SET control is one the device can read. I also prefer the current return value. If a put always returned 1, the kernel would send a change event even when alsactl restores an unchanged value. So I dropped my diff. Patch 10 has only the comment typo fixed and the blank line removed. > Is there a reason 4, 5 and 6 are separate? They should all be one big > update in the device definition tables without any code changes, right? Right, they add only table entries, the device ID and the map lines. They are now one patch (15 of this series). > Happy to review and test an RFC of the complete series until he's back and > takes a decision. Thanks, here it is: your 11 RFC V2 patches, then the five iD14 patches. It sits on top of your four mixer_evo fixes. I can rebase it once Takashi decides how those go in. Patches 12 to 16: - 12 adds a step size to integer controls (the iD14 volumes move in 1 dB steps). - 13 adds enumerated controls (routing, iD key function, talkback source, digital input mode). - 14 gives the iD14 MkI its own mixer map; the MkII keeps the shared one. - 15 adds the iD14 MkI controls: monitor section, routing, mixer matrix and the write-only controls. - 16 replaces the generic FU 12 control, whose GET returns stale data. Base: sound master 603a4df9e6ae with your four fixes (Patchwork series 1193966). Each patch builds on its own with W=1 without warnings. On an iD14 MkI (7.2.11 stable), the complete series passed the same read and write checks as RFC V2, change events included. Thanks, Will Christian Ruppert (11): ALSA: rename mixer_evo to mixer_audient ALSA: mixer_audient: explicitly define full control names ALSA: mixer_audient: clarify USB control message definition ALSA: mixer_audient: Add length check to USB transfer ALSA: mixer_audient: make USB control transfer size configurable ALSA: mixer_audient: Allow arbitrary boolean control values ALSA: mixer_audient: Add integer range checks ALSA: mixer_audient: Add control initialization at probe ALSA: mixer_audient: Add readback-free parameter set ALSA: mixer_audient: add control value caching ALSA: mixer_audient: Create matrix programmatically Will Porter (5): ALSA: mixer_audient: Add a step size to integer controls ALSA: mixer_audient: Add enumerated controls ALSA: usb-audio: Give the Audient iD14 MkI its own mixer map ALSA: mixer_audient: Add Audient iD14 MkI controls ALSA: mixer_audient: Replace the Audient iD14 MkI FU 12 control MAINTAINERS | 7 +- sound/usb/Makefile | 2 +- sound/usb/mixer_audient.c | 1342 +++++++++++++++++++++++++++++++++++++ sound/usb/mixer_audient.h | 13 + sound/usb/mixer_evo.c | 526 --------------- sound/usb/mixer_evo.h | 12 - sound/usb/mixer_maps.c | 10 +- sound/usb/mixer_quirks.c | 7 +- 8 files changed, 1374 insertions(+), 545 deletions(-) create mode 100644 sound/usb/mixer_audient.c create mode 100644 sound/usb/mixer_audient.h delete mode 100644 sound/usb/mixer_evo.c delete mode 100644 sound/usb/mixer_evo.h base-commit: 603a4df9e6ae60a26adb335fe8d8f6e8f19e5d8e prerequisite-patch-id: 522b05214a3c615ec30e50574b2bcc9c6c55dc3c prerequisite-patch-id: 4c58588cb3fd46832de61018d60452ad1f5de1f9 prerequisite-patch-id: e15c90c1732110d25b16d26b4f919715cae7f5be prerequisite-patch-id: 02c9ab9c3fd4cc8617060c81eed06affae2da0d2 -- 2.47.3 ^ permalink raw reply [flat|nested] 2+ messages in thread
* [RFC PATCH 13/16] ALSA: mixer_audient: Add enumerated controls 2026-11-06 16:31 ` [RFC PATCH 00/16] ALSA: usb-audio: Audient driver and iD14 MkI support Will Porter @ 2026-11-06 16:31 ` Will Porter 0 siblings, 0 replies; 2+ messages in thread From: Will Porter @ 2026-11-06 16:31 UTC (permalink / raw) To: Christian Ruppert Cc: Takashi Iwai, Jaroslav Kysela, linux-sound, linux-kernel, Neil Andrews The iD14 has selectors with a fixed set of device values: output routing, mono mode, the iD key function, talkback source and the digital input mode. Add an enumerated control type with a value list. The item list has one item more than the values. A put cannot select it. A get shows it for a device value outside the list, so a value set by other means stays visible as such, not as a wrong item, and for a write-only value that no write has confirmed. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Will Porter <mrwillporter@gmail.com> --- sound/usb/mixer_audient.c | 130 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/sound/usb/mixer_audient.c b/sound/usb/mixer_audient.c index c4ce2340f8bb..3e6cd8981b4f 100644 --- a/sound/usb/mixer_audient.c +++ b/sound/usb/mixer_audient.c @@ -42,6 +42,27 @@ static const DECLARE_TLV_DB_MINMAX_MUTE(snd_audient_tlv_mixer, -12800, 600); #define SND_AUDIENT_CTYPE_FLAGS_FORCE_SET BIT(2) #define SND_AUDIENT_CTYPE_FLAGS_CACHE BIT(3) +/* + * An enumerated control: item i sends values[i]. The texts have one item + * more than the values. A put cannot select that last item: a get shows it + * for a device value outside the list ("Other"), or for a write-only value + * that no write has confirmed ("Unknown"). + */ +struct snd_audient_enum { + const char *const *texts; + const u32 *values; + unsigned int items; +}; + +#define SND_AUDIENT_ENUM(name, texts_, ...) \ + static const u32 name##_values[] = { __VA_ARGS__ }; \ + static const struct snd_audient_enum name = { \ + .texts = texts_, \ + .values = name##_values, \ + .items = ARRAY_SIZE(name##_values), \ + }; \ + static_assert(ARRAY_SIZE(texts_) == ARRAY_SIZE(name##_values) + 1) + static const struct snd_audient_ctrl_type { snd_ctl_elem_type_t type; unsigned long flags; @@ -54,6 +75,7 @@ static const struct snd_audient_ctrl_type { } max; /* for booleans holds physical int value for true */ u32 init; /* hardware and cache are initialized to this value */ unsigned int res; /* integers: device units per control step, 0 = 1 */ + const struct snd_audient_enum *enumeration; const unsigned int *tlv; u8 unit; u8 sel; @@ -560,12 +582,116 @@ static int snd_ctl_audient_integer_set(struct snd_kcontrol *kctl, return changed; } +static unsigned int snd_audient_enum_item(const struct snd_audient_enum *e, + u32 value) +{ + unsigned int item; + + for (item = 0; item < e->items; item++) + if (e->values[item] == value) + break; + + return item; /* e->items: not in the list */ +} + +static int snd_ctl_audient_enum_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ctl_val) +{ + struct usb_mixer_elem_info *const elem = snd_kcontrol_chip(kctl); + struct usb_mixer_interface *const mixer = elem->head.mixer; + + const unsigned int nchan = snd_audient_kctl_channels(kctl); + const unsigned int hwchan = snd_audient_kctl_hwchannels(kctl); + const struct snd_audient_ctrl_type *const ctype + = snd_audient_kctl_type(kctl); + const u8 base = snd_audient_kctl_cidxoffs(kctl); + + unsigned int i; + + CLASS(snd_usb_lock, pm)(mixer->chip); + if (pm.err < 0) + return pm.err; + /* serializes the transfers and the cache, also between gets */ + guard(mutex)(&mixer->lock); + + for (i = 0; i < hwchan; i++) { + u32 val; + int ret; + + ret = snd_audient_raw_get_one(mixer, ctype, + snd_audient_cache_slot(elem, i), + base + i, &val); + if (ret == -ENODATA) { /* unknown write-only value */ + ctl_val->value.enumerated.item[i] = + ctype->enumeration->items; + continue; + } else if (ret < 0) { + return ret; + } + + ctl_val->value.enumerated.item[i] = + snd_audient_enum_item(ctype->enumeration, val); + } + + for (; i < nchan; i++) + ctl_val->value.enumerated.item[i] = 0; + + return 0; +} + +static int snd_ctl_audient_enum_set(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ctl_val) +{ + struct usb_mixer_elem_info *const elem = snd_kcontrol_chip(kctl); + struct usb_mixer_interface *const mixer = elem->head.mixer; + + const unsigned int hwchan = snd_audient_kctl_hwchannels(kctl); + const struct snd_audient_ctrl_type *const ctype + = snd_audient_kctl_type(kctl); + const struct snd_audient_enum *const e = ctype->enumeration; + const u8 base = snd_audient_kctl_cidxoffs(kctl); + + unsigned int i; + int changed = 0; + + for (i = 0; i < hwchan; i++) + if (ctl_val->value.enumerated.item[i] >= e->items) + return -EINVAL; + + CLASS(snd_usb_lock, pm)(mixer->chip); + if (pm.err < 0) + return pm.err; + /* serializes the transfers and the cache, also between gets */ + guard(mutex)(&mixer->lock); + + for (i = 0; i < hwchan; i++) { + const unsigned int item = ctl_val->value.enumerated.item[i]; + int ret; + + ret = snd_audient_raw_set_one(mixer, ctype, + snd_audient_cache_slot(elem, i), + base + i, e->values[item], false); + if (ret < 0) + return ret; + + if (ret) + changed = 1; + } + + return changed; +} + static int snd_ctl_audient_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { const struct snd_audient_ctrl_type *const ctype = snd_audient_kctl_type(kctl); + if (ctype->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) + return snd_ctl_enum_info(uinfo, snd_audient_kctl_channels(kctl), + ctype->enumeration->items + 1, + ctype->enumeration->texts); + uinfo->type = ctype->type; uinfo->count = snd_audient_kctl_channels(kctl); @@ -613,6 +739,10 @@ static int snd_audient_add_ctrl(struct usb_mixer_interface *mixer, knew.get = snd_ctl_audient_boolean_get; knew.put = snd_ctl_audient_boolean_set; break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + knew.get = snd_ctl_audient_enum_get; + knew.put = snd_ctl_audient_enum_set; + break; default: return -EINVAL; } -- 2.47.3 ^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-06 20:30 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <sashiko-outbox-201869@kernel.org>
2026-11-06 20:29 ` [RFC PATCH 13/16] ALSA: mixer_audient: Add enumerated controls Will Porter
2026-11-03 23:01 [RFC V2 PATCH 00/11] Re: ALSA: usb-audio: Audient iD14 MkI vendor Christian Ruppert
2026-11-06 16:31 ` [RFC PATCH 00/16] ALSA: usb-audio: Audient driver and iD14 MkI support Will Porter
2026-11-06 16:31 ` [RFC PATCH 13/16] ALSA: mixer_audient: Add enumerated controls Will Porter
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®