diff options
-rw-r--r-- | configfs.c | 7 | ||||
-rw-r--r-- | core.c | 105 | ||||
-rw-r--r-- | core.h | 9 | ||||
-rw-r--r-- | sound/avirt.h | 1 |
4 files changed, 79 insertions, 43 deletions
@@ -47,12 +47,7 @@ static ssize_t cfg_snd_avirt_stream_map_store(struct config_item *item, snd_avirt_stream_from_config_item(item); split = strsep((char **)&page, "\n"); - memcpy(stream->map, (char *)split, count); - - /* Create the PCM device now */ - stream->pcm = snd_avirt_pcm_create(stream); - if (IS_ERROR_NULL(stream->pcm)) - return 0; + snd_avirt_stream_set_map(stream, split); return count; } @@ -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; } @@ -68,8 +68,13 @@ struct snd_avirt_stream *snd_avirt_stream_find_by_device(unsigned int device); */ struct snd_avirt_stream *snd_avirt_stream_create(const char *name, int direction); - -struct snd_pcm *snd_avirt_pcm_create(struct snd_avirt_stream *stream); +/** + * snd_avirt_stream_set_map - Set Audio Path mapping for a given stream + * @stream: The stream to assign the mapping to. + * @map: The Audio Path UID to map the stream to. + * @return: 0 on success, negative ERRNO on failure + */ +int snd_avirt_stream_set_map(struct snd_avirt_stream *stream, const char *map); /** * snd_avirt_audiopath_get - retrieves the Audio Path by it's UID diff --git a/sound/avirt.h b/sound/avirt.h index 90859d5..92bb07d 100644 --- a/sound/avirt.h +++ b/sound/avirt.h @@ -61,6 +61,7 @@ struct snd_avirt_stream { unsigned int device; /* Stream PCM device no. */ unsigned int direction; /* Stream direction */ struct snd_pcm *pcm; /* ALSA PCM */ + struct snd_pcm_ops *pcm_ops; /* ALSA PCM ops */ struct config_item item; /* configfs item reference */ }; |