aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Farrugia <mark.farrugia@fiberdyne.com.au>2019-01-29 18:46:23 +1100
committerMark Farrugia <mark.farrugia@fiberdyne.com.au>2019-01-29 18:46:23 +1100
commit5e431d7a48d5e4ca0e2c040af1ef10dfaf0eba92 (patch)
tree118e99fba00e1e1aca2815aaaa0810be1ad1ff32
parent2e1b1a2ec043a89d7720e9b9c00d4f783ce6a62b (diff)
Rework setting the AVIRT map, and stream creation
To ensure that a stream is able to change it's mapping (before card is sealed), we cannot create the stream PCM upon setting the mapping. This had to be reworked to allow multiple setting of the mapping if so required. The PCM ops table for a given stream is now allocated and stored in the snd_avirt_stream struct, to allow retrieval and manipulation upon mapping change. Signed-off-by: Mark Farrugia <mark.farrugia@fiberdyne.com.au>
-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 */
};