control: ucm: add ioctl to retrieve full card components

The fixed-size components field in SNDRV_CTL_IOCTL_CARD_INFO can be too
small on systems with many audio devices. The kernel [1] will provide a
new ioctl to read the full string while truncating the original in
card_info if it grows too big. Make sure the code falls back to original
if the new ioctl is not supported.

[1]: https://lore.kernel.org/all/20260122111249.67319-1-mstrozek@opensource.cirrus.com/
Signed-off-by: Maciej Strozek <mstrozek@opensource.cirrus.com>
This commit is contained in:
Maciej Strozek 2026-01-22 09:14:17 +00:00
parent 75ed5f05ba
commit d4cf5da490
17 changed files with 180 additions and 5 deletions

View file

@ -123,6 +123,7 @@ typedef struct {
int device;
int subscribe_events;
snd_ctl_card_info_t card_info;
snd_ctl_card_components_t card_components;
snd_ctl_elem_list_t element_list;
snd_ctl_elem_info_t element_info;
snd_ctl_elem_value_t element_read;

View file

@ -84,6 +84,11 @@ typedef struct snd_aes_iec958 {
*/
typedef struct _snd_ctl_card_info snd_ctl_card_info_t;
/**
* \brief CTL card components container.
*/
typedef struct _snd_ctl_card_components snd_ctl_card_components_t;
/** CTL element identifier container */
typedef struct _snd_ctl_elem_id snd_ctl_elem_id_t;
@ -394,6 +399,7 @@ int snd_ctl_poll_descriptors(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int s
int snd_ctl_poll_descriptors_revents(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
int snd_ctl_subscribe_events(snd_ctl_t *ctl, int subscribe);
int snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info);
int snd_ctl_card_components(snd_ctl_t *ctl, snd_ctl_card_components_t *components);
int snd_ctl_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list);
int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info);
int snd_ctl_elem_read(snd_ctl_t *ctl, snd_ctl_elem_value_t *data);
@ -508,6 +514,22 @@ const char *snd_ctl_card_info_get_longname(const snd_ctl_card_info_t *obj);
const char *snd_ctl_card_info_get_mixername(const snd_ctl_card_info_t *obj);
const char *snd_ctl_card_info_get_components(const snd_ctl_card_info_t *obj);
size_t snd_ctl_card_components_sizeof(void);
/** \hideinitializer
* \brief allocate an invalid #snd_ctl_card_components_t using standard alloca
* \param ptr returned pointer
*/
#define snd_ctl_card_components_alloca(ptr) __snd_alloca(ptr, snd_ctl_card_components)
int snd_ctl_card_components_malloc(snd_ctl_card_components_t **ptr);
void snd_ctl_card_components_free(snd_ctl_card_components_t *obj);
void snd_ctl_card_components_clear(snd_ctl_card_components_t *obj);
void snd_ctl_card_components_copy(snd_ctl_card_components_t *dst, const snd_ctl_card_components_t *src);
int snd_ctl_card_components_get_card(const snd_ctl_card_components_t *obj);
unsigned int snd_ctl_card_components_get_length(const snd_ctl_card_components_t *obj);
const char *snd_ctl_card_components_get_string(const snd_ctl_card_components_t *obj);
size_t snd_ctl_elem_list_sizeof(void);
size_t snd_ctl_event_sizeof(void);
/** \hideinitializer
* \brief allocate an invalid #snd_ctl_event_t using standard alloca

View file

@ -102,6 +102,7 @@
#define _snd_pcm_status snd_pcm_status
#define _snd_ctl_card_info snd_ctl_card_info
#define _snd_ctl_card_components snd_ctl_card_components
#define _snd_ctl_elem_id snd_ctl_elem_id
#define _snd_ctl_elem_list snd_ctl_elem_list
#define _snd_ctl_elem_info snd_ctl_elem_info

View file

@ -75,6 +75,7 @@ typedef struct _sm_class_basic {
snd_ctl_t *ctl;
snd_hctl_t *hctl;
snd_ctl_card_info_t *info;
snd_ctl_card_components_t *card_components;
} sm_class_basic_t;
struct sm_elem_ops {

View file

@ -1044,7 +1044,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 */
@ -1058,6 +1058,18 @@ 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.
*/
#define SNDRV_CTL_COMPONENTS_LEN 512
struct snd_ctl_card_components {
int card; /* card number */
unsigned int length; /* returned length of components string */
unsigned char components[SNDRV_CTL_COMPONENTS_LEN];
};
typedef int __bitwise snd_ctl_elem_type_t;
#define SNDRV_CTL_ELEM_TYPE_NONE ((snd_ctl_elem_type_t) 0) /* invalid */
#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((snd_ctl_elem_type_t) 1) /* boolean type */
@ -1184,6 +1196,7 @@ struct snd_ctl_tlv {
#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)
#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info)
#define SNDRV_CTL_IOCTL_CARD_COMPONENTS _IOWR('U', 0x02, struct snd_ctl_card_components)
#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list)
#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info)
#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value)