summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames O'Shannessy <james.oshannessy@fiberdyne.com.au>2018-11-08 10:25:17 +1100
committerJames O'Shannessy <james.oshannessy@fiberdyne.com.au>2018-11-08 10:25:17 +1100
commit26fd635bbae7fbf5f139830fca84b58d4bddec3a (patch)
tree9f45790201d9c505455e6c2706f30775939ab2de
parent932491f75629ab2e3f4acbfd1a7e16d42f8bc351 (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.c23
-rw-r--r--pcm.c81
-rw-r--r--sound/avirt.h10
3 files changed, 87 insertions, 27 deletions
diff --git a/core.c b/core.c
index 41cc555..6698a9e 100644
--- a/core.c
+++ b/core.c
@@ -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;
}
diff --git a/pcm.c b/pcm.c
index babc8b6..73f87c9 100644
--- a/pcm.c
+++ b/pcm.c
@@ -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 {