ALSA: PCM: User contol API implementation

Introduced a new helper function snd_pcm_add_usr_ctls() to
create control elements representing the user control for each
PCM (sub)stream

Signed-off-by: Jayasena Sangaraboina <jsanga@codeaurora.org>
Signed-off-by: Banajit Goswami <bgoswami@codeaurora.org>
Signed-off-by: Sudheer Papothi <spapothi@codeaurora.org>
This commit is contained in:
Sudheer Papothi 2016-01-29 02:40:28 +05:30 committed by David Keitel
parent 6ba6d2e983
commit abe342c13b
3 changed files with 122 additions and 0 deletions

View file

@ -519,6 +519,7 @@ struct snd_pcm_str {
#endif #endif
struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */ struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */
struct snd_kcontrol *vol_kctl; /* volume controls */ struct snd_kcontrol *vol_kctl; /* volume controls */
struct snd_kcontrol *usr_kctl; /* user controls */
struct device dev; struct device dev;
}; };
@ -1435,6 +1436,30 @@ int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
unsigned long private_value, unsigned long private_value,
struct snd_pcm_volume **info_ret); struct snd_pcm_volume **info_ret);
/*
* PCM User control API
*/
/* array element of usr elem */
struct snd_pcm_usr_elem {
int val[128];
};
/* pp information; retrieved via snd_kcontrol_chip() */
struct snd_pcm_usr {
struct snd_pcm *pcm; /* assigned PCM instance */
int stream; /* PLAYBACK or CAPTURE */
struct snd_kcontrol *kctl;
const struct snd_pcm_usr_elem *usr;
int max_length;
void *private_data; /* optional: private data pointer */
};
int snd_pcm_add_usr_ctls(struct snd_pcm *pcm, int stream,
const struct snd_pcm_usr_elem *usr,
int max_length, int max_control_str_len,
unsigned long private_value,
struct snd_pcm_usr **info_ret);
/* printk helpers */ /* printk helpers */
#define pcm_err(pcm, fmt, args...) \ #define pcm_err(pcm, fmt, args...) \
dev_err((pcm)->card->dev, fmt, ##args) dev_err((pcm)->card->dev, fmt, ##args)

View file

@ -1143,6 +1143,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
snd_ctl_remove(pcm->card, pcm->streams[cidx].vol_kctl); snd_ctl_remove(pcm->card, pcm->streams[cidx].vol_kctl);
pcm->streams[cidx].vol_kctl = NULL; pcm->streams[cidx].vol_kctl = NULL;
} }
if (pcm->streams[cidx].usr_kctl) {
snd_ctl_remove(pcm->card, pcm->streams[cidx].usr_kctl);
pcm->streams[cidx].usr_kctl = NULL;
}
} }
mutex_unlock(&pcm->open_mutex); mutex_unlock(&pcm->open_mutex);
mutex_unlock(&register_mutex); mutex_unlock(&register_mutex);

View file

@ -42,6 +42,7 @@
#endif #endif
#define STRING_LENGTH_OF_INT 12 #define STRING_LENGTH_OF_INT 12
#define MAX_USR_CTRL_CNT 128
/* /*
* fill ring buffer with silence * fill ring buffer with silence
@ -2728,3 +2729,95 @@ int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(snd_pcm_add_volume_ctls); EXPORT_SYMBOL_GPL(snd_pcm_add_volume_ctls);
static int pcm_usr_ctl_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = MAX_USR_CTRL_CNT;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = INT_MAX;
return 0;
}
static void pcm_usr_ctl_private_free(struct snd_kcontrol *kcontrol)
{
struct snd_pcm_usr *info = snd_kcontrol_chip(kcontrol);
info->pcm->streams[info->stream].usr_kctl = NULL;
kfree(info);
}
/**
* snd_pcm_add_usr_ctls - create user control elements
* @pcm: the assigned PCM instance
* @stream: stream direction
* @max_length: the max length of the user parameter of stream
* @private_value: the value passed to each kcontrol's private_value field
* @info_ret: store struct snd_pcm_usr instance if non-NULL
*
* Create usr control elements assigned to the given PCM stream(s).
* Returns zero if succeed, or a negative error value.
*/
int snd_pcm_add_usr_ctls(struct snd_pcm *pcm, int stream,
const struct snd_pcm_usr_elem *usr,
int max_length, int max_kctrl_str_len,
unsigned long private_value,
struct snd_pcm_usr **info_ret)
{
struct snd_pcm_usr *info;
struct snd_kcontrol_new knew = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
.info = pcm_usr_ctl_info,
};
int err;
char *buf;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) {
pr_err("%s: snd_pcm_usr alloc failed\n", __func__);
return -ENOMEM;
}
info->pcm = pcm;
info->stream = stream;
info->usr = usr;
info->max_length = max_length;
buf = kzalloc(max_kctrl_str_len, GFP_KERNEL);
if (!buf) {
pr_err("%s: buffer allocation failed\n", __func__);
kfree(info);
return -ENOMEM;
}
knew.name = buf;
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
snprintf(buf, max_kctrl_str_len, "%s %d %s",
"Playback", pcm->device, "User kcontrol");
else
snprintf(buf, max_kctrl_str_len, "%s %d %s",
"Capture", pcm->device, "User kcontrol");
knew.device = pcm->device;
knew.count = pcm->streams[stream].substream_count;
knew.private_value = private_value;
info->kctl = snd_ctl_new1(&knew, info);
if (!info->kctl) {
kfree(info);
kfree(knew.name);
pr_err("%s: snd_ctl_new failed\n", __func__);
return -ENOMEM;
}
info->kctl->private_free = pcm_usr_ctl_private_free;
err = snd_ctl_add(pcm->card, info->kctl);
if (err < 0) {
kfree(info);
kfree(knew.name);
pr_err("%s: snd_ctl_add failed:%d\n", __func__,
err);
return -ENOMEM;
}
pcm->streams[stream].usr_kctl = info->kctl;
if (info_ret)
*info_ret = info;
kfree(knew.name);
return 0;
}
EXPORT_SYMBOL(snd_pcm_add_usr_ctls);