diff options
Diffstat (limited to 'core.c')
-rw-r--r-- | core.c | 105 |
1 files changed, 70 insertions, 35 deletions
@@ -220,46 +220,17 @@ static void pcm_private_data_free(struct snd_pcm *pcm) kfree(pcm->private_data); } -struct snd_pcm *snd_avirt_pcm_create(struct snd_avirt_stream *stream) +static struct snd_pcm *snd_avirt_pcm_create(struct snd_avirt_stream *stream) { struct snd_avirt_private_data *avirt_private_data; - 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; - 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; + if (!stream->direction) playback = true; - } else { - pcm_ops_ap = (struct snd_pcm_ops *)audiopath->pcm_capture_ops; + else capture = true; - } - if (!pcm_ops_ap) { - D_ERRORK("No PCM ops for direction '%s' for Audio Path: %s", - (stream->direction) ? "capture" : "playback", - stream->map); - return ERR_PTR(-EFAULT); - } - pcm_ops = &pcm_ops_avirt; - - /* Set PCM ops for the Audio Path*/ - 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")) { @@ -278,9 +249,10 @@ struct snd_pcm *snd_avirt_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, + stream->pcm_ops); if (capture) - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, pcm_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, stream->pcm_ops); pcm->info_flags = 0; strcpy(pcm->name, stream->name); @@ -295,6 +267,60 @@ struct snd_pcm *snd_avirt_pcm_create(struct snd_avirt_stream *stream) return pcm; } +int snd_avirt_stream_set_map(struct snd_avirt_stream *stream, const char *map) +{ + struct snd_avirt_audiopath *audiopath; + struct snd_pcm_ops *pcm_ops_ap; + + /* If already sealed, we cannot create the stream */ + if (snd_avirt_streams_sealed()) { + D_ERRORK("Streams already sealed. Cannot set map: '%s'", map); + return -EPERM; + } + + if (!strcmp(stream->map, map)) + return -1; + + memcpy(stream->map, (char *)map, strlen(map)); + audiopath = snd_avirt_audiopath_get(map); + if (!audiopath) { + D_ERRORK("Cannot find Audio Path uid: '%s'!", stream->map); + return -EFAULT; + } + + if (!stream->direction) + pcm_ops_ap = (struct snd_pcm_ops *)audiopath->pcm_playback_ops; + else + pcm_ops_ap = (struct snd_pcm_ops *)audiopath->pcm_capture_ops; + + if (!pcm_ops_ap) { + D_ERRORK("No PCM ops for direction '%s' for Audio Path: %s", + (stream->direction) ? "capture" : "playback", + stream->map); + return -EFAULT; + } + + /* Set PCM ops for the Audio Path*/ + PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, prepare); + PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, trigger); + PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, pointer); + PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, get_time_info); + PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, fill_silence); + PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, copy_user); + PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, copy_kernel); + PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, mmap); + PCM_OPS_SET(pcm_ops_ap, &stream->pcm_ops, ack); + + /* If not created, create the PCM device now */ + if (!stream->pcm) { + stream->pcm = snd_avirt_pcm_create(stream); + if (IS_ERR_OR_NULL(stream->pcm)) + return -EFAULT; + } + + return 0; +} + static int snd_avirt_streams_get(const char *map, struct snd_avirt_stream_array *stream_array) { @@ -427,7 +453,16 @@ struct snd_avirt_stream *snd_avirt_stream_create(const char *name, stream->direction = direction; stream->device = core.stream_count++; - D_INFOK("name: %s device:%d", name, stream->device); + /* Initialize PCM ops table for this stream. + * Will be populated once map is known */ + stream->pcm_ops = kzalloc(sizeof(struct snd_pcm_ops), GFP_KERNEL); + if (!stream->pcm_ops) { + D_ERRORK("Failed to allocate PCM ops table"); + return ERR_PTR(-EFAULT); + } + memcpy(stream->pcm_ops, &pcm_ops_avirt, sizeof(struct snd_pcm_ops)); + + D_INFOK("name:%s device:%d", name, stream->device); return stream; } |