Re: [PATCH v3 2/2] ALSA: control: add ioctl to retrieve full card components

From: Takashi Iwai

Date: Tue Mar 03 2026 - 10:54:16 EST


On Tue, 03 Mar 2026 15:58:00 +0100,
Maciej Strozek wrote:
>
> The fixed-size components field in SNDRV_CTL_IOCTL_CARD_INFO can be too
> small on systems with many audio devices.
>
> Keep the existing struct snd_ctl_card_info ABI intact and add a new ioctl
> to retrieve the full components string.
>
> When the legacy components field is truncated, append '>' to indicate
> that the full string is available via the new ioctl.
>
> Link: https://github.com/alsa-project/alsa-lib/pull/494
> Suggested-by: Jaroslav Kysela <perex@xxxxxxxx>
> Suggested-by: Takashi Iwai <tiwai@xxxxxxxx>
> Signed-off-by: Maciej Strozek <mstrozek@xxxxxxxxxxxxxxxxxxxxx>
> ---
> Changes for v3:
> - change components field to a dynamic array resizable in 32 byte increments
> - removed SNDRV_CTL_COMPONENTS_LEN define
> - sanity check if 'components' requests more than 512 bytes
> - added a commit to clean up trailing whitespaces
> - alsa-utils link no longer needed
> Changes for v2:
> - do not modify existing card->components field
> - add a new ioctl and struct to keep the full components string
> - handle the split/trim in snd_ctl_card_info()
> ---
> include/sound/core.h | 4 ++--
> include/uapi/sound/asound.h | 14 ++++++++++++-
> sound/core/control.c | 35 ++++++++++++++++++++++++++++++++-
> sound/core/control_compat.c | 2 ++
> sound/core/init.c | 39 +++++++++++++++++++++++++++++--------
> 5 files changed, 82 insertions(+), 12 deletions(-)
>
> diff --git a/include/sound/core.h b/include/sound/core.h
> index 4093ec82a0a1..2b58f79b524d 100644
> --- a/include/sound/core.h
> +++ b/include/sound/core.h
> @@ -87,8 +87,8 @@ struct snd_card {
> char longname[80]; /* name of this soundcard */
> char irq_descr[32]; /* Interrupt description */
> char mixername[80]; /* mixer name */
> - char components[128]; /* card components delimited with
> - space */
> + char *components_ptr;
> + unsigned int components_ptr_alloc_size; // current memory allocation components_ptr.
> struct module *module; /* top-level module */
>
> void *private_data; /* private data for soundcard */
> diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
> index d3ce75ba938a..422b0b07613d 100644
> --- a/include/uapi/sound/asound.h
> +++ b/include/uapi/sound/asound.h
> @@ -1058,7 +1058,7 @@ struct snd_timer_tread {
> * *
> ****************************************************************************/
>
> -#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9)
> +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10)
>
> struct snd_ctl_card_info {
> int card; /* card number */
> @@ -1072,6 +1072,17 @@ struct snd_ctl_card_info {
> unsigned char components[128]; /* card components / fine identification, delimited with one space (AC97 etc..) */
> };
>
> +/*
> + * Card components can exceed the fixed 128 bytes in snd_ctl_card_info.
> + * Use SNDRV_CTL_IOCTL_CARD_COMPONENTS to retrieve the full string.
> + *
> + */
> +struct snd_ctl_card_components {
> + int card;
> + unsigned int length;
> + unsigned char *components;
> +};

Embedding a pointer for ioctl is a nightmare for 32bit compatibility,
and you seem to have forgotten it, too ;)

IMO, in this case, it'd be easier to use a flex array instead, e.g.

struct snd_ctl_card_components {
int card;
unsigned int length;
unsigned char components[];
};

And the ioctl can serve for two purposes:

- When length=0 is set, the kernel stores the current number of bytes
and returns without copying. User-space can use this mode for
allocating the buffer.

- When length > 0 is set, the kernel copies the data on components[]
up to the given length. The length field is updated again to store
the number of bytes (which would be copied).

What this length field specifies is another question: is it a string
length or a buffer length including NUL?

Also, we can keep the current string size, too, for returning in the
sequence in the above, instead of doing strlen() at each time.


thanks,

Takashi