summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configfs.c7
-rw-r--r--core.c105
-rw-r--r--core.h9
-rw-r--r--sound/avirt.h1
4 files changed, 79 insertions, 43 deletions
diff --git a/configfs.c b/configfs.c
index c19c2b5..a22c75f 100644
--- a/configfs.c
+++ b/configfs.c
@@ -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;
}
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;
}
diff --git a/core.h b/core.h
index 5ea78cd..6dc3333 100644
--- a/core.h
+++ b/core.h
@@ -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 */
};