summaryrefslogtreecommitdiffstats
path: root/core.c
diff options
context:
space:
mode:
authorMark Farrugia <mark.farrugia@fiberdyne.com.au>2018-11-13 08:04:19 +1100
committerMark Farrugia <mark.farrugia@fiberdyne.com.au>2018-11-13 08:08:41 +1100
commit4ff37d576bc43e4655e5ed02bc8016e266c9893d (patch)
tree902e38d0ce00215244bbbbcc46cd1f103b45244c /core.c
parenta64111a81dff5e37defbcbfcef638a011897f44e (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.c44
1 files changed, 36 insertions, 8 deletions
diff --git a/core.c b/core.c
index f3b33d1..35998c0 100644
--- a/core.c
+++ b/core.c
@@ -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);