Skip to content

Commit d4cf5da

Browse files
committed
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>
1 parent 75ed5f0 commit d4cf5da

17 files changed

Lines changed: 180 additions & 5 deletions

File tree

aserver/aserver.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,9 @@ static int ctl_shm_cmd(client_t *client)
647647
case SNDRV_CTL_IOCTL_CARD_INFO:
648648
ctrl->result = snd_ctl_card_info(ctl, &ctrl->u.card_info);
649649
break;
650+
case SNDRV_CTL_IOCTL_CARD_COMPONENTS:
651+
ctrl->result = snd_ctl_card_components(ctl, &ctrl->u.card_components);
652+
break;
650653
case SNDRV_CTL_IOCTL_ELEM_LIST:
651654
{
652655
size_t maxsize = CTL_SHM_DATA_MAXLEN;

include/aserver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ typedef struct {
123123
int device;
124124
int subscribe_events;
125125
snd_ctl_card_info_t card_info;
126+
snd_ctl_card_components_t card_components;
126127
snd_ctl_elem_list_t element_list;
127128
snd_ctl_elem_info_t element_info;
128129
snd_ctl_elem_value_t element_read;

include/control.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ typedef struct snd_aes_iec958 {
8484
*/
8585
typedef struct _snd_ctl_card_info snd_ctl_card_info_t;
8686

87+
/**
88+
* \brief CTL card components container.
89+
*/
90+
typedef struct _snd_ctl_card_components snd_ctl_card_components_t;
91+
8792
/** CTL element identifier container */
8893
typedef struct _snd_ctl_elem_id snd_ctl_elem_id_t;
8994

@@ -394,6 +399,7 @@ int snd_ctl_poll_descriptors(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int s
394399
int snd_ctl_poll_descriptors_revents(snd_ctl_t *ctl, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
395400
int snd_ctl_subscribe_events(snd_ctl_t *ctl, int subscribe);
396401
int snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info);
402+
int snd_ctl_card_components(snd_ctl_t *ctl, snd_ctl_card_components_t *components);
397403
int snd_ctl_elem_list(snd_ctl_t *ctl, snd_ctl_elem_list_t *list);
398404
int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info);
399405
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);
508514
const char *snd_ctl_card_info_get_mixername(const snd_ctl_card_info_t *obj);
509515
const char *snd_ctl_card_info_get_components(const snd_ctl_card_info_t *obj);
510516

517+
size_t snd_ctl_card_components_sizeof(void);
518+
/** \hideinitializer
519+
* \brief allocate an invalid #snd_ctl_card_components_t using standard alloca
520+
* \param ptr returned pointer
521+
*/
522+
#define snd_ctl_card_components_alloca(ptr) __snd_alloca(ptr, snd_ctl_card_components)
523+
int snd_ctl_card_components_malloc(snd_ctl_card_components_t **ptr);
524+
void snd_ctl_card_components_free(snd_ctl_card_components_t *obj);
525+
void snd_ctl_card_components_clear(snd_ctl_card_components_t *obj);
526+
void snd_ctl_card_components_copy(snd_ctl_card_components_t *dst, const snd_ctl_card_components_t *src);
527+
int snd_ctl_card_components_get_card(const snd_ctl_card_components_t *obj);
528+
unsigned int snd_ctl_card_components_get_length(const snd_ctl_card_components_t *obj);
529+
const char *snd_ctl_card_components_get_string(const snd_ctl_card_components_t *obj);
530+
531+
size_t snd_ctl_elem_list_sizeof(void);
532+
511533
size_t snd_ctl_event_sizeof(void);
512534
/** \hideinitializer
513535
* \brief allocate an invalid #snd_ctl_event_t using standard alloca

include/local.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
#define _snd_pcm_status snd_pcm_status
103103

104104
#define _snd_ctl_card_info snd_ctl_card_info
105+
#define _snd_ctl_card_components snd_ctl_card_components
105106
#define _snd_ctl_elem_id snd_ctl_elem_id
106107
#define _snd_ctl_elem_list snd_ctl_elem_list
107108
#define _snd_ctl_elem_info snd_ctl_elem_info

include/mixer_abst.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ typedef struct _sm_class_basic {
7575
snd_ctl_t *ctl;
7676
snd_hctl_t *hctl;
7777
snd_ctl_card_info_t *info;
78+
snd_ctl_card_components_t *card_components;
7879
} sm_class_basic_t;
7980

8081
struct sm_elem_ops {

include/sound/uapi/asound.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,7 @@ struct snd_timer_tread {
10441044
* *
10451045
****************************************************************************/
10461046

1047-
#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 9)
1047+
#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10)
10481048

10491049
struct snd_ctl_card_info {
10501050
int card; /* card number */
@@ -1058,6 +1058,18 @@ struct snd_ctl_card_info {
10581058
unsigned char components[128]; /* card components / fine identification, delimited with one space (AC97 etc..) */
10591059
};
10601060

1061+
/*
1062+
* Card components can exceed the fixed 128 bytes in snd_ctl_card_info.
1063+
* Use SNDRV_CTL_IOCTL_CARD_COMPONENTS to retrieve the full string.
1064+
*/
1065+
#define SNDRV_CTL_COMPONENTS_LEN 512
1066+
1067+
struct snd_ctl_card_components {
1068+
int card; /* card number */
1069+
unsigned int length; /* returned length of components string */
1070+
unsigned char components[SNDRV_CTL_COMPONENTS_LEN];
1071+
};
1072+
10611073
typedef int __bitwise snd_ctl_elem_type_t;
10621074
#define SNDRV_CTL_ELEM_TYPE_NONE ((snd_ctl_elem_type_t) 0) /* invalid */
10631075
#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((snd_ctl_elem_type_t) 1) /* boolean type */
@@ -1184,6 +1196,7 @@ struct snd_ctl_tlv {
11841196

11851197
#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)
11861198
#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info)
1199+
#define SNDRV_CTL_IOCTL_CARD_COMPONENTS _IOWR('U', 0x02, struct snd_ctl_card_components)
11871200
#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list)
11881201
#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info)
11891202
#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value)

src/control/control.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,19 @@ int snd_ctl_card_info(snd_ctl_t *ctl, snd_ctl_card_info_t *info)
388388
return ctl->ops->card_info(ctl, info);
389389
}
390390

391+
/**
392+
* \brief Get information about the card components.
393+
* \param ctl The CTL handle.
394+
* \param components The card components information is stored here.
395+
* \return 0 on success, otherwise a negative error code.
396+
*/
397+
int snd_ctl_card_components(snd_ctl_t *ctl, snd_ctl_card_components_t *components)
398+
{
399+
assert(ctl && components);
400+
return ctl->ops->card_components(ctl, components);
401+
}
402+
403+
391404
/**
392405
* \brief Get a list of element identifiers
393406
*
@@ -2285,6 +2298,54 @@ const char *snd_ctl_card_info_get_components(const snd_ctl_card_info_t *obj)
22852298
return (const char *)obj->components;
22862299
}
22872300

2301+
size_t snd_ctl_card_components_sizeof()
2302+
{
2303+
return sizeof(snd_ctl_card_components_t);
2304+
}
2305+
2306+
int snd_ctl_card_components_malloc(snd_ctl_card_components_t **ptr)
2307+
{
2308+
assert(ptr);
2309+
*ptr = calloc(1, sizeof(snd_ctl_card_components_t));
2310+
if (!*ptr)
2311+
return -ENOMEM;
2312+
return 0;
2313+
}
2314+
2315+
void snd_ctl_card_components_free(snd_ctl_card_components_t *obj)
2316+
{
2317+
free(obj);
2318+
}
2319+
2320+
void snd_ctl_card_components_clear(snd_ctl_card_components_t *obj)
2321+
{
2322+
memset(obj, 0, sizeof(snd_ctl_card_components_t));
2323+
}
2324+
2325+
void snd_ctl_card_components_copy(snd_ctl_card_components_t *dst, const snd_ctl_card_components_t *src)
2326+
{
2327+
assert(dst && src);
2328+
*dst = *src;
2329+
}
2330+
2331+
int snd_ctl_card_components_get_card(const snd_ctl_card_components_t *obj)
2332+
{
2333+
assert(obj);
2334+
return obj->card;
2335+
}
2336+
2337+
unsigned int snd_ctl_card_components_get_length(const snd_ctl_card_components_t *obj)
2338+
{
2339+
assert(obj);
2340+
return obj->length;
2341+
}
2342+
2343+
const char *snd_ctl_card_components_get_string(const snd_ctl_card_components_t *obj)
2344+
{
2345+
assert(obj);
2346+
return (const char *)obj->components;
2347+
}
2348+
22882349
/**
22892350
* \brief get size of #snd_ctl_event_t
22902351
* \return size in bytes

src/control/control_ext.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ static int snd_ctl_ext_card_info(snd_ctl_t *handle, snd_ctl_card_info_t *info)
8989
return 0;
9090
}
9191

92+
static int snd_ctl_ext_card_components(snd_ctl_t *handle, snd_ctl_card_components_t *components)
93+
{
94+
snd_ctl_ext_t *ext = handle->private_data;
95+
96+
memset(components, 0, sizeof(*components));
97+
components->card = ext->card_idx;
98+
return 0;
99+
}
100+
92101
static int snd_ctl_ext_elem_list(snd_ctl_t *handle, snd_ctl_elem_list_t *list)
93102
{
94103
snd_ctl_ext_t *ext = handle->private_data;
@@ -469,6 +478,7 @@ static const snd_ctl_ops_t snd_ctl_ext_ops = {
469478
.async = snd_ctl_ext_async,
470479
.subscribe_events = snd_ctl_ext_subscribe_events,
471480
.card_info = snd_ctl_ext_card_info,
481+
.card_components = snd_ctl_ext_card_components,
472482
.element_list = snd_ctl_ext_elem_list,
473483
.element_info = snd_ctl_ext_elem_info,
474484
.element_add = snd_ctl_ext_elem_add,

src/control/control_hw.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,16 @@ static int snd_ctl_hw_card_info(snd_ctl_t *handle, snd_ctl_card_info_t *info)
136136
return 0;
137137
}
138138

139+
static int snd_ctl_hw_card_components(snd_ctl_t *handle, snd_ctl_card_components_t *components)
140+
{
141+
snd_ctl_hw_t *hw = handle->private_data;
142+
if (hw->protocol < SNDRV_PROTOCOL_VERSION(2, 0, 10))
143+
return -ENXIO;
144+
if (ioctl(hw->fd, SNDRV_CTL_IOCTL_CARD_COMPONENTS, components) < 0)
145+
return -errno;
146+
return 0;
147+
}
148+
139149
static int snd_ctl_hw_elem_list(snd_ctl_t *handle, snd_ctl_elem_list_t *list)
140150
{
141151
snd_ctl_hw_t *hw = handle->private_data;
@@ -389,6 +399,7 @@ static const snd_ctl_ops_t snd_ctl_hw_ops = {
389399
.async = snd_ctl_hw_async,
390400
.subscribe_events = snd_ctl_hw_subscribe_events,
391401
.card_info = snd_ctl_hw_card_info,
402+
.card_components = snd_ctl_hw_card_components,
392403
.element_list = snd_ctl_hw_elem_list,
393404
.element_info = snd_ctl_hw_elem_info,
394405
.element_add = snd_ctl_hw_elem_add,

src/control/control_local.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ typedef struct _snd_ctl_ops {
2828
int (*async)(snd_ctl_t *handle, int sig, pid_t pid);
2929
int (*subscribe_events)(snd_ctl_t *handle, int subscribe);
3030
int (*card_info)(snd_ctl_t *handle, snd_ctl_card_info_t *info);
31+
int (*card_components)(snd_ctl_t *handle, snd_ctl_card_components_t *components);
3132
int (*element_list)(snd_ctl_t *handle, snd_ctl_elem_list_t *list);
3233
int (*element_info)(snd_ctl_t *handle, snd_ctl_elem_info_t *info);
3334
int (*element_add)(snd_ctl_t *handle, snd_ctl_elem_info_t *info);

0 commit comments

Comments
 (0)