diff options
author | Mark Farrugia <mark.farrugia@fiberdyne.com.au> | 2018-11-13 08:04:19 +1100 |
---|---|---|
committer | Mark Farrugia <mark.farrugia@fiberdyne.com.au> | 2018-11-13 08:08:41 +1100 |
commit | 4ff37d576bc43e4655e5ed02bc8016e266c9893d (patch) | |
tree | 902e38d0ce00215244bbbbcc46cd1f103b45244c /core.c | |
parent | a64111a81dff5e37defbcbfcef638a011897f44e (diff) |
Rework PCM ops callback mechanism
- Fix issues regarding PCM ops callbacks via AVIRT
- As PCMs are created, the PCM ops are set according to the Audio
Path's needs. A default PCM ops table is applied for all PCMs,
which includes callbacks such as open, and hw_free, since AVIRT
requires these for intermediate processing, whether or not a given
Audio Path may need them.
- Separate PCM ops into separate playback and capture ops tables
Signed-off-by: Mark Farrugia <mark.farrugia@fiberdyne.com.au>
Diffstat (limited to 'core.c')
-rw-r--r-- | core.c | 44 |
1 files changed, 36 insertions, 8 deletions
@@ -26,6 +26,10 @@ MODULE_LICENSE("GPL v2"); #define D_PRINTK(fmt, args...) DDEBUG(D_LOGNAME, fmt, ##args) #define D_ERRORK(fmt, args...) DERROR(D_LOGNAME, fmt, ##args) +#define PCM_OPS_SET(pcm_ops_ap, pcm_ops, cb) \ + ((pcm_ops_ap->cb) ? ((*pcm_ops)->cb = pcm_ops_ap->cb) : \ + ((*pcm_ops)->cb = NULL)); + #define SND_AVIRT_DRIVER "snd_avirt" static struct snd_avirt_core core = { @@ -219,18 +223,42 @@ static void pcm_private_data_free(struct snd_pcm *pcm) 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_avirt_audiopath *audiopath; + struct snd_pcm_ops *pcm_ops, *pcm_ops_ap; struct snd_pcm *pcm; + bool playback = false, capture = false; int err; - /** Special case: loopback */ - if (!strcmp(stream->map, "ap_loopback")) { + audiopath = snd_avirt_audiopath_get(stream->map); + if (!audiopath) { + D_ERRORK("Cannot find Audio Path uid: '%s'!", stream->map); + return ERR_PTR(-EFAULT); + } + + if (!stream->direction) { + pcm_ops_ap = (struct snd_pcm_ops *)audiopath->pcm_playback_ops; playback = true; + } else { + pcm_ops_ap = (struct snd_pcm_ops *)audiopath->pcm_capture_ops; capture = true; - (&pcm_ops)->copy_user = NULL; - } else if (!stream->direction) { + } + pcm_ops = &pcm_ops_avirt; + + /* Set PCM ops for the Audio Path*/ + PCM_OPS_SET(pcm_ops_ap, &pcm_ops, close); + PCM_OPS_SET(pcm_ops_ap, &pcm_ops, prepare); + PCM_OPS_SET(pcm_ops_ap, &pcm_ops, trigger); + PCM_OPS_SET(pcm_ops_ap, &pcm_ops, pointer); + PCM_OPS_SET(pcm_ops_ap, &pcm_ops, get_time_info); + PCM_OPS_SET(pcm_ops_ap, &pcm_ops, fill_silence); + PCM_OPS_SET(pcm_ops_ap, &pcm_ops, copy_user); + PCM_OPS_SET(pcm_ops_ap, &pcm_ops, copy_kernel); + PCM_OPS_SET(pcm_ops_ap, &pcm_ops, mmap); + PCM_OPS_SET(pcm_ops_ap, &pcm_ops, ack); + + /** Special case: loopback */ + if (!strcmp(stream->map, "ap_loopback")) { playback = true; - } else { capture = true; } @@ -242,9 +270,9 @@ static struct snd_pcm *pcm_create(struct snd_avirt_stream *stream) /** Register driver callbacks */ if (playback) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, pcm_ops); if (capture) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, pcm_ops); pcm->info_flags = 0; strcpy(pcm->name, stream->name); |