summaryrefslogtreecommitdiff
path: root/sound/core
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2017-08-24 10:46:16 +0900
committerTakashi Iwai <tiwai@suse.de>2017-08-24 09:15:15 +0200
commitb8e2204b25a50e389dfb50eeff163fa796a8ec6e (patch)
tree4b98f2401b794547bc54c77a0605fac2a0b64e78 /sound/core
parentda4288287b68fe6902629f4e5306aba2a554bc4b (diff)
ALSA: control: TLV data is unavailable at initial state of user-defined element set
For user-defined element set, in its initial state, TLV data is not registered. It's firstly available when any application register it by an additional operation. However, in current implementation, it's available in its initial state. As a result, applications get -ENXIO to read it. This commit controls its readability to manage info flags properly. In an initial state, elements don't have SND_CTL_ELEM_ACCESS_TLV_READ flag. Once TLV write operation is executed, they get the flag. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/control.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index 6ddffe85126f..51d4b4ad3e1d 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1118,6 +1118,7 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
struct user_element *ue = kctl->private_data;
unsigned int *container;
struct snd_ctl_elem_id id;
+ unsigned int mask = 0;
int i;
int change;
@@ -1136,13 +1137,21 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
return 0;
}
+ if (ue->tlv_data == NULL) {
+ /* Now TLV data is available. */
+ for (i = 0; i < kctl->count; ++i)
+ kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+ mask = SNDRV_CTL_EVENT_MASK_INFO;
+ }
+
kfree(ue->tlv_data);
ue->tlv_data = container;
ue->tlv_data_size = size;
+ mask |= SNDRV_CTL_EVENT_MASK_TLV;
for (i = 0; i < kctl->count; ++i) {
snd_ctl_build_ioff(&id, kctl, i);
- snd_ctl_notify(ue->card, SNDRV_CTL_EVENT_MASK_TLV, &id);
+ snd_ctl_notify(ue->card, mask, &id);
}
return change;
@@ -1277,8 +1286,10 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_INACTIVE |
- SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE);
- if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
+ SNDRV_CTL_ELEM_ACCESS_TLV_WRITE);
+
+ /* In initial state, nothing is available as TLV container. */
+ if (access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
access |= SNDRV_CTL_ELEM_ACCESS_USER;
@@ -1341,7 +1352,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
kctl->get = snd_ctl_elem_user_get;
if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
kctl->put = snd_ctl_elem_user_put;
- if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE)
+ if (access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
kctl->tlv.c = snd_ctl_elem_user_tlv;
/* This function manage to free the instance on failure. */