Skip to content

Commit fb0fe09

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 alsa-lib can read the full string if the original is truncated. [1] link to v3 Signed-off-by: Maciej Strozek <mstrozek@opensource.cirrus.com>
1 parent 75ed5f0 commit fb0fe09

4 files changed

Lines changed: 61 additions & 6 deletions

File tree

include/local.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@
101101
#define _snd_pcm_sw_params snd_pcm_sw_params
102102
#define _snd_pcm_status snd_pcm_status
103103

104-
#define _snd_ctl_card_info snd_ctl_card_info
105104
#define _snd_ctl_elem_id snd_ctl_elem_id
106105
#define _snd_ctl_elem_list snd_ctl_elem_list
107106
#define _snd_ctl_elem_info snd_ctl_elem_info
@@ -226,6 +225,20 @@
226225
#include "seq_midi_event.h"
227226
#include "list.h"
228227

228+
/* V2 structure - increased components string from 128 bytes to 512 bytes */
229+
struct _snd_ctl_card_info {
230+
int card; /* card number */
231+
int pad; /* reserved for future (was type) */
232+
unsigned char id[16]; /* ID of card (user selectable) */
233+
unsigned char driver[16]; /* Driver name */
234+
unsigned char name[32]; /* Short name of soundcard */
235+
unsigned char longname[80]; /* name + info text about soundcard */
236+
unsigned char reserved_[16]; /* reserved for future (was ID of mixer) */
237+
unsigned char mixername[80]; /* visual mixer identification */
238+
char components[512];
239+
};
240+
241+
229242
struct _snd_async_handler {
230243
enum {
231244
SND_ASYNC_HANDLER_GENERIC,

include/sound/uapi/asound.h

Lines changed: 13 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,17 @@ 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+
*/
1066+
struct snd_ctl_card_components {
1067+
int card; /* card number */
1068+
unsigned int length; /* returned length of components string for ioctl query */
1069+
unsigned char *components; /* user buffer for components string */
1070+
};
1071+
10611072
typedef int __bitwise snd_ctl_elem_type_t;
10621073
#define SNDRV_CTL_ELEM_TYPE_NONE ((snd_ctl_elem_type_t) 0) /* invalid */
10631074
#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((snd_ctl_elem_type_t) 1) /* boolean type */
@@ -1184,6 +1195,7 @@ struct snd_ctl_tlv {
11841195

11851196
#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)
11861197
#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info)
1198+
#define SNDRV_CTL_IOCTL_CARD_COMPONENTS _IOWR('U', 0x02, struct snd_ctl_card_components)
11871199
#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list)
11881200
#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info)
11891201
#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value)

src/control/cards.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,17 @@
4242
static int snd_card_load2(const char *control)
4343
{
4444
int open_dev;
45-
snd_ctl_card_info_t info;
45+
struct snd_ctl_card_info kinfo;
4646

4747
open_dev = snd_open_device(control, O_RDONLY);
4848
if (open_dev >= 0) {
49-
if (ioctl(open_dev, SNDRV_CTL_IOCTL_CARD_INFO, &info) < 0) {
49+
if (ioctl(open_dev, SNDRV_CTL_IOCTL_CARD_INFO, &kinfo) < 0) {
5050
int err = -errno;
5151
close(open_dev);
5252
return err;
5353
}
5454
close(open_dev);
55-
return info.card;
55+
return kinfo.card;
5656
} else {
5757
return -errno;
5858
}

src/control/control_hw.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,40 @@ static int snd_ctl_hw_subscribe_events(snd_ctl_t *handle, int subscribe)
129129
static int snd_ctl_hw_card_info(snd_ctl_t *handle, snd_ctl_card_info_t *info)
130130
{
131131
snd_ctl_hw_t *hw = handle->private_data;
132-
if (ioctl(hw->fd, SNDRV_CTL_IOCTL_CARD_INFO, info) < 0) {
132+
struct snd_ctl_card_info kinfo;
133+
struct snd_ctl_card_components comp;
134+
135+
if (ioctl(hw->fd, SNDRV_CTL_IOCTL_CARD_INFO, &kinfo) < 0) {
133136
snd_errornum(CONTROL, "SNDRV_CTL_IOCTL_CARD_INFO failed");
134137
return -errno;
135138
}
139+
140+
snd_ctl_card_info_clear(info);
141+
info->card = kinfo.card;
142+
info->pad = kinfo.pad;
143+
snd_strlcpy((char *)info->id, (char *)kinfo.id, sizeof(info->id));
144+
snd_strlcpy((char *)info->driver, (char *)kinfo.driver, sizeof(info->driver));
145+
snd_strlcpy((char *)info->name, (char *)kinfo.name, sizeof(info->name));
146+
snd_strlcpy((char *)info->longname, (char *)kinfo.longname, sizeof(info->longname));
147+
snd_strlcpy((char *)info->reserved_, (char *)kinfo.reserved_, sizeof(info->reserved_));
148+
snd_strlcpy((char *)info->mixername, (char *)kinfo.mixername, sizeof(info->mixername));
149+
if (strnlen((char *)kinfo.components, sizeof(kinfo.components)) == sizeof(kinfo.components) - 1 &&
150+
kinfo.components[sizeof(kinfo.components) - 2] == '>') {
151+
comp.components = (unsigned char *)info->components;
152+
comp.length = sizeof(info->components);
153+
if (ioctl(hw->fd, SNDRV_CTL_IOCTL_CARD_COMPONENTS, &comp) < 0) {
154+
snd_errornum(CONTROL, "SNDRV_CTL_IOCTL_CARD_COMPONENTS failed");
155+
return -errno;
156+
}
157+
if (comp.length != strnlen((char *)comp.components, sizeof(info->components)) + 1 ) {
158+
snd_error(CONTROL, "SNDRV_CTL_IOCTL_CARD_COMPONENTS unexpected length %u, should be %u",
159+
comp.length, strnlen((char *)comp.components, sizeof(info->components)) + 1);
160+
return -errno;
161+
}
162+
} else {
163+
snd_strlcpy(info->components, (char *)kinfo.components, sizeof(info->components));
164+
}
165+
136166
return 0;
137167
}
138168

0 commit comments

Comments
 (0)