ALSA: PCM: volume API implementation
Introduced a new helper function snd_pcm_add_volume_ctls() to create control elements representing the volume for each PCM (sub)stream. Signed-off-by: Damir Didjusto <damird@codeaurora.org> Signed-off-by: Banajit Goswami <bgoswami@codeaurora.org> Signed-off-by: Sudheer Papothi <spapothi@codeaurora.org>
This commit is contained in:
parent
4ce9b377bb
commit
f928605b0e
3 changed files with 119 additions and 0 deletions
|
@ -518,6 +518,7 @@ struct snd_pcm_str {
|
||||||
#endif
|
#endif
|
||||||
#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 device dev;
|
struct device dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1410,6 +1411,30 @@ static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
|
||||||
return 1ULL << (__force int) pcm_format;
|
return 1ULL << (__force int) pcm_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PCM Volume control API
|
||||||
|
*/
|
||||||
|
/* array element of volume */
|
||||||
|
struct snd_pcm_volume_elem {
|
||||||
|
int volume;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* pp information; retrieved via snd_kcontrol_chip() */
|
||||||
|
struct snd_pcm_volume {
|
||||||
|
struct snd_pcm *pcm; /* assigned PCM instance */
|
||||||
|
int stream; /* PLAYBACK or CAPTURE */
|
||||||
|
struct snd_kcontrol *kctl;
|
||||||
|
const struct snd_pcm_volume_elem *volume;
|
||||||
|
int max_length;
|
||||||
|
void *private_data; /* optional: private data pointer */
|
||||||
|
};
|
||||||
|
|
||||||
|
int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
|
||||||
|
const struct snd_pcm_volume_elem *volume,
|
||||||
|
int max_length,
|
||||||
|
unsigned long private_value,
|
||||||
|
struct snd_pcm_volume **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)
|
||||||
|
|
|
@ -1139,6 +1139,10 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
|
||||||
snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
|
snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
|
||||||
pcm->streams[cidx].chmap_kctl = NULL;
|
pcm->streams[cidx].chmap_kctl = NULL;
|
||||||
}
|
}
|
||||||
|
if (pcm->streams[cidx].vol_kctl) {
|
||||||
|
snd_ctl_remove(pcm->card, pcm->streams[cidx].vol_kctl);
|
||||||
|
pcm->streams[cidx].vol_kctl = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&pcm->open_mutex);
|
mutex_unlock(&pcm->open_mutex);
|
||||||
mutex_unlock(®ister_mutex);
|
mutex_unlock(®ister_mutex);
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
#define trace_hw_ptr_error(substream, reason)
|
#define trace_hw_ptr_error(substream, reason)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define STRING_LENGTH_OF_INT 12
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fill ring buffer with silence
|
* fill ring buffer with silence
|
||||||
* runtime->silence_start: starting pointer to silence area
|
* runtime->silence_start: starting pointer to silence area
|
||||||
|
@ -2568,6 +2570,23 @@ static void pcm_chmap_ctl_private_free(struct snd_kcontrol *kcontrol)
|
||||||
kfree(info);
|
kfree(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pcm_volume_ctl_info(struct snd_kcontrol *kcontrol,
|
||||||
|
struct snd_ctl_elem_info *uinfo)
|
||||||
|
{
|
||||||
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||||
|
uinfo->count = 1;
|
||||||
|
uinfo->value.integer.min = 0;
|
||||||
|
uinfo->value.integer.max = 0x2000;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pcm_volume_ctl_private_free(struct snd_kcontrol *kcontrol)
|
||||||
|
{
|
||||||
|
struct snd_pcm_volume *info = snd_kcontrol_chip(kcontrol);
|
||||||
|
info->pcm->streams[info->stream].vol_kctl = NULL;
|
||||||
|
kfree(info);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_pcm_add_chmap_ctls - create channel-mapping control elements
|
* snd_pcm_add_chmap_ctls - create channel-mapping control elements
|
||||||
* @pcm: the assigned PCM instance
|
* @pcm: the assigned PCM instance
|
||||||
|
@ -2627,3 +2646,74 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls);
|
EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* snd_pcm_add_volume_ctls - create volume control elements
|
||||||
|
* @pcm: the assigned PCM instance
|
||||||
|
* @stream: stream direction
|
||||||
|
* @max_length: the max length of the volume parameter of stream
|
||||||
|
* @private_value: the value passed to each kcontrol's private_value field
|
||||||
|
* @info_ret: store struct snd_pcm_volume instance if non-NULL
|
||||||
|
*
|
||||||
|
* Create volume control elements assigned to the given PCM stream(s).
|
||||||
|
* Returns zero if succeed, or a negative error value.
|
||||||
|
*/
|
||||||
|
int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
|
||||||
|
const struct snd_pcm_volume_elem *volume,
|
||||||
|
int max_length,
|
||||||
|
unsigned long private_value,
|
||||||
|
struct snd_pcm_volume **info_ret)
|
||||||
|
{
|
||||||
|
struct snd_pcm_volume *info;
|
||||||
|
struct snd_kcontrol_new knew = {
|
||||||
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||||
|
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
|
||||||
|
SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||||
|
.info = pcm_volume_ctl_info,
|
||||||
|
};
|
||||||
|
int err;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||||
|
if (!info)
|
||||||
|
return -ENOMEM;
|
||||||
|
info->pcm = pcm;
|
||||||
|
info->stream = stream;
|
||||||
|
info->volume = volume;
|
||||||
|
info->max_length = max_length;
|
||||||
|
size = sizeof("Playback ") + sizeof(" Volume") +
|
||||||
|
STRING_LENGTH_OF_INT*sizeof(char) + 1;
|
||||||
|
knew.name = kzalloc(size, GFP_KERNEL);
|
||||||
|
if (!knew.name) {
|
||||||
|
kfree(info);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||||
|
snprintf(knew.name, size, "%s %d %s",
|
||||||
|
"Playback", pcm->device, "Volume");
|
||||||
|
else
|
||||||
|
snprintf(knew.name, size, "%s %d %s",
|
||||||
|
"Capture", pcm->device, "Volume");
|
||||||
|
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);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
info->kctl->private_free = pcm_volume_ctl_private_free;
|
||||||
|
err = snd_ctl_add(pcm->card, info->kctl);
|
||||||
|
if (err < 0) {
|
||||||
|
kfree(info);
|
||||||
|
kfree(knew.name);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
pcm->streams[stream].vol_kctl = info->kctl;
|
||||||
|
if (info_ret)
|
||||||
|
*info_ret = info;
|
||||||
|
kfree(knew.name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(snd_pcm_add_volume_ctls);
|
||||||
|
|
Loading…
Add table
Reference in a new issue