diff options
author | James O'Shannessy <james.oshannessy@fiberdyne.com.au> | 2018-11-08 10:25:17 +1100 |
---|---|---|
committer | James O'Shannessy <james.oshannessy@fiberdyne.com.au> | 2018-11-08 10:25:17 +1100 |
commit | 26fd635bbae7fbf5f139830fca84b58d4bddec3a (patch) | |
tree | 9f45790201d9c505455e6c2706f30775939ab2de | |
parent | 932491f75629ab2e3f4acbfd1a7e16d42f8bc351 (diff) |
Add private data structure to PCM for audio path management
Expand upon the private data structure currently used by avirt
to allow audio paths to store own user data to PCM implementation.
Signed-off-by: James O'Shannessy <james.oshannessy@fiberdyne.com.au>
-rw-r--r-- | core.c | 23 | ||||
-rw-r--r-- | pcm.c | 81 | ||||
-rw-r--r-- | sound/avirt.h | 10 |
3 files changed, 87 insertions, 27 deletions
@@ -198,8 +198,26 @@ static void destroy_snd_avirt_audiopath_obj(struct snd_avirt_audiopath_obj *p) kobject_put(&p->kobj); } +/** + * pcm_private_data_free - callback function to free private data allocated to pcm + * @pcm: the PCM with private data + */ +void pcm_private_data_free(struct snd_pcm *pcm) +{ + struct snd_avirt_private_data *avirt_private_data; + D_PRINTK("Issuing free to private data struct"); + if(pcm->private_data){ + avirt_private_data = pcm->private_data; + if(avirt_private_data->ap_userdata) + avirt_private_data->private_free(pcm); + } + + kfree(pcm->private_data); +} + static struct snd_pcm *pcm_create(struct snd_avirt_stream *stream) { + struct snd_avirt_private_data *avirt_private_data; bool playback = false, capture = false; struct snd_pcm *pcm; int err; @@ -230,6 +248,11 @@ static struct snd_pcm *pcm_create(struct snd_avirt_stream *stream) pcm->info_flags = 0; strcpy(pcm->name, stream->name); + avirt_private_data = kzalloc(sizeof(*avirt_private_data), GFP_KERNEL); + pcm->private_data = avirt_private_data; + // Set the private free function for the private user data + pcm->private_free = pcm_private_data_free; + return pcm; } @@ -20,6 +20,9 @@ (ap)->pcm_ops->callback((substream), ##__VA_ARGS__) : \ 0) +#define PRIVATE_DATA(substream) \ + ((struct snd_avirt_private_data *) substream->private_data) + /** * snd_avirt_pcm_period_elapsed - PCM buffer complete callback * @substreamid: pointer to ALSA PCM substream @@ -48,6 +51,7 @@ EXPORT_SYMBOL_GPL(snd_avirt_pcm_period_elapsed); */ static int pcm_open(struct snd_pcm_substream *substream) { + struct snd_avirt_private_data *avirt_private_data; struct snd_avirt_audiopath *audiopath; struct snd_avirt_stream *stream; struct snd_pcm_hardware *hw; @@ -56,7 +60,8 @@ static int pcm_open(struct snd_pcm_substream *substream) stream = snd_avirt_stream_find_by_device(substream->pcm->device); audiopath = snd_avirt_audiopath_get(stream->map); CHK_NULL_V(audiopath, "Cannot find Audio Path uid: '%s'!", stream->map); - substream->private_data = audiopath; + avirt_private_data = substream->private_data; + avirt_private_data->audiopath = audiopath; // Copy the hw params from the audiopath to the pcm hw = &substream->runtime->hw; @@ -87,8 +92,8 @@ static int pcm_close(struct snd_pcm_substream *substream) { // Do additional Audio Path 'close' callback return DO_AUDIOPATH_CB( - ((struct snd_avirt_audiopath *)substream->private_data), close, - substream); + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, + close, substream); } /** @@ -120,7 +125,8 @@ static int pcm_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - audiopath = ((struct snd_avirt_audiopath *)substream->private_data); + audiopath = + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath; bufsz = params_buffer_bytes(hw_params) * audiopath->hw->periods_max; retval = snd_pcm_lib_alloc_vmalloc_buffer(substream, bufsz); @@ -145,8 +151,8 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) // Do additional Audio Path 'hw_free' callback err = DO_AUDIOPATH_CB( - ((struct snd_avirt_audiopath *)substream->private_data), - hw_free, substream); + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, + hw_free, substream); return snd_pcm_lib_free_vmalloc_buffer(substream); } @@ -163,10 +169,11 @@ static int pcm_hw_free(struct snd_pcm_substream *substream) */ static int pcm_prepare(struct snd_pcm_substream *substream) { + // Do additional Audio Path 'prepare' callback return DO_AUDIOPATH_CB( - ((struct snd_avirt_audiopath *)substream->private_data), - prepare, substream); + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, + prepare, substream); } /** @@ -181,7 +188,8 @@ static int pcm_prepare(struct snd_pcm_substream *substream) */ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) { - switch (cmd) { + + switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_STOP: @@ -194,8 +202,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) // Do additional Audio Path 'trigger' callback return DO_AUDIOPATH_CB( - ((struct snd_avirt_audiopath *)substream->private_data), - trigger, substream, cmd); + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, + trigger, substream, cmd); } /** @@ -212,8 +220,8 @@ static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream) { // Do additional Audio Path 'pointer' callback return DO_AUDIOPATH_CB( - ((struct snd_avirt_audiopath *)substream->private_data), - pointer, substream); + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, + pointer, substream); } /** @@ -228,14 +236,14 @@ static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream) * * Returns 0 on success or error code otherwise */ -static int pcm_get_time_info( - struct snd_pcm_substream *substream, struct timespec *system_ts, - struct timespec *audio_ts, - struct snd_pcm_audio_tstamp_config *audio_tstamp_config, - struct snd_pcm_audio_tstamp_report *audio_tstamp_report) +static int +pcm_get_time_info(struct snd_pcm_substream *substream, + struct timespec *system_ts, struct timespec *audio_ts, + struct snd_pcm_audio_tstamp_config *audio_tstamp_config, + struct snd_pcm_audio_tstamp_report *audio_tstamp_report) { return DO_AUDIOPATH_CB( - ((struct snd_avirt_audiopath *)substream->private_data), + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, get_time_info, substream, system_ts, audio_ts, audio_tstamp_config, audio_tstamp_report); } @@ -257,6 +265,7 @@ static int pcm_copy_user(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count) { + // struct snd_pcm_runtime *runtime; // int offset; @@ -265,8 +274,8 @@ static int pcm_copy_user(struct snd_pcm_substream *substream, int channel, // Do additional Audio Path 'copy_user' callback return DO_AUDIOPATH_CB( - ((struct snd_avirt_audiopath *)substream->private_data), - copy_user, substream, channel, pos, src, count); + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, + copy_user, substream, channel, pos, src, count); } /** @@ -286,8 +295,8 @@ static int pcm_copy_kernel(struct snd_pcm_substream *substream, int channel, unsigned long pos, void *buf, unsigned long count) { return DO_AUDIOPATH_CB( - ((struct snd_avirt_audiopath *)substream->private_data), - copy_kernel, substream, channel, pos, buf, count); + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, + copy_kernel, substream, channel, pos, buf, count); } /** @@ -302,16 +311,33 @@ static int pcm_copy_kernel(struct snd_pcm_substream *substream, int channel, static int pcm_ack(struct snd_pcm_substream *substream) { return DO_AUDIOPATH_CB( - ((struct snd_avirt_audiopath *)substream->private_data), ack, - substream); + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, + ack, substream); } static int pcm_silence(struct snd_pcm_substream *substream, int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count) { return DO_AUDIOPATH_CB( - ((struct snd_avirt_audiopath *)substream->private_data), - fill_silence, substream, channel, pos, count); + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, + fill_silence, substream, channel, pos, count); +} + +/** + * pcm_mmap - Implements 'mmap' callback for PCM middle layer + * @substream: pointer to ALSA PCM substream + * + * This is where we need to ack + * + * Returns 0 on success or error code otherwise. + * + */ +static int pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + return DO_AUDIOPATH_CB( + (struct snd_avirt_audiopath *)PRIVATE_DATA(substream)->audiopath, + mmap, substream, vma); } struct snd_pcm_ops pcm_ops = { @@ -329,4 +355,5 @@ struct snd_pcm_ops pcm_ops = { .copy_kernel = pcm_copy_kernel, .page = snd_pcm_lib_get_vmalloc_page, .ack = pcm_ack, + .mmap = pcm_mmap, }; diff --git a/sound/avirt.h b/sound/avirt.h index 55db1eb..52d2404 100644 --- a/sound/avirt.h +++ b/sound/avirt.h @@ -64,6 +64,16 @@ struct snd_avirt_stream { }; /** + * Private Data Expansion + */ +struct snd_avirt_private_data { + void *audiopath; + void *ap_userdata; + + void (*private_free)(struct snd_pcm *pcm); +}; + +/** * Audio stream group */ struct snd_avirt_stream_array { |