aboutsummaryrefslogtreecommitdiffstats
path: root/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'core.c')
-rw-r--r--core.c105
1 files changed, 70 insertions, 35 deletions
diff --git a/core.c b/core.c
index 23351fc..32b7e22 100644
--- a/core.c
+++ b/core.c
@@ -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;
}